// Native-backed emulation core implementation #include #include #include #include #include #include "vue_NativeVue.h" /////////////////////////////////////////////////////////////////////////////// // Constants // /////////////////////////////////////////////////////////////////////////////// // Memory access type sizes static const int TYPE_SIZES[] = { 1, 1, 2, 2, 4 }; /////////////////////////////////////////////////////////////////////////////// // Types // /////////////////////////////////////////////////////////////////////////////// // Breakpoint token typedef struct { int32_t type; int32_t value; } Token; // Precompiled breakpoint typedef struct { int32_t enabled; // The breakpoint is enabled int32_t numAddresses; // Number of address ranges int32_t numCondition; // Number of tokens in condition int32_t *addresses; // Address ranges Token *condition; // Condition tokens in RPN order } Breakpoint; // Core context state type typedef struct { Vue vue; // Context into the generic C library int32_t numBreakpoints; // Number of breakpoints Breakpoint *breakpoints; // Application breakpoints int32_t *stack; // Expression stack for breakpoints } Core; /////////////////////////////////////////////////////////////////////////////// // Macros // /////////////////////////////////////////////////////////////////////////////// /* Sign-extend a value */ #define SIGN_EXTEND(bits, value) \ ((value) & 1 << (bits - 1) ? (value) | (~(1 << bits) + 1) : (value)) /////////////////////////////////////////////////////////////////////////////// // Component Includes // /////////////////////////////////////////////////////////////////////////////// #define NATIVEVue #include "Breakpoint.c" /////////////////////////////////////////////////////////////////////////////// // Internal Functions // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Method Functions // /////////////////////////////////////////////////////////////////////////////// // Native constructor JNIEXPORT jlong JNICALL Java_vue_NativeVue_construct (JNIEnv *env, jobject vue) { Core *mem[] = { NULL, NULL }; Core *core = mem[0] = calloc(sizeof (Core), 1); vueInitialize(&core->vue); vueReset(&core->vue); return *(jlong *)&core; } // Release any used resources JNIEXPORT void JNICALL Java_vue_NativeVue_dispose (JNIEnv *env, jobject vue, jlong handle) { Core *core = *(Core **)&handle; if (core->vue.pak.rom != NULL) free(core->vue.pak.rom); if (core->vue.pak.ram != NULL) free(core->vue.pak.ram); free(core); } // Process the simulation JNIEXPORT jint JNICALL Java_vue_NativeVue_emulate (JNIEnv *env, jobject vue, jlong handle, jint maxCycles) { Core *core = *(Core **)&handle; return vueEmulate(&core->vue, maxCycles); } // Evaluate the condition in a breakpoint JNIEXPORT jboolean JNICALL Java_vue_NativeVue_evaluate (JNIEnv *env, jobject vue, jlong handle, jobject brk) { Core *core = *(Core **)&handle; return JNI_FALSE; } // Retrieve the application break code JNIEXPORT jint JNICALL Java_vue_NativeVue_getBreakCode (JNIEnv *env, jobject vue, jlong handle) { Core *core = *(Core **)&handle; return vueGetBreakCode(&core->vue); } // Retrieve a register value JNIEXPORT jint JNICALL Java_vue_NativeVue_getRegister (JNIEnv *env, jobject vue, jlong handle, jint index, jboolean system) { Core *core = *(Core **)&handle; return vueGetRegister(&core->vue, index, system);; } // Retrieve a copy of the ROM data JNIEXPORT jbyteArray JNICALL Java_vue_NativeVue_getROM (JNIEnv *env, jobject vue, jlong handle) { Core *core = *(Core **)&handle; // No ROM data if (core->vue.pak.rom == NULL) return NULL; // Copy the ROM data jbyteArray ret = (*env)->NewByteArray(env, (jint)core->vue.pak.romSize); jbyte *elems = (*env)->GetByteArrayElements(env, ret, NULL); memcpy(elems, core->vue.pak.rom, core->vue.pak.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 a value from the CPU bus JNIEXPORT jint JNICALL Java_vue_NativeVue_read (JNIEnv *env, jobject vue, jlong handle, jint address, jint type) { Core *core = *(Core **)&handle; return vueRead(&core->vue, address, type); } // Read bytes from the CPU bus JNIEXPORT jboolean JNICALL Java_vue_NativeVue_readBytes (JNIEnv *env, jobject vue, jlong handle, 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 = *(Core **)&handle; jbyte *elems = (*env)->GetByteArrayElements(env, data, NULL); vueReadBytes(&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, jlong handle) { Core *core = *(Core **)&handle; vueReset(&core->vue); } // Specify an exception breakpoint callback JNIEXPORT void JNICALL Java_vue_NativeVue_setException (JNIEnv *env, jobject vue, jlong handle, jobject onException) { Core *core = *(Core **)&handle; } // Specify an execute breakpoint callback JNIEXPORT void JNICALL Java_vue_NativeVue_setExecute (JNIEnv *env, jobject vue, jlong handle, jobject onExecute) { Core *core = *(Core **)&handle; } // Specify a read breakpoint callback JNIEXPORT void JNICALL Java_vue_NativeVue_setRead (JNIEnv *env, jobject vue, jlong handle, jobject onRead) { Core *core = *(Core **)&handle; } // Specify a register value JNIEXPORT jint JNICALL Java_vue_NativeVue_setRegister (JNIEnv *env, jobject vue, jlong handle, jint index, jboolean system, jint value) { Core *core = *(Core **)&handle; return vueSetRegister(&core->vue, index, system, value); } // Provide new ROM data JNIEXPORT jboolean JNICALL Java_vue_NativeVue_setROM (JNIEnv *env, jobject vue, jlong handle, 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 = malloc(length); 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 = *(Core **)&handle; if (core->vue.pak.rom != NULL) free(core->vue.pak.rom); vueSetROM(&core->vue, rom, length); return JNI_TRUE; } // Specify a write breakpoint callback JNIEXPORT void JNICALL Java_vue_NativeVue_setWrite (JNIEnv *env, jobject vue, jlong handle, jobject onWrite) { Core *core = *(Core **)&handle; } // Write a value to the CPU bus JNIEXPORT void JNICALL Java_vue_NativeVue_write (JNIEnv *env, jobject vue, jlong handle, jint address, jint type, jint value) { Core *core = *(Core **)&handle; vueWrite(&core->vue, address, type, value); } // Write bytes to the CPU bus JNIEXPORT jboolean JNICALL Java_vue_NativeVue_writeBytes (JNIEnv *env, jobject vue, jlong handle, 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 = *(Core **)&handle; jbyte *elems = (*env)->GetByteArrayElements(env, data, NULL); vueWriteBytes(&core->vue, address, &elems[offset], length); (*env)->ReleaseByteArrayElements(env, data, elems, 0); return JNI_TRUE; }