diff --git a/makefile b/makefile index afbe3c4..0a46fc7 100644 --- a/makefile +++ b/makefile @@ -19,6 +19,7 @@ default: @echo @echo "Usage: make " @echo " Package recipes:" + @echo " build Compiles the native modules and desktop application" @echo " bundle Produces a .jar and deletes all intermediate files" @echo " clean Deletes all output files" @echo " core Check the native core library for style errors" @@ -38,12 +39,17 @@ default: # Package Recipes # ############################################################################### -# Perform a full build process -.PHONY: bundle -bundle: +# Perform a full build process of the native modules and desktop application +.PHONY: build +build: @make -s core @make -s desktop @make -s native + +# Performs a full build and packages it into a .jar +.PHONY: bundle +bundle: + @make -s build @make -s pack @echo " Removing temporary files" @make -s clean_most diff --git a/src/desktop/Main.java b/src/desktop/Main.java index 5b50c55..dab1032 100644 --- a/src/desktop/Main.java +++ b/src/desktop/Main.java @@ -1,14 +1,47 @@ +// Java imports +import java.io.*; + // Project imports import app.*; import util.*; +import vue.*; // Desktop application primary class public class Main { // Program entry point public static void main(String[] args) { + + // Configure Swing look-and-feel Util.setSystemLAF(); + + // Load the native module, if available + for (String filename : Util.listFiles("native")) { + File file = null; + + // Skip .gitignore + if (filename.equals(".gitignore")) + continue; + + // Write the contents of the native object file + FileOutputStream stream = null; + try { + file = File.createTempFile("native", "." + filename); + stream = new FileOutputStream(file); + stream.write(Util.fileRead("native/" + filename)); + } catch (Exception e) { file = null; } + try { stream.close(); } catch (Exception e) { } + + // Load the native object file into the JVM + try { System.load(file.getAbsolutePath()); break; } + catch (Error e) { } + } + + // Begin application operations new App(); + + var vue = VUE.create(true); + System.out.println(vue.isNative()); } } diff --git a/src/desktop/app/ROM.java b/src/desktop/app/ROM.java index d5fa482..d72aa6a 100644 --- a/src/desktop/app/ROM.java +++ b/src/desktop/app/ROM.java @@ -96,7 +96,9 @@ public class ROM { // Produce a byte array containing the ROM contents public byte[] toByteArray() { - return data; + var ret = new byte[data.length]; + System.arraycopy(data, 0, ret, 0, data.length); + return ret; } @@ -136,7 +138,8 @@ public class ROM { int size = 1024; int minSize = (head == -1 ? 0 : head + 1) + (tail == -1 ? 0 : 0x01000000 - tail); - if (minSize == 0 || tail == -1 && (minSize - 1 & minSize) != 0) + if (minSize == 0 || tail == -1 && + (minSize < 1024 || (minSize - 1 & minSize) != 0)) throw new RuntimeException(); for (; size < minSize; size <<= 1); diff --git a/src/desktop/native/native.c b/src/desktop/native/native.c index 6cbf434..bbdb98f 100644 --- a/src/desktop/native/native.c +++ b/src/desktop/native/native.c @@ -1,7 +1,36 @@ +#include +#include +#include #include #include "vue_NativeVUE.h" -JNIEXPORT jint JNICALL Java_vue_NativeVUE_test(JNIEnv *env, jobject obj, - jint x, jint y) { - return x * y; +// Retrieve a copy of the ROM data +JNIEXPORT jbyteArray JNICALL Java_vue_NativeVUE_getROM + (JNIEnv *env, jobject vue) { +} + +// Determine whether the context is native-backed +JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_isNative + (JNIEnv *env, jobject vue) { + return JNI_TRUE; +} + +// Provide new ROM data +JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_setROM + (JNIEnv *env, jobject vue, jbyteArray data, jint offset, jint length) { + jsize data_length = (*env)->GetArrayLength(env, data); + + // Error checking + if (data == NULL || offset < 0 || length < 1024 || + offset + length > data_length || (length & length - 1) != 0) + return JNI_FALSE; + + // Accept the new ROM data + return JNI_TRUE; +} + +// Invoke native code to ensure the module is loaded +JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_testNative + (JNIEnv *env, jclass vue) { + return JNI_TRUE; } diff --git a/src/desktop/vue/JavaVUE.java b/src/desktop/vue/JavaVUE.java new file mode 100644 index 0000000..9e31b9a --- /dev/null +++ b/src/desktop/vue/JavaVUE.java @@ -0,0 +1,53 @@ +package vue; + +// Java emulation core implementation +// Native-backed emulation core implementation +class JavaVUE implements VUE { + + // Instance fields + private byte[] rom; // Cartridge ROM + + + + /////////////////////////////////////////////////////////////////////////// + // Constructors // + /////////////////////////////////////////////////////////////////////////// + + // Default constructor + JavaVUE() { + rom = new byte[1024]; + } + + + + /////////////////////////////////////////////////////////////////////////// + // Public Methods // + /////////////////////////////////////////////////////////////////////////// + + // Retrieve a copy of the ROM data + public byte[] getROM() { + var ret = new byte[rom.length]; + System.arraycopy(rom, 0, ret, 0, rom.length); + return ret; + } + + // Determine whether the context is native-backed + public boolean isNative() { + return false; + } + + // 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; + + // Accept the new ROM data + rom = new byte[length]; + System.arraycopy(data, offset, rom, 0, length); + return true; + } + +} diff --git a/src/desktop/vue/NativeVUE.java b/src/desktop/vue/NativeVUE.java index f8f9d46..295a1d6 100644 --- a/src/desktop/vue/NativeVUE.java +++ b/src/desktop/vue/NativeVUE.java @@ -1,13 +1,55 @@ package vue; // Native-backed emulation core implementation -class NativeVUE extends VUE { +class NativeVUE implements VUE { - // Retrieve the implementation's name - public String getName() { - return "Native"; + // Instance fields + private byte[] pointer; // Instance address in native memory + + + + /////////////////////////////////////////////////////////////////////////// + // Constructors // + /////////////////////////////////////////////////////////////////////////// + + // Default constructor + NativeVUE() { } - native int test(int x, int y); + + + /////////////////////////////////////////////////////////////////////////// + // Package Methods // + /////////////////////////////////////////////////////////////////////////// + + // Determine whether the native library has been loaded + static boolean isLoaded() { + try { return testNative(); } + catch (Exception e) { return false; } + } + + + + /////////////////////////////////////////////////////////////////////////// + // Public Methods // + /////////////////////////////////////////////////////////////////////////// + + // Retrieve a copy of the ROM data + public native byte[] getROM(); + + // Determine whether the context is native-backed + public native boolean isNative(); + + // Provide new ROM data + public native boolean setROM(byte[] data, int offset, int length); + + + + /////////////////////////////////////////////////////////////////////////// + // Private Methods // + /////////////////////////////////////////////////////////////////////////// + + // Invoke native code to ensure the module is loaded + private static native boolean testNative(); } diff --git a/src/desktop/vue/VUE.java b/src/desktop/vue/VUE.java index 6220378..21e002d 100644 --- a/src/desktop/vue/VUE.java +++ b/src/desktop/vue/VUE.java @@ -1,9 +1,31 @@ package vue; -// Template class for emulation core implementations -public abstract class VUE { +// Template for emulation core implementations +public interface VUE { - // Retrieve the implementation's name - public abstract String getName(); + /////////////////////////////////////////////////////////////////////////// + // Factory Methods // + /////////////////////////////////////////////////////////////////////////// + + // Produce an emulation core context + public static VUE create(boolean useNative) { + return !useNative ? new JavaVUE() : + NativeVUE.isLoaded() ? new NativeVUE() : null; + } + + + + /////////////////////////////////////////////////////////////////////////// + // Public Methods // + /////////////////////////////////////////////////////////////////////////// + + // Retrieve a copy of the ROM data + byte[] getROM(); + + // Determine whether the context is native-backed + boolean isNative(); + + // Provide new ROM data + boolean setROM(byte[] data, int offset, int length); }