// Native-backed emulation core implementation #include #include #include #include #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; }