pvbemu/src/desktop/vue/NativeVUE.c

197 lines
6.2 KiB
C

// Native-backed emulation core implementation
#include <stdlib.h>
#include <string.h>
#include <jni.h>
#include <vue.h>
#include "vue_NativeVUE.h"
///////////////////////////////////////////////////////////////////////////////
// Constants //
///////////////////////////////////////////////////////////////////////////////
// Memory access type sizes
static const int TYPE_SIZES[] = { 1, 1, 2, 2, 4 };
///////////////////////////////////////////////////////////////////////////////
// Types //
///////////////////////////////////////////////////////////////////////////////
// Core context state type
typedef struct {
VUE vue; /* Context into the generic C library */
} CORE;
///////////////////////////////////////////////////////////////////////////////
// Internal Functions //
///////////////////////////////////////////////////////////////////////////////
// Determine the field ID of NativeVUE.pointer
static jfieldID GetPointerID(JNIEnv *env, jobject vue) {
return (*env)->GetFieldID(env,
(*env)->GetObjectClass(env, vue), "pointer", "[B");
}
// Retrieve the handle to a NativeVUE's core context
static CORE* GetCore(JNIEnv *env, jobject vue) {
jbyteArray pointer =
(*env)->GetObjectField(env, vue, GetPointerID(env, vue));
jbyte *elems = (*env)->GetByteArrayElements(env, pointer, NULL);
CORE *core = *(CORE **)elems;
(*env)->ReleaseByteArrayElements(env, pointer, elems, 0);
return core;
}
///////////////////////////////////////////////////////////////////////////////
// Method Functions //
///////////////////////////////////////////////////////////////////////////////
// Native constructor
JNIEXPORT void JNICALL Java_vue_NativeVUE_construct
(JNIEnv *env, jobject vue) {
// Produce and initialize s new core context
CORE *core = calloc(sizeof (CORE), 1);
vueInitialize(&core->vue);
vueReset(&core->vue);
// Encode the context handle into a byte array
jbyteArray pointer = (*env)->NewByteArray(env, sizeof (void *));
jbyte *elems = (*env)->GetByteArrayElements(env, pointer, NULL);
*(CORE **)elems = core;
(*env)->ReleaseByteArrayElements(env, pointer, elems, 0);
(*env)->SetObjectField(env, vue, GetPointerID(env, vue), pointer);
}
// Release any used resources
JNIEXPORT void JNICALL Java_vue_NativeVUE_dispose
(JNIEnv *env, jobject vue) {
CORE *core = GetCore(env, vue);
if (core->vue.bus.rom != NULL)
free(core->vue.bus.rom);
if (core->vue.bus.sram != NULL)
free(core->vue.bus.sram);
free(core);
}
// Retrieve a register value
JNIEXPORT jint JNICALL Java_vue_NativeVUE_getRegister
(JNIEnv *env, jobject vue, jint index, jboolean system) {
CORE *core = GetCore(env, vue);
return vueGetRegister(&core->vue, index, system);;
}
// Retrieve a copy of the ROM data
JNIEXPORT jbyteArray JNICALL Java_vue_NativeVUE_getROM
(JNIEnv *env, jobject vue) {
CORE *core = GetCore(env, vue);
// No ROM data
if (core->vue.bus.rom == NULL)
return NULL;
// Copy the ROM data
jbyteArray ret = (*env)->NewByteArray(env, (jint)core->vue.bus.romSize);
jbyte *elems = (*env)->GetByteArrayElements(env, ret, NULL);
memcpy(elems, core->vue.bus.rom, core->vue.bus.romSize);
(*env)->ReleaseByteArrayElements(env, ret, elems, 0);
return ret;
}
// Determine whether the context is native-backed
JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_isNative
(JNIEnv *env, jobject vue) {
return JNI_TRUE;
}
// Read bytes from the CPU bus
JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_read
(JNIEnv *env, jobject vue, jint address, jbyteArray data, jint offset,
jint length) {
// Error checking
if (
data == NULL ||
offset < 0 ||
length < 0 ||
offset + length > (*env)->GetArrayLength(env, data)
) return JNI_FALSE;
// Perform the operation
CORE *core = GetCore(env, vue);
jbyte *elems = (*env)->GetByteArrayElements(env, data, NULL);
vueRead(&core->vue, address, &elems[offset], length);
(*env)->ReleaseByteArrayElements(env, data, elems, 0);
return JNI_TRUE;
}
// Initialize all system components
JNIEXPORT void JNICALL Java_vue_NativeVUE_reset
(JNIEnv *env, jobject vue) {
CORE *core = GetCore(env, vue);
vueReset(&core->vue);
}
// Specify a register value
JNIEXPORT jint JNICALL Java_vue_NativeVUE_setRegister
(JNIEnv *env, jobject vue, jint index, jboolean system, jint value) {
CORE *core = GetCore(env, vue);
return vueSetRegister(&core->vue, index, system, value);
}
// Provide new ROM data
JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_setROM
(JNIEnv *env, jobject vue, jbyteArray data, jint offset, jint length) {
// Error checking
if (
data == NULL ||
offset < 0 ||
length < 1024 || length > 0x01000000 ||
(length & length - 1) != 0 ||
offset + length > (*env)->GetArrayLength(env, data)
) return JNI_FALSE;
// Accept the new ROM data
uint8_t *rom = calloc(length, 1);
jbyte *elems = (*env)->GetByteArrayElements(env, data, NULL);
memcpy(rom, &elems[offset], length);
(*env)->ReleaseByteArrayElements(env, data, elems, 0);
// Transfer the ROM data to the emulation state
CORE *core = GetCore(env, vue);
if (core->vue.bus.rom != NULL)
free(core->vue.bus.rom);
vueSetROM(&core->vue, rom, length);
return JNI_TRUE;
}
/* Write bytes to the CPU bus */
JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_write
(JNIEnv *env, jobject vue, jint address, jbyteArray data, jint offset,
jint length) {
// Error checking
if (
data == NULL ||
offset < 0 ||
length < 0 ||
offset + length > (*env)->GetArrayLength(env, data)
) return JNI_FALSE;
// Perform the operation
CORE *core = GetCore(env, vue);
jbyte *elems = (*env)->GetByteArrayElements(env, data, NULL);
vueWrite(&core->vue, address, &elems[offset], length);
(*env)->ReleaseByteArrayElements(env, data, elems, 0);
return JNI_TRUE;
}