From cc25345960db9781678e4a565b6c4fa1a3428c4b Mon Sep 17 00:00:00 2001 From: Guy Perfect Date: Mon, 3 Aug 2020 20:34:02 -0500 Subject: [PATCH] End of day: working on vueRead()/VUE.read() --- makefile | 7 ++- src/core/bus.c | 47 ++++++++++++++ src/core/include/vue.h | 45 +++++++++++++ src/core/vue.c | 74 ++++++++++++++++++++++ src/desktop/native/native.c | 112 +++++++++++++++++++++++---------- src/desktop/vue/JavaVUE.java | 41 ++++++++++-- src/desktop/vue/NativeVUE.java | 4 ++ src/desktop/vue/VUE.java | 17 +++++ 8 files changed, 307 insertions(+), 40 deletions(-) create mode 100644 src/core/bus.c diff --git a/makefile b/makefile index fe7eb2c..5e1391c 100644 --- a/makefile +++ b/makefile @@ -63,11 +63,14 @@ clean: clean_most .PHONY: core core: @echo " Checking native core library for style errors" - $(eval coreargs = -c -Isrc/core/include -Wall -Wextra \ + $(eval coreargs = -c -Isrc/core/include -Werror -Wall -Wextra -Wpedantic \ -fno-strict-aliasing -fsyntax-only src/core/vue.c) @gcc -std=c90 $(coreargs) + @gcc -std=c90 -D VUE_BIGENDIAN $(coreargs) @gcc -std=c99 $(coreargs) + @gcc -std=c99 -D VUE_BIGENDIAN $(coreargs) @gcc -std=c11 $(coreargs) + @gcc -std=c11 -D VUE_BIGENDIAN $(coreargs) # Compile the Java desktop application .PHONY: desktop @@ -161,5 +164,5 @@ win64: win64_pre native_common native_common: @echo " Building native module $(name)" @$(prefix)gcc $(include) -Isrc/core/include $(gccargs) -s -shared -O2 \ - -fno-strict-aliasing \ + -fno-strict-aliasing -Werror \ -o native/$(name)$(ext) src/desktop/native/native.c src/core/vue.c diff --git a/src/core/bus.c b/src/core/bus.c new file mode 100644 index 0000000..051dfcc --- /dev/null +++ b/src/core/bus.c @@ -0,0 +1,47 @@ +/* This file is included through vue.c and cannot be built directly. */ +#ifdef VUEAPI + +/* Read a value directly from host memory */ +static int32_t busReadMemory(uint8_t *data, int type) { + + /* Host memory is little-endian */ + #ifndef VUE_BIGENDIAN + switch (type) { + case VUE_S8 : return *(int8_t *)data; + case VUE_U8 : return *(uint8_t *)data; + case VUE_S16: return *(int16_t *)data; + case VUE_U16: return *(uint16_t *)data; + case VUE_S32: return *(int32_t *)data; + } + + /* Host memory is big-endian */ + #else + switch (type) { + case VUE_S8 : return (int8_t ) data[0]; + case VUE_U8 : return (uint8_t ) data[0]; + case VUE_S16: return (int16_t ) data[0] << 8 | data[1]; + case VUE_U16: return (uint16_t) data[0] << 8 | data[1]; + case VUE_S32: return (int32_t ) + data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; + } + #endif + + return 0; /* Unreachable, but the compiler doesn't know that */ +} + +/* Perform a read operation */ +static int32_t busReadValue(VUE *vue, uint32_t address, int type, vbool debug){ + address &= ~TYPE_SIZES[type] + 1; + switch (address >> 24 & 7) { + case 3: /* Unmapped */ + case 4: return 0; /* Cartridge expansion */ + case 5: return busReadMemory(&vue->wram[address & 8191], type); + case 6: return vue->sram == NULL ? 0 : + busReadMemory(&vue->sram[address & (vue->sram_size - 1)], type); + case 7: return vue->rom == NULL ? 0 : + busReadMemory(&vue->rom [address & (vue->rom_size - 1)], type); + } + return debug * 0; /* Unreachable */ +} + +#endif /* VUEAPI */ diff --git a/src/core/include/vue.h b/src/core/include/vue.h index 0f1254c..a4e708d 100644 --- a/src/core/include/vue.h +++ b/src/core/include/vue.h @@ -15,6 +15,51 @@ extern "C" { +/***************************************************************************** + * Constants * + *****************************************************************************/ + +/* Boolean values */ +#define VUE_FALSE 0 +#define VUE_TRUE 1 + +/* Memory access types */ +#define VUE_S8 0 +#define VUE_U8 1 +#define VUE_S16 2 +#define VUE_U16 3 +#define VUE_S32 4 + + + +/***************************************************************************** + * Types * + *****************************************************************************/ + +/* Boolean */ +typedef int vbool; + +/* Emulation state */ +typedef struct { + uint8_t *rom; /* Cartridge ROM */ + uint32_t rom_size; /* Number of bytes in cartridge ROM */ + uint8_t *sram; /* Cartridge RAM */ + uint32_t sram_size; /* Number of bytes in cartridge RAM */ + uint8_t wram[0x10000]; /* System memory */ +} VUE; + + + +/***************************************************************************** + * Function Prototypes * + *****************************************************************************/ + +VUEAPI void vueInitialize(VUE *vue); +VUEAPI vbool vueRead (VUE *vue, uint32_t address, uint8_t *data, uint32_t length); +VUEAPI vbool vueSetROM (VUE *vue, uint8_t *rom, uint32_t size); + + + #ifdef __cplusplus } #endif diff --git a/src/core/vue.c b/src/core/vue.c index 9a3b005..5236af4 100644 --- a/src/core/vue.c +++ b/src/core/vue.c @@ -1,2 +1,76 @@ #define VUEAPI #include + + + +/***************************************************************************** + * Constants * + *****************************************************************************/ + +/* Memory access type sizes */ +static const int TYPE_SIZES[] = { 1, 1, 2, 2, 4 }; + + + +/***************************************************************************** + * Component Includes * + *****************************************************************************/ + +#include "bus.c" + + + +/***************************************************************************** + * Library Functions * + *****************************************************************************/ + +/* Prepare an emulation state context for use */ +void vueInitialize(VUE *vue) { + vue->rom = NULL; + vue->sram = NULL; +} + +/* Perform a read operation */ +vbool vueRead(VUE *vue, uint32_t address, uint8_t *data, uint32_t length) { + uint32_t count; /* Bytes to read in one iteration */ + + /* Error checking */ + if ( + vue == NULL || + data == NULL || + length > 0x01000000 + ) return VUE_FALSE; + + /* Perform the operation */ + for (; length > 0; address += count, length -= count, data += count) { + + /* Determine the maximum number of bytes to process at once */ + count = 0x01000000 - (address & 0x00FFFFFF); + if (count > length) + count = length; + + /* Process by component */ + switch (address >> 24 & 7) { + /* case 7: ROM, etc */ + } + + }; + return VUE_TRUE; +} + +/* Specify a new ROM buffer */ +vbool vueSetROM(VUE *vue, uint8_t *rom, uint32_t size) { + + /* Error checking */ + if ( + vue == NULL || + rom == NULL || + size < 1024 || size > 0x01000000 || + (size & (size - 1)) != 0 + ) return VUE_FALSE; + + /* Accept the new ROM buffer */ + vue->rom = rom; + vue->rom_size = size; + return VUE_TRUE; +} diff --git a/src/desktop/native/native.c b/src/desktop/native/native.c index 2a70b3c..d26a2b3 100644 --- a/src/desktop/native/native.c +++ b/src/desktop/native/native.c @@ -1,60 +1,81 @@ -#include -#include #include #include #include +#include #include "vue_NativeVUE.h" -// NativeVUE class lookup data -static struct { - jclass clazz; // Handle to NativeVUE class - jfieldID pointer; // ID of NativeVUE.pointer field -} NativeVUE; + + +/////////////////////////////////////////////////////////////////////////////// +// Constants // +/////////////////////////////////////////////////////////////////////////////// + +// Memory access type sizes +static const int TYPE_SIZES[] = { 1, 1, 2, 2, 4 }; + + + +/////////////////////////////////////////////////////////////////////////////// +// Types // +/////////////////////////////////////////////////////////////////////////////// // Core context state type typedef struct { - uint8_t *rom; - uint32_t rom_size; + VUE vue; } 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, NativeVUE.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) { - // Initialize the class data - if (NativeVUE.clazz == NULL) { - NativeVUE.clazz = (*env)->GetObjectClass(env, vue); - NativeVUE.pointer = - (*env)->GetFieldID(env, NativeVUE.clazz, "pointer", "[B"); - } - // Produce and initialize s new core context CORE *core = calloc(sizeof (CORE), 1); - core->rom = calloc(1024, 1); + vueInitialize(&core->vue); + vueSetROM(&core->vue, calloc(1024, 1), 1024); // 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, NativeVUE.pointer, pointer); + (*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); - free(core->rom); + free(core->vue.rom); + if (core->vue.sram != NULL) + free(core->vue.sram); free(core); } @@ -62,9 +83,9 @@ JNIEXPORT void JNICALL Java_vue_NativeVUE_dispose JNIEXPORT jbyteArray JNICALL Java_vue_NativeVUE_getROM (JNIEnv *env, jobject vue) { CORE *core = GetCore(env, vue); - jbyteArray ret = (*env)->NewByteArray(env, (jint) core->rom_size); + jbyteArray ret = (*env)->NewByteArray(env, (jint) core->vue.rom_size); jbyte *elems = (*env)->GetByteArrayElements(env, ret, NULL); - memcpy(elems, core->rom, core->rom_size); + memcpy(elems, core->vue.rom, core->vue.rom_size); (*env)->ReleaseByteArrayElements(env, ret, elems, 0); return ret; } @@ -75,23 +96,50 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_isNative return JNI_TRUE; } +// Perform a read access +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 || + length < 0 || length > 0x01000000 || + 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; +} + // 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 || - offset + length > (*env)->GetArrayLength(env, data) || - (length & length - 1) != 0) - return JNI_FALSE; + 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 - CORE *core = GetCore(env, vue); - free(core->rom); - core->rom = calloc(length, 1); - jbyte *elems = (*env)->GetByteArrayElements(env, data, NULL); - memcpy(core->rom, &elems[offset], length); + uint8_t *rom = calloc(length, 1); + jbyte *elems = (*env)->GetByteArrayElements(env, data, NULL); + memcpy(rom, &elems[offset], length); (*env)->ReleaseByteArrayElements(env, data, elems, 0); - core->rom_size = (uint32_t) length; + + // Transfer the ROM data to the emulation state + CORE *core = GetCore(env, vue); + free(core->vue.rom); + vueSetROM(&core->vue, rom, length); return JNI_TRUE; } diff --git a/src/desktop/vue/JavaVUE.java b/src/desktop/vue/JavaVUE.java index f12b1d2..77d7843 100644 --- a/src/desktop/vue/JavaVUE.java +++ b/src/desktop/vue/JavaVUE.java @@ -4,7 +4,17 @@ package vue; class JavaVUE extends VUE { // Instance fields - private byte[] rom; // Cartridge ROM + private byte[] rom; // Cartridge ROM + private byte[] sram; // Cartridge SRAM + + + + /////////////////////////////////////////////////////////////////////////// + // Constants // + /////////////////////////////////////////////////////////////////////////// + + // Memory access type sizes + private static final int[] TYPE_SIZES = { 1, 1, 2, 2, 4 }; @@ -14,7 +24,6 @@ class JavaVUE extends VUE { // Default constructor JavaVUE() { - rom = new byte[1024]; } @@ -29,7 +38,7 @@ class JavaVUE extends VUE { // Retrieve a copy of the ROM data public byte[] getROM() { var ret = new byte[rom.length]; - System.arraycopy(rom, 0, ret, 0, rom.length); + System.arraycopy(rom, 0, ret, 0, ret.length); return ret; } @@ -38,13 +47,33 @@ class JavaVUE extends VUE { return false; } + // Perform a read operation + public boolean read(int address, byte[] data, int offset, int length) { + + // Error checking + if (data == null || + offset < 0 || + length < 0 || + length < 0 || length > 0x01000000 || + offset + length > data.length + ) return false; + + // Perform the operation + + return true; + } + // Provide new ROM data public boolean setROM(byte[] data, int offset, int length) { // Error checking - if (data == null || offset < 0 || length < 1024 || - offset + length > data.length || (length & length - 1) != 0) - return false; + if ( + data == null || + offset < 0 || + length < 1024 || length > 0x01000000 || + (length & length - 1) != 0 || + offset + length > data.length + ) return false; // Accept the new ROM data rom = new byte[length]; diff --git a/src/desktop/vue/NativeVUE.java b/src/desktop/vue/NativeVUE.java index ee3cfef..5840132 100644 --- a/src/desktop/vue/NativeVUE.java +++ b/src/desktop/vue/NativeVUE.java @@ -32,6 +32,10 @@ class NativeVUE extends VUE { // Determine whether the context is native-backed public native boolean isNative(); + // Perform a read operation + public native boolean read(int address, byte[] data, int offset, + int length); + // Provide new ROM data public native boolean setROM(byte[] data, int offset, int length); diff --git a/src/desktop/vue/VUE.java b/src/desktop/vue/VUE.java index 7749f45..6ec6c27 100644 --- a/src/desktop/vue/VUE.java +++ b/src/desktop/vue/VUE.java @@ -8,6 +8,19 @@ public abstract class VUE { + /////////////////////////////////////////////////////////////////////////// + // Constants // + /////////////////////////////////////////////////////////////////////////// + + // Memory access types + public static final int S8 = 0; + public static final int U8 = 1; + public static final int S16 = 2; + public static final int U16 = 3; + public static final int S32 = 4; + + + /////////////////////////////////////////////////////////////////////////// // Static Methods // /////////////////////////////////////////////////////////////////////////// @@ -48,6 +61,10 @@ public abstract class VUE { // Determine whether the context is native-backed public abstract boolean isNative(); + // Perform a read operation + public abstract boolean read(int address, byte[] data, int offset, + int length); + // Provide new ROM data public abstract boolean setROM(byte[] data, int offset, int length);