Merge branch 'feature/python-bindings'

This commit is contained in:
Jeffrey Pfau 2016-12-29 01:23:31 -08:00
commit 6d898542c7
41 changed files with 1361 additions and 80 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
*.user*
*~
*.swp
*.pyc

View File

@ -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)")
@ -151,6 +152,9 @@ add_custom_target(version-info ALL
include(${CMAKE_CURRENT_SOURCE_DIR}/version.cmake)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/core/version.c.in ${CMAKE_CURRENT_BINARY_DIR}/version.c)
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})
list(APPEND UTIL_SRC ${CMAKE_CURRENT_BINARY_DIR}/version.c)
source_group("Generated sources" FILES ${CMAKE_CURRENT_BINARY_DIR}/version.c)
@ -755,6 +759,11 @@ if(BUILD_SUITE)
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})
@ -838,6 +847,7 @@ if(NOT QUIET)
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}")

View File

@ -75,7 +75,7 @@ union PSR {
unsigned z : 1;
unsigned c : 1;
unsigned v : 1;
unsigned : 20;
unsigned unused : 20;
unsigned i : 1;
unsigned f : 1;
unsigned t : 1;
@ -85,7 +85,7 @@ union PSR {
unsigned t : 1;
unsigned f : 1;
unsigned i : 1;
unsigned : 20;
unsigned unused : 20;
unsigned v : 1;
unsigned c : 1;
unsigned z : 1;

View File

@ -12,6 +12,8 @@ CXX_GUARD_START
#include "debugger/debugger.h"
#include "arm/arm.h"
struct ARMDebugBreakpoint {
uint32_t address;
bool isSw;

96
src/core/flags.h.in Normal file
View File

@ -0,0 +1,96 @@
#ifndef FLAGS_H
#define FLAGS_H
#ifndef MINIMAL_CORE
#cmakedefine MINIMAL_CORE @MINIMAL_CORE@
#endif
// BUILD flags
#ifndef BUILD_GL
#cmakedefine BUILD_GL
#endif
#ifndef BUILD_GLES2
#cmakedefine BUILD_GLES2
#endif
// COLOR flags
#ifndef COLOR_16_BIT
#cmakedefine COLOR_16_BIT
#endif
#ifndef COLOR_5_6_5
#cmakedefine COLOR_5_6_5
#endif
// M_CORE flags
#ifndef M_CORE_GBA
#cmakedefine M_CORE_GBA
#endif
#ifndef M_CORE_GB
#cmakedefine M_CORE_GB
#endif
// USE flags
#ifndef MINIMAL_CORE
#ifndef USE_DEBUGGERS
#cmakedefine USE_DEBUGGERS
#endif
#ifndef USE_EDITLINE
#cmakedefine USE_EDITLINE
#endif
#ifndef USE_EPOXY
#cmakedefine USE_EPOXY
#endif
#ifndef USE_FFMPEG
#cmakedefine USE_FFMPEG
#endif
#ifndef USE_GDB_STUB
#cmakedefine USE_GDB_STUB
#endif
#ifndef USE_LIBAV
#cmakedefine USE_LIBAV
#endif
#ifndef USE_LIBZIP
#cmakedefine USE_LIBZIP
#endif
#ifndef USE_LZMA
#cmakedefine USE_LZMA
#endif
#ifndef USE_MAGICK
#cmakedefine USE_MAGICK
#endif
#ifndef USE_MINIZIP
#cmakedefine USE_MINIZIP
#endif
#ifndef USE_PNG
#cmakedefine USE_PNG
#endif
#ifndef USE_PTHREADS
#cmakedefine USE_PTHREADS
#endif
#ifndef USE_ZLIB
#cmakedefine USE_ZLIB
#endif
#endif
#endif

View File

@ -44,4 +44,18 @@ const char* mLogCategoryName(int category) {
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")

View File

@ -32,19 +32,7 @@ int mLogGenerateCategory(const char*);
const char* mLogCategoryName(int);
ATTRIBUTE_FORMAT(printf, 3, 4)
static inline 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);
}
void mLog(int category, enum mLogLevel level, const char* format, ...);
#define mLOG(CATEGORY, LEVEL, ...) mLog(_mLOG_CAT_ ## CATEGORY (), mLOG_ ## LEVEL, __VA_ARGS__)

View File

@ -10,7 +10,7 @@
CXX_GUARD_START
#include "arm/arm.h"
#include "core/cpu.h"
#include "core/log.h"
#include "util/vector.h"
@ -37,7 +37,7 @@ enum mDebuggerState {
enum mWatchpointType {
WATCHPOINT_WRITE = 1,
WATCHPOINT_READ = 2,
WATCHPOINT_RW = WATCHPOINT_WRITE | WATCHPOINT_READ
WATCHPOINT_RW = 3
};
enum mBreakpointType {

View File

@ -122,7 +122,6 @@ void GBHalt(struct LR35902Core* cpu);
struct VFile;
bool GBLoadROM(struct GB* gb, struct VFile* vf);
bool GBLoadSave(struct GB* gb, struct VFile* vf);
void GBYankROM(struct GB* gb);
void GBUnloadROM(struct GB* gb);
void GBSynthesizeROM(struct VFile* vf);

View File

@ -19,17 +19,17 @@ enum {
GB_VIDEO_HORIZONTAL_PIXELS = 160,
GB_VIDEO_VERTICAL_PIXELS = 144,
GB_VIDEO_VBLANK_PIXELS = 10,
GB_VIDEO_VERTICAL_TOTAL_PIXELS = GB_VIDEO_VERTICAL_PIXELS + GB_VIDEO_VBLANK_PIXELS,
GB_VIDEO_VERTICAL_TOTAL_PIXELS = 154,
// TODO: Figure out exact lengths
GB_VIDEO_MODE_2_LENGTH = 76,
GB_VIDEO_MODE_3_LENGTH_BASE = 171,
GB_VIDEO_MODE_0_LENGTH_BASE = 209,
GB_VIDEO_HORIZONTAL_LENGTH = GB_VIDEO_MODE_0_LENGTH_BASE + GB_VIDEO_MODE_2_LENGTH + GB_VIDEO_MODE_3_LENGTH_BASE,
GB_VIDEO_HORIZONTAL_LENGTH = 456,
GB_VIDEO_MODE_1_LENGTH = GB_VIDEO_HORIZONTAL_LENGTH * GB_VIDEO_VBLANK_PIXELS,
GB_VIDEO_TOTAL_LENGTH = GB_VIDEO_HORIZONTAL_LENGTH * GB_VIDEO_VERTICAL_TOTAL_PIXELS,
GB_VIDEO_MODE_1_LENGTH = 65664,
GB_VIDEO_TOTAL_LENGTH = 70224,
GB_BASE_MAP = 0x1800,
GB_SIZE_MAP = 0x0400

View File

@ -118,7 +118,7 @@ struct GBAMemory {
uint32_t* wram;
uint32_t* iwram;
uint32_t* rom;
uint16_t io[SIZE_IO >> 1];
uint16_t io[512];
struct GBACartridgeHardware hw;
struct GBASavedata savedata;

View File

@ -245,7 +245,7 @@ bool GBAVBMSetStream(struct GBAVBMContext* vbm, struct VFile* vf) {
uint8_t flags;
vf->read(vf, &flags, sizeof(flags));
if (flags & 2) {
#if USE_ZLIB
#ifdef USE_ZLIB
vbm->d.initFrom = INIT_FROM_SAVEGAME;
#else
// zlib is needed to parse the savegame

View File

@ -20,13 +20,13 @@ enum {
VIDEO_HBLANK_PIXELS = 68,
VIDEO_HDRAW_LENGTH = 1006,
VIDEO_HBLANK_LENGTH = 226,
VIDEO_HORIZONTAL_LENGTH = VIDEO_HDRAW_LENGTH + VIDEO_HBLANK_LENGTH,
VIDEO_HORIZONTAL_LENGTH = 1232,
VIDEO_VERTICAL_PIXELS = 160,
VIDEO_VBLANK_PIXELS = 68,
VIDEO_VERTICAL_TOTAL_PIXELS = VIDEO_VERTICAL_PIXELS + VIDEO_VBLANK_PIXELS,
VIDEO_VERTICAL_TOTAL_PIXELS = 228,
VIDEO_TOTAL_LENGTH = VIDEO_HORIZONTAL_LENGTH * VIDEO_VERTICAL_TOTAL_PIXELS,
VIDEO_TOTAL_LENGTH = 280896,
OBJ_HBLANK_FREE_LENGTH = 954,
OBJ_LENGTH = 1210,
@ -178,7 +178,7 @@ struct GBAVideo {
// VCOUNT
int vcount;
uint16_t palette[SIZE_PALETTE_RAM >> 1];
uint16_t palette[512];
uint16_t* vram;
union GBAOAM oam;

View File

@ -8,6 +8,36 @@
#include "lr35902/emitter-lr35902.h"
#include "lr35902/lr35902.h"
static inline uint16_t LR35902ReadHL(struct LR35902Core* cpu) {
uint16_t hl;
LOAD_16LE(hl, 0, &cpu->hl);
return hl;
}
static inline void LR35902WriteHL(struct LR35902Core* cpu, uint16_t hl) {
STORE_16LE(hl, 0, &cpu->hl);
}
static inline uint16_t LR35902ReadBC(struct LR35902Core* cpu) {
uint16_t bc;
LOAD_16LE(bc, 0, &cpu->bc);
return bc;
}
static inline void LR35902WriteBC(struct LR35902Core* cpu, uint16_t bc) {
STORE_16LE(bc, 0, &cpu->bc);
}
static inline uint16_t LR35902ReadDE(struct LR35902Core* cpu) {
uint16_t de;
LOAD_16LE(de, 0, &cpu->de);
return de;
}
static inline void LR35902WriteDE(struct LR35902Core* cpu, uint16_t de) {
STORE_16LE(de, 0, &cpu->de);
}
#define DEFINE_INSTRUCTION_LR35902(NAME, BODY) \
static void _LR35902Instruction ## NAME (struct LR35902Core* cpu) { \
UNUSED(cpu); \

View File

@ -23,9 +23,9 @@ union FlagRegister {
unsigned n : 1;
unsigned h : 1;
unsigned c : 1;
unsigned : 4;
unsigned unused : 4;
#else
unsigned : 4;
unsigned unused : 4;
unsigned c : 1;
unsigned h : 1;
unsigned n : 1;
@ -127,36 +127,6 @@ struct LR35902Core {
struct mCPUComponent** components;
};
static inline uint16_t LR35902ReadHL(struct LR35902Core* cpu) {
uint16_t hl;
LOAD_16LE(hl, 0, &cpu->hl);
return hl;
}
static inline void LR35902WriteHL(struct LR35902Core* cpu, uint16_t hl) {
STORE_16LE(hl, 0, &cpu->hl);
}
static inline uint16_t LR35902ReadBC(struct LR35902Core* cpu) {
uint16_t bc;
LOAD_16LE(bc, 0, &cpu->bc);
return bc;
}
static inline void LR35902WriteBC(struct LR35902Core* cpu, uint16_t bc) {
STORE_16LE(bc, 0, &cpu->bc);
}
static inline uint16_t LR35902ReadDE(struct LR35902Core* cpu) {
uint16_t de;
LOAD_16LE(de, 0, &cpu->de);
return de;
}
static inline void LR35902WriteDE(struct LR35902Core* cpu, uint16_t de) {
STORE_16LE(de, 0, &cpu->de);
}
void LR35902Init(struct LR35902Core* cpu);
void LR35902Deinit(struct LR35902Core* cpu);
void LR35902SetComponents(struct LR35902Core* cpu, struct mCPUComponent* master, int extra, struct mCPUComponent** extras);

View File

@ -0,0 +1,12 @@
find_program(PYTHON python)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in ${CMAKE_CURRENT_BINARY_DIR}/setup.py)
add_custom_command(OUTPUT build/lib/${BINARY_NAME}/__init__.py
COMMAND BINDIR=${CMAKE_CURRENT_BINARY_DIR}/.. ${PYTHON} ${CMAKE_CURRENT_BINARY_DIR}/setup.py build --build-base ${CMAKE_CURRENT_BINARY_DIR}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${BINARY_NAME}
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/setup.py
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/_builder.py)
add_custom_target(${BINARY_NAME}-py ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/build/lib/${BINARY_NAME}/__init__.py)

View File

@ -0,0 +1,49 @@
#define COMMON_H
#define PNG_H
#define _SYS_TIME_H
#define _SYS_TIME_H_
#define _TIME_H
#define _TIME_H_
#define ATTRIBUTE_FORMAT(X, Y, Z)
#define DECL_BITFIELD(newtype, oldtype) typedef oldtype newtype
#define DECL_BIT(type, name, bit)
#define DECL_BITS(type, name, bit, nbits)
#define CXX_GUARD_START
#define CXX_GUARD_END
typedef int... time_t;
typedef int... off_t;
typedef ... va_list;
typedef ...* png_structp;
typedef ...* png_infop;
typedef ...* png_unknown_chunkp;
void free(void*);
#include <limits.h>
#undef const
#include "flags.h"
#include "core/core.h"
#include "core/tile-cache.h"
#include "platform/python/vfs-py.h"
#include "platform/python/log.h"
#ifdef USE_PNG
#include "util/png-io.h"
#endif
#ifdef M_CORE_GBA
#include "arm/arm.h"
#include "gba/gba.h"
#include "gba/input.h"
#include "gba/renderers/tile-cache.h"
#endif
#ifdef M_CORE_GB
#include "lr35902/lr35902.h"
#include "gb/gb.h"
#include "gba/input.h"
#include "gb/renderers/tile-cache.h"
#endif

View File

@ -0,0 +1,64 @@
import cffi
import os, os.path
import shlex
import subprocess
import sys
ffi = cffi.FFI()
pydir = os.path.dirname(os.path.abspath(__file__))
srcdir = os.path.join(pydir, "..", "..")
bindir = os.environ.get("BINDIR", os.path.join(os.getcwd(), ".."))
cpp = shlex.split(os.environ.get("CPP", "cc -E"))
cppflags = shlex.split(os.environ.get("CPPFLAGS", ""))
if __name__ == "__main__":
cppflags.extend(sys.argv[1:])
cppflags.extend(["-I" + srcdir, "-I" + bindir])
ffi.set_source("mgba._pylib", """
#include "flags.h"
#include "util/common.h"
#include "core/core.h"
#include "core/log.h"
#include "core/tile-cache.h"
#include "arm/arm.h"
#include "gba/gba.h"
#include "gba/input.h"
#include "gba/renderers/tile-cache.h"
#include "lr35902/lr35902.h"
#include "gb/gb.h"
#include "gb/renderers/tile-cache.h"
#include "util/png-io.h"
#include "util/vfs.h"
struct VFile* VFileFromPython(void* fileobj);
struct VFilePy {
struct VFile d;
void* fileobj;
};
struct mLogger* mLoggerPythonCreate(void* pyobj);
struct mLoggerPy {
struct mLogger d;
void* pyobj;
};
""", include_dirs=[srcdir],
extra_compile_args=cppflags,
libraries=["mgba"],
library_dirs=[bindir],
sources=[os.path.join(pydir, path) for path in ["vfs-py.c", "log.c"]])
preprocessed = subprocess.check_output(cpp + ["-fno-inline", "-P"] + cppflags + [os.path.join(pydir, "_builder.h")], universal_newlines=True)
lines = []
for line in preprocessed.splitlines():
line = line.strip()
if line.startswith('#'):
continue
lines.append(line)
ffi.cdef('\n'.join(lines))
if __name__ == "__main__":
ffi.compile()

27
src/platform/python/log.c Normal file
View File

@ -0,0 +1,27 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "core/log.h"
struct mLoggerPy {
struct mLogger d;
void* pyobj;
};
void _pyLog(void* logger, int category, enum mLogLevel level, const char* message);
static void _pyLogShim(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
struct mLoggerPy* pylogger = (struct mLoggerPy*) logger;
char message[256] = {0};
vsnprintf(message, sizeof(message) - 1, format, args);
_pyLog(pylogger, category, level, message);
}
struct mLogger* mLoggerPythonCreate(void* pyobj) {
struct mLoggerPy* logger = malloc(sizeof(*logger));
logger->d.log = _pyLogShim;
logger->pyobj = pyobj;
return &logger->d;
}

15
src/platform/python/log.h Normal file
View File

@ -0,0 +1,15 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "core/log.h"
struct mLoggerPy {
struct mLogger d;
void* pyobj;
};
struct mLogger* mLoggerPythonCreate(void* pyobj);
extern "Python+C" void _pyLog(void* logger, int category, enum mLogLevel level, const char* message);

View File

View File

@ -0,0 +1,28 @@
# Copyright (c) 2013-2016 Jeffrey Pfau
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from ._pylib import ffi, lib
class _ARMRegisters:
def __init__(self, cpu):
self._cpu = cpu
def __getitem__(self, r):
if r > lib.ARM_PC:
raise IndexError("Register out of range")
return self._cpu._native.gprs[r]
def __setitem__(self, r, value):
if r >= lib.ARM_PC:
raise IndexError("Register out of range")
self._cpu._native.gprs[r] = value
class ARMCore:
def __init__(self, native):
self._native = ffi.cast("struct ARMCore*", native)
self.gprs = _ARMRegisters(self)
self.cpsr = self._native.cpsr
self.spsr = self._native.spsr

View File

@ -0,0 +1,162 @@
# Copyright (c) 2013-2016 Jeffrey Pfau
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from ._pylib import ffi, lib
from . import tile
from cached_property import cached_property
def find(path):
core = lib.mCoreFind(path.encode('UTF-8'))
if core == ffi.NULL:
return None
return Core._init(core)
def findVF(vf):
core = lib.mCoreFindVF(vf.handle)
if core == ffi.NULL:
return None
return Core._init(core)
def loadPath(path):
core = find(path)
if not core or not core.loadFile(path):
return None
return core
def loadVF(vf):
core = findVF(vf)
if not core or not core.loadROM(vf):
return None
return core
def needsReset(f):
def wrapper(self, *args, **kwargs):
if not self._wasReset:
raise RuntimeError("Core must be reset first")
return f(self, *args, **kwargs)
return wrapper
class Core(object):
def __init__(self, native):
self._core = native
self._wasReset = False
@cached_property
def tiles(self):
return tile.TileView(self)
@classmethod
def _init(cls, native):
core = ffi.gc(native, native.deinit)
success = bool(core.init(core))
if not success:
raise RuntimeError("Failed to initialize core")
if hasattr(cls, 'PLATFORM_GBA') and core.platform(core) == cls.PLATFORM_GBA:
return GBA(core)
if hasattr(cls, 'PLATFORM_GB') and core.platform(core) == cls.PLATFORM_GB:
return GB(core)
return Core(core)
def _deinit(self):
self._core.deinit(self._core)
def loadFile(self, path):
return bool(lib.mCoreLoadFile(self._core, path.encode('UTF-8')))
def isROM(self, vf):
return bool(self._core.isROM(vf.handle))
def loadROM(self, vf):
return bool(self._core.loadROM(self._core, vf.handle))
def loadSave(self, vf):
return bool(self._core.loadSave(self._core, vf.handle))
def loadTemporarySave(self, vf):
return bool(self._core.loadTemporarySave(self._core, vf.handle))
def loadPatch(self, vf):
return bool(self._core.loadPatch(self._core, vf.handle))
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 setVideoBuffer(self, image):
self._core.setVideoBuffer(self._core, image.buffer, image.stride)
def reset(self):
self._core.reset(self._core)
self._wasReset = True
@needsReset
def runFrame(self):
self._core.runFrame(self._core)
@needsReset
def runLoop(self):
self._core.runLoop(self._core)
@needsReset
def step(self):
self._core.step(self._core)
@staticmethod
def _keysToInt(*args, **kwargs):
keys = 0
if 'raw' in kwargs:
keys = kwargs['raw']
for key in args:
keys |= 1 << key
return keys
def setKeys(self, *args, **kwargs):
self._core.setKeys(self._core, self._keysToInt(*args, **kwargs))
def addKeys(self, *args, **kwargs):
self._core.addKeys(self._core, self._keysToInt(*args, **kwargs))
def clearKeys(self, *args, **kwargs):
self._core.clearKeys(self._core, self._keysToInt(*args, **kwargs))
@needsReset
def frameCounter(self):
return self._core.frameCounter(self._core)
def frameCycles(self):
return self._core.frameCycles(self._core)
def frequency(self):
return self._core.frequency(self._core)
def getGameTitle(self):
title = ffi.new("char[16]")
self._core.getGameTitle(self._core, title)
return ffi.string(title, 16).decode("ascii")
def getGameCode(self):
code = ffi.new("char[12]")
self._core.getGameCode(self._core, code)
return ffi.string(code, 12).decode("ascii")
if hasattr(lib, 'PLATFORM_GBA'):
from .gba import GBA
Core.PLATFORM_GBA = lib.PLATFORM_GBA
if hasattr(lib, 'PLATFORM_GB'):
from .gb import GB
from .lr35902 import LR35902Core
Core.PLATFORM_GB = lib.PLATFORM_GB

View File

@ -0,0 +1,81 @@
# Copyright (c) 2013-2016 Jeffrey Pfau
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from ._pylib import ffi, lib
from .lr35902 import LR35902Core
from .core import Core, needsReset
from .memory import Memory
from .tile import Sprite
class GB(Core):
KEY_A = lib.GBA_KEY_A
KEY_B = lib.GBA_KEY_B
KEY_SELECT = lib.GBA_KEY_SELECT
KEY_START = lib.GBA_KEY_START
KEY_DOWN = lib.GBA_KEY_DOWN
KEY_UP = lib.GBA_KEY_UP
KEY_LEFT = lib.GBA_KEY_LEFT
KEY_RIGHT = lib.GBA_KEY_RIGHT
def __init__(self, native):
super(GB, self).__init__(native)
self._native = ffi.cast("struct GB*", native.board)
self.sprites = GBObjs(self)
self.cpu = LR35902Core(self._core.cpu)
@needsReset
def _initTileCache(self, cache):
lib.GBVideoTileCacheInit(cache)
lib.GBVideoTileCacheAssociate(cache, ffi.addressof(self._native.video))
def _deinitTileCache(self, cache):
self._native.video.renderer.cache = ffi.NULL
lib.mTileCacheDeinit(cache)
class GBMemory(Memory):
def __init__(self, core):
super(GBMemory, self).__init__(core, 0x10000)
self.cart = Memory(core, lib.GB_SIZE_CART_BANK0 * 2, lib.GB_BASE_CART_BANK0)
self.vram = Memory(core, lib.GB_SIZE_VRAM, lib.GB_BASE_VRAM)
self.sram = Memory(core, lib.GB_SIZE_EXTERNAL_RAM, lib.GB_REGION_EXTERNAL_RAM)
self.iwram = Memory(core, lib.GB_SIZE_WORKING_RAM_BANK0, lib.GB_BASE_WORKING_RAM_BANK0)
self.oam = Memory(core, lib.GB_SIZE_OAM, lib.GB_BASE_OAM)
self.io = Memory(core, lib.GB_SIZE_IO, lib.GB_BASE_IO)
self.hram = Memory(core, lib.GB_SIZE_HRAM, lib.GB_BASE_HRAM)
class GBSprite(Sprite):
PALETTE_BASE = 8,
def __init__(self, obj, core):
self.x = obj.x
self.y = obj.y
self.tile = obj.tile
self._attr = obj.attr
self.width = 8
lcdc = core._native.memory.io[0x40]
self.height = 16 if lcdc & 4 else 8
if core._native.model >= lib.GB_MODEL_CGB:
if self._attr & 8:
self.tile += 512
self.paletteId = self._attr & 7
else:
self.paletteId = (self._attr >> 4) & 1
class GBObjs:
def __init__(self, core):
self._core = core
self._obj = core._native.video.oam.obj
def __len__(self):
return 40
def __getitem__(self, index):
if index >= len(self):
raise IndexError()
sprite = GBSprite(self._obj[index], self._core)
sprite.constitute(self._core.tiles, 0, 0)
return sprite

View File

@ -0,0 +1,96 @@
# Copyright (c) 2013-2016 Jeffrey Pfau
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from ._pylib import ffi, lib
from .arm import ARMCore
from .core import Core, needsReset
from .tile import Sprite
from .memory import Memory
class GBA(Core):
KEY_A = lib.GBA_KEY_A
KEY_B = lib.GBA_KEY_B
KEY_SELECT = lib.GBA_KEY_SELECT
KEY_START = lib.GBA_KEY_START
KEY_DOWN = lib.GBA_KEY_DOWN
KEY_UP = lib.GBA_KEY_UP
KEY_LEFT = lib.GBA_KEY_LEFT
KEY_RIGHT = lib.GBA_KEY_RIGHT
KEY_L = lib.GBA_KEY_L
KEY_R = lib.GBA_KEY_R
def __init__(self, native):
super(GBA, self).__init__(native)
self._native = ffi.cast("struct GBA*", native.board)
self.sprites = GBAObjs(self)
self.cpu = ARMCore(self._core.cpu)
@needsReset
def _initTileCache(self, cache):
lib.GBAVideoTileCacheInit(cache)
lib.GBAVideoTileCacheAssociate(cache, ffi.addressof(self._native.video))
def _deinitTileCache(self, cache):
self._native.video.renderer.cache = ffi.NULL
lib.mTileCacheDeinit(cache)
def reset(self):
super(GBA, self).reset()
self.memory = GBAMemory(self._core, self._native.memory.romSize)
class GBAMemory(Memory):
def __init__(self, core, romSize=lib.SIZE_CART0):
super(GBAMemory, self).__init__(core, 0x100000000)
self.bios = Memory(core, lib.SIZE_BIOS, lib.BASE_BIOS)
self.wram = Memory(core, lib.SIZE_WORKING_RAM, lib.BASE_WORKING_RAM)
self.iwram = Memory(core, lib.SIZE_WORKING_IRAM, lib.BASE_WORKING_IRAM)
self.io = Memory(core, lib.SIZE_IO, lib.BASE_IO)
self.palette = Memory(core, lib.SIZE_PALETTE_RAM, lib.BASE_PALETTE_RAM)
self.vram = Memory(core, lib.SIZE_VRAM, lib.BASE_VRAM)
self.oam = Memory(core, lib.SIZE_OAM, lib.BASE_OAM)
self.cart0 = Memory(core, romSize, lib.BASE_CART0)
self.cart1 = Memory(core, romSize, lib.BASE_CART1)
self.cart2 = Memory(core, romSize, lib.BASE_CART2)
self.cart = self.cart0
self.rom = self.cart0
self.sram = Memory(core, lib.SIZE_CART_SRAM, lib.BASE_CART_SRAM)
class GBASprite(Sprite):
TILE_BASE = 0x800, 0x400
PALETTE_BASE = 0x10, 1
def __init__(self, obj):
self._a = obj.a
self._b = obj.b
self._c = obj.c
self.x = self._b & 0x1FF
self.y = self._a & 0xFF
self._shape = self._a >> 14
self._size = self._b >> 14
self._256Color = bool(self._a & 0x2000)
self.width, self.height = lib.GBAVideoObjSizes[self._shape * 4 + self._size]
self.tile = self._c & 0x3FF
if self._256Color:
self.paletteId = 0
self.tile >>= 1
else:
self.paletteId = self._c >> 12
class GBAObjs:
def __init__(self, core):
self._core = core
self._obj = core._native.video.oam.obj
def __len__(self):
return 128
def __getitem__(self, index):
if index >= len(self):
raise IndexError()
sprite = GBASprite(self._obj[index])
map1D = bool(self._core._native.memory.io[0] & 0x40)
sprite.constitute(self._core.tiles, 0 if map1D else 0x20, int(sprite._256Color))
return sprite

View File

@ -0,0 +1,69 @@
# Copyright (c) 2013-2016 Jeffrey Pfau
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from ._pylib import ffi, lib
from . import png
class Image:
def __init__(self, width, height, stride=0):
self.width = width
self.height = height
self.stride = stride
self.constitute()
def constitute(self):
if self.stride <= 0:
self.stride = self.width
self.buffer = ffi.new("color_t[{}]".format(self.stride * self.height))
def savePNG(self, f):
p = png.PNG(f)
success = p.writeHeader(self)
success = success and p.writePixels(self)
p.writeClose()
return success
def u16ToU32(c):
r = c & 0x1F
g = (c >> 5) & 0x1F
b = (c >> 10) & 0x1F
a = (c >> 15) & 1
abgr = r << 3
abgr |= g << 11
abgr |= b << 19
abgr |= (a * 0xFF) << 24
return abgr
def u32ToU16(c):
r = (c >> 3) & 0x1F
g = (c >> 11) & 0x1F
b = (c >> 19) & 0x1F
a = c >> 31
abgr = r
abgr |= g << 5
abgr |= b << 10
abgr |= a << 15
return abgr
if ffi.sizeof("color_t") == 2:
def colorToU16(c):
return c
colorToU32 = u16ToU32
def u16ToColor(c):
return c
u32ToColor = u32ToU16
else:
def colorToU32(c):
return c
colorToU16 = u32ToU16
def u32ToColor(c):
return c
u16ToColor = u16ToU32

View File

@ -0,0 +1,38 @@
# Copyright (c) 2013-2016 Jeffrey Pfau
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from ._pylib import ffi, lib
@ffi.def_extern()
def _pyLog(logger, category, level, message):
l = ffi.cast("struct mLoggerPy*", logger)
ffi.from_handle(l.pyobj).log(category, level, ffi.string(message).decode('UTF-8'))
def installDefault(logger):
lib.mLogSetDefaultLogger(logger._native)
class Logger(object):
FATAL = lib.mLOG_FATAL
DEBUG = lib.mLOG_DEBUG
INFO = lib.mLOG_INFO
WARN = lib.mLOG_WARN
ERROR = lib.mLOG_ERROR
STUB = lib.mLOG_STUB
GAME_ERROR = lib.mLOG_GAME_ERROR
def __init__(self):
self._handle = ffi.new_handle(self)
self._native = ffi.gc(lib.mLoggerPythonCreate(self._handle), lib.free)
@staticmethod
def categoryName(category):
return ffi.string(lib.mLogCategoryName(category)).decode('UTF-8')
def log(self, category, level, message):
print("{}: {}".format(self.categoryName(category), message))
class NullLogger(Logger):
def log(self, category, level, message):
pass

View File

@ -0,0 +1,123 @@
# Copyright (c) 2013-2016 Jeffrey Pfau
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from ._pylib import ffi, lib
class LR35902Core:
def __init__(self, native):
self._native = ffi.cast("struct LR35902Core*", native)
@property
def a(self):
return self._native.a
@property
def b(self):
return self._native.b
@property
def c(self):
return self._native.c
@property
def d(self):
return self._native.d
@property
def e(self):
return self._native.e
@property
def f(self):
return self._native.f
@property
def h(self):
return self._native.h
@property
def l(self):
return self._native.l
@property
def sp(self):
return self._native.sp
@property
def pc(self):
return self._native.pc
@property
def af(self):
return (self.a << 8) | self.f
@property
def bc(self):
return (self.b << 8) | self.c
@property
def de(self):
return (self.d << 8) | self.e
@property
def hl(self):
return (self.h << 8) | self.l
@a.setter
def a(self, value):
self._native.a = value
@b.setter
def b(self, value):
self._native.b = value
@c.setter
def c(self, value):
self._native.c = value
@d.setter
def d(self, value):
self._native.d = value
@e.setter
def e(self, value):
self._native.e = value
@f.setter
def f(self, value):
self._native.f.packed = value
self._native.f.unused = 0
@h.setter
def h(self, value):
self._native.h = value
@l.setter
def l(self, value):
self._native.l = value
@sp.setter
def sp(self, value):
self._native.sp = value
@af.setter
def af(self, value):
self.a = value >> 8
self.f = value & 0xFF
@bc.setter
def bc(self, value):
self.b = value >> 8
self.c = value & 0xFF
@de.setter
def de(self, value):
self.d = value >> 8
self.e = value & 0xFF
@hl.setter
def hl(self, value):
self.h = value >> 8
self.l = value & 0xFF

View File

@ -0,0 +1,83 @@
# Copyright (c) 2013-2016 Jeffrey Pfau
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from ._pylib import ffi, lib
class MemoryView(object):
def __init__(self, core, width, size, base=0, sign="u"):
self._core = core
self._width = width
self._size = size
self._base = base
self._busRead = getattr(self._core, "busRead" + str(width * 8))
self._busWrite = getattr(self._core, "busWrite" + str(width * 8))
self._rawRead = getattr(self._core, "rawRead" + str(width * 8))
self._rawWrite = getattr(self._core, "rawWrite" + str(width * 8))
self._mask = (1 << (width * 8)) - 1 # Used to force values to fit within range so that negative values work
if sign == "u" or sign == "unsigned":
self._type = "uint{}_t".format(width * 8)
elif sign == "i" or sign == "s" or sign == "signed":
self._type = "int{}_t".format(width * 8)
else:
raise ValueError("Invalid sign type: '{}'".format(sign))
def _addrCheck(self, address):
if isinstance(address, slice):
start = address.start or 0
stop = self._size - self._width if address.stop is None else address.stop
else:
start = address
stop = address + self._width
if start >= self._size or stop > self._size:
raise IndexError()
if start < 0 or stop < 0:
raise IndexError()
def __len__(self):
return self._size
def __getitem__(self, address):
self._addrCheck(address)
if isinstance(address, slice):
start = address.start or 0
stop = self._size - self._width if address.stop is None else address.stop
step = address.step or self._width
return [int(ffi.cast(self._type, self._busRead(self._core, self._base + a))) for a in range(start, stop, step)]
else:
return int(ffi.cast(self._type, self._busRead(self._core, self._base + address)))
def __setitem__(self, address, value):
self._addrCheck(address)
if isinstance(address, slice):
start = address.start or 0
stop = self._size - self._width if address.stop is None else address.stop
step = address.step or self._width
for a in range(start, stop, step):
self._busWrite(self._core, self._base + a, value[a] & self._mask)
else:
self._busWrite(self._core, self._base + address, value & self._mask)
def rawRead(self, address, segment=-1):
self._addrCheck(address)
return int(ffi.cast(self._type, self._rawRead(self._core, self._base + address, segment)))
def rawWrite(self, address, value, segment=-1):
self._addrCheck(address)
self._rawWrite(self._core, self._base + address, segment, value & self._mask)
class Memory(object):
def __init__(self, core, size, base=0):
self.size = size
self.base = base
self.u8 = MemoryView(core, 1, size, base, "u")
self.u16 = MemoryView(core, 2, size, base, "u")
self.u32 = MemoryView(core, 4, size, base, "u")
self.s8 = MemoryView(core, 1, size, base, "s")
self.s16 = MemoryView(core, 2, size, base, "s")
self.s32 = MemoryView(core, 4, size, base, "s")
def __len__(self):
return self._size

View File

@ -0,0 +1,24 @@
# Copyright (c) 2013-2016 Jeffrey Pfau
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from ._pylib import ffi, lib
from . import vfs
class PNG:
def __init__(self, f):
self.vf = vfs.open(f)
def writeHeader(self, image):
self._png = lib.PNGWriteOpen(self.vf.handle)
self._info = lib.PNGWriteHeader(self._png, image.width, image.height)
return self._info != ffi.NULL
def writePixels(self, image):
return lib.PNGWritePixels(self._png, image.width, image.height, image.stride, image.buffer)
def writeClose(self):
lib.PNGWriteClose(self._png, self._info)
del self._png
del self._info

View File

@ -0,0 +1,57 @@
# Copyright (c) 2013-2016 Jeffrey Pfau
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from ._pylib import ffi, lib
from . import image
class Tile:
def __init__(self, data):
self.buffer = data
def toImage(self):
i = image.Image(8, 8)
self.composite(i, 0, 0)
return i
def composite(self, i, x, y):
for iy in range(8):
for ix in range(8):
i.buffer[ix + x + (iy + y) * i.stride] = image.u16ToColor(self.buffer[ix + iy * 8])
class TileView:
def __init__(self, core):
self.core = core
self.cache = ffi.gc(ffi.new("struct mTileCache*"), core._deinitTileCache)
core._initTileCache(self.cache)
lib.mTileCacheSetPalette(self.cache, 0)
self.paletteSet = 0
def getTile(self, tile, palette):
return Tile(lib.mTileCacheGetTile(self.cache, tile, palette))
def setPalette(self, paletteSet):
if paletteSet > 1 or paletteSet < 0:
raise IndexError("Palette Set ID out of bounds")
lib.mTileCacheSetPalette(self.cache, paletteSet)
self.paletteSet = paletteSet
class Sprite(object):
TILE_BASE = 0, 0
PALETTE_BASE = 0, 0
def constitute(self, tileView, tilePitch, paletteSet):
oldPaletteSet = tileView.paletteSet
tileView.setPalette(paletteSet)
i = image.Image(self.width, self.height)
tileId = self.tile + self.TILE_BASE[paletteSet]
for y in range(self.height // 8):
for x in range(self.width // 8):
tile = tileView.getTile(tileId, self.paletteId + self.PALETTE_BASE[paletteSet])
tile.composite(i, x * 8, y * 8)
tileId += 1
if tilePitch:
tileId += tilePitch - self.width // 8
self.image = i
tileView.setPalette(oldPaletteSet)

View File

@ -0,0 +1,130 @@
# Copyright (c) 2013-2016 Jeffrey Pfau
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from ._pylib import ffi, lib
import mmap
import os
@ffi.def_extern()
def _vfpClose(vf):
vfp = ffi.cast("struct VFilePy*", vf)
ffi.from_handle(vfp.fileobj).close()
@ffi.def_extern()
def _vfpSeek(vf, offset, whence):
vfp = ffi.cast("struct VFilePy*", vf)
f = ffi.from_handle(vfp.fileobj)
f.seek(offset, whence)
return f.tell()
@ffi.def_extern()
def _vfpRead(vf, buffer, size):
vfp = ffi.cast("struct VFilePy*", vf)
pybuf = ffi.buffer(buffer, size)
ffi.from_handle(vfp.fileobj).readinto(pybuf)
return size
@ffi.def_extern()
def _vfpWrite(vf, buffer, size):
vfp = ffi.cast("struct VFilePy*", vf)
pybuf = ffi.buffer(buffer, size)
ffi.from_handle(vfp.fileobj).write(pybuf)
return size
@ffi.def_extern()
def _vfpMap(vf, size, flags):
pass
@ffi.def_extern()
def _vfpUnmap(vf, memory, size):
pass
@ffi.def_extern()
def _vfpTruncate(vf, size):
vfp = ffi.cast("struct VFilePy*", vf)
ffi.from_handle(vfp.fileobj).truncate(size)
@ffi.def_extern()
def _vfpSize(vf):
vfp = ffi.cast("struct VFilePy*", vf)
f = ffi.from_handle(vfp.fileobj)
pos = f.tell()
f.seek(0, os.SEEK_END)
size = f.tell()
f.seek(pos, os.SEEK_SET)
return size
@ffi.def_extern()
def _vfpSync(vf, buffer, size):
vfp = ffi.cast("struct VFilePy*", vf)
f = ffi.from_handle(vfp.fileobj)
if buffer and size:
pos = f.tell()
f.seek(0, os.SEEK_SET)
_vfpWrite(vf, buffer, size)
f.seek(pos, os.SEEK_SET)
f.flush()
os.fsync()
return True
def open(f):
handle = ffi.new_handle(f)
vf = VFile(lib.VFileFromPython(handle))
# Prevent garbage collection
vf._fileobj = f
vf._handle = handle
return vf
def openPath(path, mode="r"):
flags = 0
if mode.startswith("r"):
flags |= os.O_RDONLY
elif mode.startswith("w"):
flags |= os.O_WRONLY | os.O_CREAT | os.O_TRUNC
elif mode.startswith("a"):
flags |= os.O_WRONLY | os.O_CREAT | os.O_APPEND
else:
return None
if "+" in mode[1:]:
flags |= os.O_RDWR
if "x" in mode[1:]:
flags |= os.O_EXCL
return VFile(lib.VFileOpen(path.encode("UTF-8"), flags))
class VFile:
def __init__(self, vf):
self.handle = vf
def close(self):
return self.handle.close(self.handle)
def seek(self, offset, whence):
return self.handle.seek(self.handle, offset, whence)
def read(self, buffer, size):
return self.handle.read(self.handle, buffer, size)
def readline(self, buffer, size):
return self.handle.readline(self.handle, buffer, size)
def write(self, buffer, size):
return self.handle.write(self.handle, buffer, size)
def map(self, size, flags):
return self.handle.map(self.handle, size, flags)
def unmap(self, memory, size):
self.handle.unmap(self.handle, memory, size)
def truncate(self, size):
self.handle.truncate(self.handle, size)
def size(self):
return self.handle.size(self.handle)
def sync(self, buffer, size):
return self.handle.sync(self.handle, buffer, size)

View File

@ -0,0 +1,24 @@
from setuptools import setup
import re
classifiers = [
"Programming Language :: C",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 3",
"License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
"Topic :: Games/Entertainment",
"Topic :: System :: Emulators"
]
setup(name="${BINARY_NAME}",
version=re.sub("/", "-", "${VERSION_STRING}"),
author="Jeffrey Pfau",
author_email="jeffrey@endrift.com",
url="http://github.com/mgba-emu/mgba/",
packages=["mgba"],
setup_requires=['cffi>=1.6'],
install_requires=['cffi>=1.6', 'cached-property'],
cffi_modules=["_builder.py:ffi"],
license="MPL 2.0",
classifiers=classifiers
)

View File

@ -0,0 +1,46 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "util/vfs.h"
struct VFilePy {
struct VFile d;
void* fileobj;
};
bool _vfpClose(struct VFile* vf);
off_t _vfpSeek(struct VFile* vf, off_t offset, int whence);
ssize_t _vfpRead(struct VFile* vf, void* buffer, size_t size);
ssize_t _vfpWrite(struct VFile* vf, const void* buffer, size_t size);
void* _vfpMap(struct VFile* vf, size_t size, int flags);
void _vfpUnmap(struct VFile* vf, void* memory, size_t size);
void _vfpTruncate(struct VFile* vf, size_t size);
ssize_t _vfpSize(struct VFile* vf);
bool _vfpSync(struct VFile* vf, const void* buffer, size_t size);
struct VFile* VFileFromPython(void* fileobj) {
if (!fileobj) {
return 0;
}
struct VFilePy* vfp = malloc(sizeof(struct VFilePy));
if (!vfp) {
return 0;
}
vfp->fileobj = fileobj;
vfp->d.close = _vfpClose;
vfp->d.seek = _vfpSeek;
vfp->d.read = _vfpRead;
vfp->d.readline = VFileReadline;
vfp->d.write = _vfpWrite;
vfp->d.map = _vfpMap;
vfp->d.unmap = _vfpUnmap;
vfp->d.truncate = _vfpTruncate;
vfp->d.size = _vfpSize;
vfp->d.sync = _vfpSync;
return &vfp->d;
}

View File

@ -0,0 +1,28 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "util/vfs.h"
struct VFilePy {
struct VFile d;
void* fileobj;
};
struct VFile* VFileFromPython(void* fileobj);
extern "Python+C" {
bool _vfpClose(struct VFile* vf);
off_t _vfpSeek(struct VFile* vf, off_t offset, int whence);
ssize_t _vfpRead(struct VFile* vf, void* buffer, size_t size);
ssize_t _vfpWrite(struct VFile* vf, const void* buffer, size_t size);
void* _vfpMap(struct VFile* vf, size_t size, int flags);
void _vfpUnmap(struct VFile* vf, void* memory, size_t size);
void _vfpTruncate(struct VFile* vf, size_t size);
ssize_t _vfpSize(struct VFile* vf);
bool _vfpSync(struct VFile* vf, const void* buffer, size_t size);
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2013-2015 Jeffrey Pfau
/* Copyright (c) 2013-2016 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -7,16 +7,20 @@
#include "gl-common.h"
#include "core/thread.h"
#ifndef __APPLE__
#include <malloc.h>
#endif
static bool mSDLGLES2Init(struct mSDLRenderer* renderer);
static void mSDLGLES2RunloopGBA(struct mSDLRenderer* renderer, void* user);
static void mSDLGLES2Runloop(struct mSDLRenderer* renderer, void* user);
static void mSDLGLES2Deinit(struct mSDLRenderer* renderer);
void mSDLGLES2Create(struct mSDLRenderer* renderer) {
renderer->init = mSDLGLES2Init;
renderer->deinit = mSDLGLES2Deinit;
renderer->runloop = mSDLGLES2RunloopGBA;
renderer->runloop = mSDLGLES2Runloop;
}
bool mSDLGLES2Init(struct mSDLRenderer* renderer) {
@ -93,8 +97,13 @@ bool mSDLGLES2Init(struct mSDLRenderer* renderer) {
mSDLGLCommonInit(renderer);
#endif
renderer->d.outputBuffer = memalign(16, VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4);
renderer->d.outputBufferStride = VIDEO_HORIZONTAL_PIXELS;
#ifndef __APPLE__
renderer->outputBuffer = memalign(16, renderer->width * renderer->height * BYTES_PER_PIXEL);
#else
posix_memalign((void**) &renderer->outputBuffer, 16, renderer->width * renderer->height * BYTES_PER_PIXEL);
#endif
memset(renderer->outputBuffer, 0, renderer->width * renderer->height * BYTES_PER_PIXEL);
renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, renderer->width);
mGLES2ContextCreate(&renderer->gl2);
renderer->gl2.d.user = renderer;
@ -107,17 +116,17 @@ bool mSDLGLES2Init(struct mSDLRenderer* renderer) {
}
void mSDLGLES2Runloop(struct mSDLRenderer* renderer, void* user) {
struct GBAThread* context = user;
struct mCoreThread* context = user;
SDL_Event event;
struct VideoBackend* v = &renderer->gl2.d;
while (context->state < THREAD_EXITING) {
while (SDL_PollEvent(&event)) {
mSDLHandleEventGBA(context, &renderer->player, &event);
mSDLHandleEvent(context, &renderer->player, &event);
}
if (mCoreSyncWaitFrameStart(&context->sync)) {
v->postFrame(v, renderer->d.outputBuffer);
v->postFrame(v, renderer->outputBuffer);
}
mCoreSyncWaitFrameEnd(&context->sync);
v->drawFrame(v);
@ -142,5 +151,5 @@ void mSDLGLES2Deinit(struct mSDLRenderer* renderer) {
#elif SDL_VERSION_ATLEAST(2, 0, 0)
SDL_GL_DeleteContext(renderer->glCtx);
#endif
free(renderer->d.outputBuffer);
free(renderer->outputBuffer);
}

View File

@ -24,7 +24,7 @@ void blip_set_rates( blip_t*, double clock_rate, double sample_rate );
enum { /** Maximum clock_rate/sample_rate ratio. For a given sample_rate,
clock_rate must not be greater than sample_rate*blip_max_ratio. */
blip_max_ratio = 1 << 20 };
blip_max_ratio = 0x100000 };
/** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */
void blip_clear( blip_t* );

View File

@ -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;

View File

@ -31,13 +31,8 @@ void TableClear(struct Table*);
void TableEnumerate(const struct Table*, void (handler(uint32_t key, void* value, void* user)), void* user);
size_t TableSize(const struct Table*);
static inline void HashTableInit(struct Table* table, size_t initialSize, void (deinitializer(void*))) {
TableInit(table, initialSize, deinitializer);
}
static inline void HashTableDeinit(struct Table* table) {
TableDeinit(table);
}
void HashTableInit(struct Table* table, size_t initialSize, void (deinitializer(void*)));
void HashTableDeinit(struct Table* table);
void* HashTableLookup(const struct Table*, const char* key);
void HashTableInsert(struct Table*, const char* key, void* value);

View File

@ -104,7 +104,7 @@ struct VDir* VDirOpenArchive(const char* path) {
dir = VDirOpenZip(path, 0);
}
#endif
#if USE_LZMA
#ifdef USE_LZMA
if (!dir) {
dir = VDirOpen7z(path, 0);
}

View File

@ -67,12 +67,11 @@ struct VDir {
struct VFile* VFileOpen(const char* path, int flags);
struct VFile* VFileOpenFD(const char* path, int flags);
struct VFile* VFileFOpen(const char* path, const char* mode);
struct VFile* VFileFromFD(int fd);
struct VFile* VFileFromMemory(void* mem, size_t size);
struct VFile* VFileFromConstMemory(const void* mem, size_t size);
struct VFile* VFileMemChunk(const void* mem, size_t size);
struct VFile* VFileFromFILE(FILE* file);
struct VDir* VDirOpen(const char* path);
struct VDir* VDirOpenArchive(const char* path);
@ -85,7 +84,11 @@ struct VDir* VDirOpenZip(const char* path, int flags);
struct VDir* VDirOpen7z(const char* path, int flags);
#endif
#if defined(WII) || defined(_3DS)
struct VFile* VFileFOpen(const char* path, const char* mode);
struct VFile* VFileFromFILE(FILE* file);
struct VDir* VDeviceList(void);
#endif
void separatePath(const char* path, char* dirname, char* basename, char* extension);