pvbemu/src/desktop/vue/NativeVue.c

275 lines
8.6 KiB
C

// Native-backed emulation core implementation
#include <stdlib.h>
#include <string.h>
#include <math.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 //
///////////////////////////////////////////////////////////////////////////////
// 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;
}