GBA SIO: Add generic JOY bus implementation, Python bindings

This commit is contained in:
Vicki Pfau 2017-10-21 17:26:05 -07:00
parent 5d72a2be9d
commit 63d7927b60
8 changed files with 130 additions and 1 deletions

View File

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

View File

@ -21,6 +21,13 @@ enum GBASIOMode {
SIO_JOYBUS = 12
};
enum GBASIOJOYCommand {
JOY_RESET = 0xFF,
JOY_POLL = 0x00,
JOY_TRANS = 0x14,
JOY_RECV = 0x15
};
struct GBA;
struct GBAAudio;
struct GBASIO;
@ -48,6 +55,10 @@ struct GBASIODriver {
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
#endif

76
src/gba/sio/joybus.c Normal file
View File

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

View File

@ -53,6 +53,7 @@ void free(void*);
#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>

View File

@ -30,6 +30,7 @@ ffi.set_source("mgba._pylib", """
#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>

View File

@ -26,6 +26,7 @@ class GBA(Core):
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):
@ -83,6 +84,32 @@ class GBASIODriver(object):
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):
super(GBAMemory, self).__init__(core, 0x100000000)

View File

@ -46,6 +46,18 @@ struct GBASIODriver* GBASIOPythonDriverCreate(void* 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

View File

@ -13,6 +13,7 @@ struct GBASIOPythonDriver {
};
struct GBASIODriver* GBASIOPythonDriverCreate(void* pyobj);
struct GBASIODriver* GBASIOJOYPythonDriverCreate(void* pyobj);
PYEXPORT bool _pyGBASIOPythonDriverInit(void* driver);
PYEXPORT void _pyGBASIOPythonDriverDeinit(void* driver);