GBA SIO: Add generic JOY bus implementation, Python bindings
Vicki Pfau vi@endrift.com
Sat, 21 Oct 2017 17:26:05 -0700
8 files changed,
130 insertions(+),
1 deletions(-)
M
CMakeLists.txt
→
CMakeLists.txt
@@ -55,7 +55,7 @@ file(GLOB UTIL_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/util/*.[cSs])
file(GLOB UTIL_TEST_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/util/test/*.c) file(GLOB GUI_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/util/gui/*.c ${CMAKE_CURRENT_SOURCE_DIR}/src/feature/gui/*.c) file(GLOB GBA_RENDERER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/renderers/*.c) -file(GLOB GBA_SIO_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/sio/lockstep.c) +file(GLOB GBA_SIO_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/sio/*.c) file(GLOB GBA_EXTRA_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/extra/*.c) file(GLOB GB_SIO_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gb/sio/*.c) file(GLOB GB_RENDERER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gb/renderers/*.c)
M
include/mgba/gba/interface.h
→
include/mgba/gba/interface.h
@@ -21,6 +21,13 @@ SIO_GPIO = 8,
SIO_JOYBUS = 12 }; +enum GBASIOJOYCommand { + JOY_RESET = 0xFF, + JOY_POLL = 0x00, + JOY_TRANS = 0x14, + JOY_RECV = 0x15 +}; + struct GBA; struct GBAAudio; struct GBASIO;@@ -47,6 +54,10 @@ bool (*load)(struct GBASIODriver* driver);
bool (*unload)(struct GBASIODriver* driver); uint16_t (*writeRegister)(struct GBASIODriver* driver, uint32_t address, uint16_t value); }; + +void GBASIOJOYCreate(struct GBASIODriver* sio); +int GBASIOJOYSendCommand(struct GBASIODriver* sio, enum GBASIOJOYCommand command, uint8_t* data); + CXX_GUARD_END
A
src/gba/sio/joybus.c
@@ -0,0 +1,76 @@
+/* Copyright (c) 2013-2017 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 <mgba/internal/gba/sio.h> + +#include <mgba/internal/gba/gba.h> +#include <mgba/internal/gba/io.h> + +static uint16_t GBASIOJOYWriteRegister(struct GBASIODriver* sio, uint32_t address, uint16_t value); + +void GBASIOJOYCreate(struct GBASIODriver* sio) { + sio->init = NULL; + sio->deinit = NULL; + sio->load = NULL; + sio->unload = NULL; + sio->writeRegister = GBASIOJOYWriteRegister; +} + +uint16_t GBASIOJOYWriteRegister(struct GBASIODriver* sio, uint32_t address, uint16_t value) { + switch (address) { + case REG_JOYCNT: + return (value & 0x0040) | (sio->p->p->memory.io[REG_JOYCNT >> 1] & ~(value & 0x7) & ~0x0040); + case REG_JOYSTAT: + return (value & 0x0030) | (sio->p->p->memory.io[REG_JOYSTAT >> 1] & ~0x30); + case REG_JOY_TRANS_LO: + case REG_JOY_TRANS_HI: + sio->p->p->memory.io[REG_JOYSTAT >> 1] |= 8; + break; + } + return value; +} + +int GBASIOJOYSendCommand(struct GBASIODriver* sio, enum GBASIOJOYCommand command, uint8_t* data) { + switch (command) { + case JOY_RESET: + sio->p->p->memory.io[REG_JOYCNT >> 1] |= 1; + if (sio->p->p->memory.io[REG_JOYCNT >> 1] & 0x40) { + GBARaiseIRQ(sio->p->p, IRQ_SIO); + } + // Fall through + case JOY_POLL: + data[0] = 0x00; + data[1] = 0x04; + data[2] = sio->p->p->memory.io[REG_JOYSTAT >> 1]; + return 3; + case JOY_RECV: + sio->p->p->memory.io[REG_JOYCNT >> 1] |= 2; + sio->p->p->memory.io[REG_JOYSTAT >> 1] |= 2; + + sio->p->p->memory.io[REG_JOY_RECV_LO >> 1] = data[0] | (data[1] << 8); + sio->p->p->memory.io[REG_JOY_RECV_HI >> 1] = data[2] | (data[3] << 8); + + data[0] = sio->p->p->memory.io[REG_JOYSTAT >> 1]; + + if (sio->p->p->memory.io[REG_JOYCNT >> 1] & 0x40) { + GBARaiseIRQ(sio->p->p, IRQ_SIO); + } + return 1; + case JOY_TRANS: + sio->p->p->memory.io[REG_JOYCNT >> 1] |= 4; + sio->p->p->memory.io[REG_JOYSTAT >> 1] &= ~8; + data[0] = sio->p->p->memory.io[REG_JOY_TRANS_LO >> 1]; + data[1] = sio->p->p->memory.io[REG_JOY_TRANS_LO >> 1] >> 8; + data[2] = sio->p->p->memory.io[REG_JOY_TRANS_HI >> 1]; + data[3] = sio->p->p->memory.io[REG_JOY_TRANS_HI >> 1] >> 8; + data[4] = sio->p->p->memory.io[REG_JOYSTAT >> 1]; + + if (sio->p->p->memory.io[REG_JOYCNT >> 1] & 0x40) { + GBARaiseIRQ(sio->p->p, IRQ_SIO); + } + return 5; + } + return 0; +}
M
src/platform/python/_builder.h
→
src/platform/python/_builder.h
@@ -53,6 +53,7 @@ #ifdef USE_PNG
#include <mgba-util/png-io.h> #endif #ifdef M_CORE_GBA +#include <mgba/gba/interface.h> #include <mgba/internal/arm/arm.h> #include <mgba/internal/gba/gba.h> #include <mgba/internal/gba/input.h>
M
src/platform/python/_builder.py
→
src/platform/python/_builder.py
@@ -30,6 +30,7 @@ #include <mgba/core/mem-search.h>
#include <mgba/core/thread.h> #include <mgba/core/version.h> #include <mgba/debugger/debugger.h> +#include <mgba/gba/interface.h> #include <mgba/internal/arm/arm.h> #include <mgba/internal/debugger/cli-debugger.h> #include <mgba/internal/gba/gba.h>
M
src/platform/python/mgba/gba.py
→
src/platform/python/mgba/gba.py
@@ -26,6 +26,7 @@ SIO_NORMAL_8 = lib.SIO_NORMAL_8
SIO_NORMAL_32 = lib.SIO_NORMAL_32 SIO_MULTI = lib.SIO_MULTI SIO_UART = lib.SIO_UART + SIO_JOYBUS = lib.SIO_JOYBUS SIO_GPIO = lib.SIO_GPIO def __init__(self, native):@@ -82,6 +83,32 @@ return True
def writeRegister(self, address, value): return value + +class GBASIOJOYDriver(GBASIODriver): + RESET = lib.JOY_RESET + POLL = lib.JOY_POLL + TRANS = lib.JOY_TRANS + RECV = lib.JOY_RECV + + def __init__(self): + self._handle = ffi.new_handle(self) + self._native = ffi.gc(lib.GBASIOJOYPythonDriverCreate(self._handle), lib.free) + + def sendCommand(self, cmd, data): + buffer = ffi.new('uint8_t[5]') + try: + buffer[0] = data[0] + buffer[1] = data[1] + buffer[2] = data[2] + buffer[3] = data[3] + buffer[4] = data[4] + except IndexError: + pass + + outlen = lib.GBASIOJOYSendCommand(self._native, cmd, buffer) + if outlen > 0 and outlen <= 5: + return bytes(buffer[0:outlen]) + return None class GBAMemory(Memory): def __init__(self, core, romSize=lib.SIZE_CART0):
M
src/platform/python/sio.c
→
src/platform/python/sio.c
@@ -46,6 +46,18 @@ driver->pyobj = pyobj;
return &driver->d; } +struct GBASIODriver* GBASIOJOYPythonDriverCreate(void* pyobj) { + struct GBASIOPythonDriver* driver = malloc(sizeof(*driver)); + GBASIOJOYCreate(&driver->d); + driver->d.init = _pyGBASIOPythonDriverInitShim; + driver->d.deinit = _pyGBASIOPythonDriverDeinitShim; + driver->d.load = _pyGBASIOPythonDriverLoadShim; + driver->d.unload = _pyGBASIOPythonDriverUnloadShim; + + driver->pyobj = pyobj; + return &driver->d; +} + #endif #ifdef M_CORE_GB
M
src/platform/python/sio.h
→
src/platform/python/sio.h
@@ -13,6 +13,7 @@ void* pyobj;
}; struct GBASIODriver* GBASIOPythonDriverCreate(void* pyobj); +struct GBASIODriver* GBASIOJOYPythonDriverCreate(void* pyobj); PYEXPORT bool _pyGBASIOPythonDriverInit(void* driver); PYEXPORT void _pyGBASIOPythonDriverDeinit(void* driver);