197 lines
6.2 KiB
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;
|
|
}
|