Finishing viewRead()/viewWrite()
This commit is contained in:
		
							parent
							
								
									cc25345960
								
							
						
					
					
						commit
						952605a8a4
					
				
							
								
								
									
										20
									
								
								makefile
								
								
								
								
							
							
						
						
									
										20
									
								
								makefile
								
								
								
								
							| 
						 | 
				
			
			@ -10,7 +10,7 @@ default:
 | 
			
		|||
	@echo
 | 
			
		||||
	@echo "Planet Virtual Boy Emulator"
 | 
			
		||||
	@echo "  https://www.planetvb.com/"
 | 
			
		||||
	@echo "  August 3, 2020"
 | 
			
		||||
	@echo "  August 4, 2020"
 | 
			
		||||
	@echo
 | 
			
		||||
	@echo "Intended build environment: Debian i386 or amd64"
 | 
			
		||||
	@echo "  gcc-multilib"
 | 
			
		||||
| 
						 | 
				
			
			@ -20,12 +20,12 @@ default:
 | 
			
		|||
	@echo "Usage: make <recipe>"
 | 
			
		||||
	@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"
 | 
			
		||||
	@echo "    desktop  Compiles the Java desktop application"
 | 
			
		||||
	@echo "    native   Builds all native modules"
 | 
			
		||||
	@echo "    pack     Bundles everything in a .jar file"
 | 
			
		||||
	@echo "    release  Produces a .jar and deletes all intermediate files"
 | 
			
		||||
	@echo "  Native recipes:"
 | 
			
		||||
	@echo "    lin32    Builds native module linux_x86"
 | 
			
		||||
	@echo "    lin64    Builds native module linux_x86-64"
 | 
			
		||||
| 
						 | 
				
			
			@ -46,14 +46,6 @@ build:
 | 
			
		|||
	@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
 | 
			
		||||
 | 
			
		||||
# Delete all output files
 | 
			
		||||
.PHONY: clean
 | 
			
		||||
clean: clean_most
 | 
			
		||||
| 
						 | 
				
			
			@ -95,6 +87,14 @@ pack:
 | 
			
		|||
	@jar -cfe $(jarname) Main *.class \
 | 
			
		||||
        app images locale native src util vue makefile license.txt
 | 
			
		||||
 | 
			
		||||
# Performs a full build and packages it into a .jar
 | 
			
		||||
.PHONY: release
 | 
			
		||||
release:
 | 
			
		||||
	@make -s build
 | 
			
		||||
	@make -s pack
 | 
			
		||||
	@echo "  Removing temporary files"
 | 
			
		||||
	@make -s clean_most
 | 
			
		||||
 | 
			
		||||
# Delete only Java .class files
 | 
			
		||||
.PHONY: clean_desktop
 | 
			
		||||
clean_desktop:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										147
									
								
								src/core/bus.c
								
								
								
								
							
							
						
						
									
										147
									
								
								src/core/bus.c
								
								
								
								
							| 
						 | 
				
			
			@ -1,47 +1,134 @@
 | 
			
		|||
/* 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) {
 | 
			
		||||
/* Read bytes from host memory */
 | 
			
		||||
static void busReadBytes(uint8_t *src, uint8_t *dest, uint32_t address,
 | 
			
		||||
    uint32_t size, uint32_t length) {
 | 
			
		||||
 | 
			
		||||
    /* 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;
 | 
			
		||||
        }
 | 
			
		||||
    /* There is no source data */
 | 
			
		||||
    if (src == NULL)
 | 
			
		||||
        while (length-- > 0)
 | 
			
		||||
            *dest++ = 0;
 | 
			
		||||
 | 
			
		||||
    /* Copy bytes from the source as a circular buffer */
 | 
			
		||||
    else for (size--; length-- > 0;)
 | 
			
		||||
        *dest++ = src[address++ & size];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Read a value directly from host memory */
 | 
			
		||||
static int32_t busReadMemory(uint8_t *data, uint32_t offset, int type) {
 | 
			
		||||
    int32_t value; /* Value read */
 | 
			
		||||
 | 
			
		||||
    /* There is no source data */
 | 
			
		||||
    if (data == NULL)
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
    /* Locate the value */
 | 
			
		||||
    data = &data[offset];
 | 
			
		||||
 | 
			
		||||
    /* Read the value */
 | 
			
		||||
    switch (type) {
 | 
			
		||||
        case VUE_S8 : value = *(int8_t   *)data; break;
 | 
			
		||||
        case VUE_U8 : value = *(uint8_t  *)data; break;
 | 
			
		||||
        case VUE_S16: value = *(int16_t  *)data; break;
 | 
			
		||||
        case VUE_U16: value = *(uint16_t *)data; break;
 | 
			
		||||
        case VUE_S32: value = *(int32_t  *)data; break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Host memory is big-endian */
 | 
			
		||||
    #else
 | 
			
		||||
    #ifdef VUE_BIGENDIAN
 | 
			
		||||
        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];
 | 
			
		||||
            case VUE_S32:
 | 
			
		||||
                value = (value >> 16 & 0x0000FFFF) | value << 16;
 | 
			
		||||
                /* Fallthrough */
 | 
			
		||||
            case VUE_S16:
 | 
			
		||||
            case VUE_U16:
 | 
			
		||||
                value = (value >> 8 & 0x00FF00FF) | (value << 8 & 0xFF00FF00);
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    return 0; /* Unreachable, but the compiler doesn't know that */
 | 
			
		||||
    return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Perform a read operation */
 | 
			
		||||
static int32_t busReadValue(VUE *vue, uint32_t address, int type, vbool debug){
 | 
			
		||||
    address &= ~TYPE_SIZES[type] + 1;
 | 
			
		||||
/* Read a value from the CPU bus */
 | 
			
		||||
static int32_t busReadValue(VUE *vue, uint32_t address, int type) {
 | 
			
		||||
    address &= -TYPE_SIZES[type];
 | 
			
		||||
    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);
 | 
			
		||||
        case 1: /* Fallthrough */ /* VSU (write-only) */
 | 
			
		||||
        case 3: /* Fallthrough */ /* Unmapped */
 | 
			
		||||
        case 4: /* Cartridge expansion (not supported) */
 | 
			
		||||
            return 0;
 | 
			
		||||
        case 5: return /* System WRAM */
 | 
			
		||||
            busReadMemory(vue->wram, address & 0xFFFF              , type);
 | 
			
		||||
        case 6: return /* Cartridge RAM */
 | 
			
		||||
            busReadMemory(vue->sram, address & (vue->sram_size - 1), type);
 | 
			
		||||
        case 7: return /* Cartridge ROM */
 | 
			
		||||
            busReadMemory(vue->rom , address & (vue->rom_size  - 1), type);
 | 
			
		||||
    }
 | 
			
		||||
    return 0; /* Unreachable */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Write bytes to host memory */
 | 
			
		||||
static void busWriteBytes(uint8_t *dest, uint8_t *src, uint32_t address,
 | 
			
		||||
    uint32_t size, uint32_t length) {
 | 
			
		||||
    if (dest != NULL)
 | 
			
		||||
        for (size--; length-- > 0;)
 | 
			
		||||
            dest[address++ & size] = *src++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Write a value directly to host memory */
 | 
			
		||||
static void busWriteMemory(uint8_t *data, uint32_t offset, int type,
 | 
			
		||||
    int32_t value) {
 | 
			
		||||
 | 
			
		||||
    /* There is no destination data */
 | 
			
		||||
    if (data == NULL)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    /* Locate the value */
 | 
			
		||||
    data = &data[offset];
 | 
			
		||||
 | 
			
		||||
    /* Host memory is big-endian */
 | 
			
		||||
    #ifdef VUE_BIGENDIAN
 | 
			
		||||
        switch (type) {
 | 
			
		||||
            case VUE_S32:
 | 
			
		||||
                value = (value >> 16 & 0x0000FFFF) | value << 16;
 | 
			
		||||
                /* Fallthrough */
 | 
			
		||||
            case VUE_S16:
 | 
			
		||||
            case VUE_U16:
 | 
			
		||||
                value = (value >> 8 & 0x00FF00FF) | (value << 8 & 0xFF00FF00);
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    /* Write the value */
 | 
			
		||||
    switch (type) {
 | 
			
		||||
        case VUE_S8 : /* Fallthrough */
 | 
			
		||||
        case VUE_U8 : *(uint8_t  *)data = (uint8_t) value; break;
 | 
			
		||||
        case VUE_S16: /* Fallthrough */
 | 
			
		||||
        case VUE_U16: *(uint16_t *)data = (int16_t) value; break;
 | 
			
		||||
        case VUE_S32: *(int32_t  *)data = (int32_t) value; break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Write a value to the CPU bus */
 | 
			
		||||
static void busWriteValue(VUE *vue, uint32_t address, int type, int32_t value){
 | 
			
		||||
    address &= -TYPE_SIZES[type];
 | 
			
		||||
    switch (address >> 24 & 7) {
 | 
			
		||||
        case 5: /* System WRAM */
 | 
			
		||||
            busWriteMemory(vue->wram,
 | 
			
		||||
                address & 0xFFFF              , type, value);
 | 
			
		||||
            break;
 | 
			
		||||
        case 6: /* Cartridge RAM */
 | 
			
		||||
            busWriteMemory(vue->sram,
 | 
			
		||||
                address & (vue->sram_size - 1), type, value);
 | 
			
		||||
            break;
 | 
			
		||||
        case 7: /* Cartridge ROM */
 | 
			
		||||
            busWriteMemory(vue->rom ,
 | 
			
		||||
                address & (vue->rom_size  - 1), type, value);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
    return debug * 0; /* Unreachable */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* VUEAPI */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,8 +55,9 @@ typedef struct {
 | 
			
		|||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
VUEAPI void  vueInitialize(VUE *vue);
 | 
			
		||||
VUEAPI vbool vueRead      (VUE *vue, uint32_t address, uint8_t *data, uint32_t length);
 | 
			
		||||
VUEAPI vbool vueRead      (VUE *vue, uint32_t address, uint8_t *dest, uint32_t length);
 | 
			
		||||
VUEAPI vbool vueSetROM    (VUE *vue, uint8_t *rom, uint32_t size);
 | 
			
		||||
VUEAPI vbool vueWrite     (VUE *vue, uint32_t address, uint8_t *src, uint32_t length);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,19 +30,16 @@ void vueInitialize(VUE *vue) {
 | 
			
		|||
    vue->sram = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Perform a read operation */
 | 
			
		||||
vbool vueRead(VUE *vue, uint32_t address, uint8_t *data, uint32_t length) {
 | 
			
		||||
/* Read bytes from the CPU bus */
 | 
			
		||||
vbool vueRead(VUE *vue, uint32_t address, uint8_t *dest, uint32_t length) {
 | 
			
		||||
    uint32_t count; /* Bytes to read in one iteration */
 | 
			
		||||
 | 
			
		||||
    /* Error checking */
 | 
			
		||||
    if (
 | 
			
		||||
        vue    == NULL ||
 | 
			
		||||
        data   == NULL ||
 | 
			
		||||
        length >  0x01000000
 | 
			
		||||
    ) return VUE_FALSE;
 | 
			
		||||
    if (vue == NULL || dest == NULL)
 | 
			
		||||
        return VUE_FALSE;
 | 
			
		||||
 | 
			
		||||
    /* Perform the operation */
 | 
			
		||||
    for (; length > 0; address += count, length -= count, data += count) {
 | 
			
		||||
    for (; length > 0; address += count, length -= count, dest += count) {
 | 
			
		||||
 | 
			
		||||
        /* Determine the maximum number of bytes to process at once */
 | 
			
		||||
        count = 0x01000000 - (address & 0x00FFFFFF);
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +48,20 @@ vbool vueRead(VUE *vue, uint32_t address, uint8_t *data, uint32_t length) {
 | 
			
		|||
 | 
			
		||||
        /* Process by component */
 | 
			
		||||
        switch (address >> 24 & 7) {
 | 
			
		||||
            /* case 7: ROM, etc */
 | 
			
		||||
            case 1: /* Fallthrough */ /* VSU (write-only) */
 | 
			
		||||
            case 3: /* Fallthrough */ /* Unmapped */
 | 
			
		||||
            case 4: /* Cartridge expansion (not supported) */
 | 
			
		||||
                busReadBytes(NULL     , dest, address, 0             , count);
 | 
			
		||||
                break;
 | 
			
		||||
            case 5: /* System WRAM */
 | 
			
		||||
                busReadBytes(vue->wram, dest, address, 0x10000       , count);
 | 
			
		||||
                break;
 | 
			
		||||
            case 6: /* Cartridge RAM */
 | 
			
		||||
                busReadBytes(vue->sram, dest, address, vue->sram_size, count);
 | 
			
		||||
                break;
 | 
			
		||||
            case 7: /* Cartridge ROM */
 | 
			
		||||
                busReadBytes(vue->rom , dest, address, vue->rom_size , count);
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			@ -74,3 +84,36 @@ vbool vueSetROM(VUE *vue, uint8_t *rom, uint32_t size) {
 | 
			
		|||
    vue->rom_size = size;
 | 
			
		||||
    return VUE_TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Write bytes to the CPU bus */
 | 
			
		||||
vbool vueWrite(VUE *vue, uint32_t address, uint8_t *src, uint32_t length) {
 | 
			
		||||
    uint32_t count; /* Bytes to write in one iteration */
 | 
			
		||||
 | 
			
		||||
    /* Error checking */
 | 
			
		||||
    if (vue == NULL || src == NULL)
 | 
			
		||||
        return VUE_FALSE;
 | 
			
		||||
 | 
			
		||||
    /* Perform the operation */
 | 
			
		||||
    for (; length > 0; address += count, length -= count, src += 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 5: /* System WRAM */
 | 
			
		||||
                busWriteBytes(vue->wram, src, address, 0x10000       , count);
 | 
			
		||||
                break;
 | 
			
		||||
            case 6: /* Cartridge RAM */
 | 
			
		||||
                busWriteBytes(vue->sram, src, address, vue->sram_size, count);
 | 
			
		||||
                break;
 | 
			
		||||
            case 7: /* Cartridge ROM */
 | 
			
		||||
                busWriteBytes(vue->rom , src, address, vue->rom_size , count);
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
    return VUE_TRUE;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,7 +96,7 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_isNative
 | 
			
		|||
    return JNI_TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Perform a read access
 | 
			
		||||
// 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) {
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +106,6 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_read
 | 
			
		|||
        data   == NULL ||
 | 
			
		||||
        offset <  0    ||
 | 
			
		||||
        length <  0    ||
 | 
			
		||||
        length <  0    || length > 0x01000000 ||
 | 
			
		||||
        offset + length > (*env)->GetArrayLength(env, data)
 | 
			
		||||
    ) return JNI_FALSE;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -143,3 +142,24 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_setROM
 | 
			
		|||
    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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,143 @@
 | 
			
		|||
package vue;
 | 
			
		||||
 | 
			
		||||
// Java imports
 | 
			
		||||
import java.util.*;
 | 
			
		||||
 | 
			
		||||
// Simulation of the CPU bus
 | 
			
		||||
class Bus {
 | 
			
		||||
 | 
			
		||||
    // Instance fields
 | 
			
		||||
    private JavaVUE vue; // Emulation state
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                             Constructors                              //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Default constructor
 | 
			
		||||
    Bus(JavaVUE vue) {
 | 
			
		||||
        this.vue = vue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Read bytes from host memory
 | 
			
		||||
    void readBytes(byte[] src,byte[] dest,int address,int offset,int length) {
 | 
			
		||||
 | 
			
		||||
        // There is no source data
 | 
			
		||||
        if (src == null) {
 | 
			
		||||
            Arrays.fill(dest, offset, offset + length, (byte) 0);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Copy bytes from the source as a circular buffer
 | 
			
		||||
        int count = 0; // Bytes to process in one iteration
 | 
			
		||||
        for (; length > 0; address += count, length -= count, offset += count){
 | 
			
		||||
            int from = address & src.length - 1;
 | 
			
		||||
            count    = Math.min(length, src.length - from);
 | 
			
		||||
            System.arraycopy(src, from, dest, offset, count);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Read a value directly from host memory
 | 
			
		||||
    int readMemory(byte[] data, int offset, int type) {
 | 
			
		||||
 | 
			
		||||
        // There is no source data
 | 
			
		||||
        if (data == null)
 | 
			
		||||
            return 0;
 | 
			
		||||
 | 
			
		||||
        // Processing by type
 | 
			
		||||
        switch (type) {
 | 
			
		||||
            case VUE.S8 : return data[offset];
 | 
			
		||||
            case VUE.U8 : return data[offset] & 0xFF;
 | 
			
		||||
            case VUE.S16: return
 | 
			
		||||
                 data[offset+1]         <<  8 |  data[offset  ] & 0xFF;
 | 
			
		||||
            case VUE.U16: return
 | 
			
		||||
                (data[offset+1] & 0xFF) <<  8 |  data[offset  ] & 0xFF;
 | 
			
		||||
            case VUE.S32: return
 | 
			
		||||
                 data[offset+3]         << 24 | (data[offset+2] & 0xFF) << 16 |
 | 
			
		||||
                (data[offset+1] & 0xFF) <<  8 | (data[offset  ] & 0xFF);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0; // Unreachable
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Read a value from the CPU bus
 | 
			
		||||
    int readValue(int address, int type) {
 | 
			
		||||
        address &= ~JavaVUE.TYPE_SIZES[type] + 1;
 | 
			
		||||
        switch (address >> 24 & 7) {
 | 
			
		||||
            case 1: // Fallthrough, VSU (write-only)
 | 
			
		||||
            case 3: // Fallthrough, unmapped
 | 
			
		||||
            case 4: // Cartridge expansion (not supported)
 | 
			
		||||
                return 0;
 | 
			
		||||
            case 5: return
 | 
			
		||||
                readMemory(vue.wram, address & 0xFFFF             , type);
 | 
			
		||||
            case 6: return
 | 
			
		||||
                readMemory(vue.sram, address & vue.sram.length - 1, type);
 | 
			
		||||
            case 7: return
 | 
			
		||||
                readMemory(vue.rom , address & vue.rom .length - 1, type);
 | 
			
		||||
        }
 | 
			
		||||
        return 0; // Unreachable
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Write bytes to host memory
 | 
			
		||||
    void writeBytes(byte[] dest,byte[] src,int address,int offset,int length) {
 | 
			
		||||
 | 
			
		||||
        // There is no destination data
 | 
			
		||||
        if (dest != null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // Copy bytes to the destination as a circular buffer
 | 
			
		||||
        int count = 0; // Bytes to process in one iteration
 | 
			
		||||
        for (; length > 0; address += count, length -= count, offset += count){
 | 
			
		||||
            int to = address & dest.length - 1;
 | 
			
		||||
            count  = Math.min(length, dest.length - to);
 | 
			
		||||
            System.arraycopy(src, offset, dest, to, count);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Write a value directly to host memory
 | 
			
		||||
    void writeMemory(byte[] data, int offset, int type, int value) {
 | 
			
		||||
 | 
			
		||||
        // There is no source data
 | 
			
		||||
        if (data == null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // Processing by type
 | 
			
		||||
        switch (type) {
 | 
			
		||||
            case VUE.S32:
 | 
			
		||||
                data[offset + 3] = (byte) (value >> 24);
 | 
			
		||||
                data[offset + 2] = (byte) (value >> 16);
 | 
			
		||||
                // Fallthrough
 | 
			
		||||
            case VUE.S16: // Fallthrough
 | 
			
		||||
            case VUE.U16:
 | 
			
		||||
                data[offset + 1] = (byte) (value >>  8);
 | 
			
		||||
                // Fallthrough
 | 
			
		||||
            case VUE.S8 : // Fallthrough
 | 
			
		||||
            case VUE.U8 :
 | 
			
		||||
                data[offset    ] = (byte)  value       ;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Write a value to the CPU bus
 | 
			
		||||
    void writeValue(int address, int type, int value) {
 | 
			
		||||
        address &= ~JavaVUE.TYPE_SIZES[type] + 1;
 | 
			
		||||
        switch (address >> 24 & 7) {
 | 
			
		||||
            case 5:
 | 
			
		||||
                writeMemory(vue.wram,
 | 
			
		||||
                    address & 0xFFFF             , type, value);
 | 
			
		||||
                break;
 | 
			
		||||
            case 6:
 | 
			
		||||
                writeMemory(vue.sram,
 | 
			
		||||
                    address & vue.sram.length - 1, type, value);
 | 
			
		||||
                break;
 | 
			
		||||
            case 7:
 | 
			
		||||
                writeMemory(vue.rom ,
 | 
			
		||||
                    address & vue.rom .length - 1, type, value);
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -4,8 +4,12 @@ package vue;
 | 
			
		|||
class JavaVUE extends VUE {
 | 
			
		||||
 | 
			
		||||
    // Instance fields
 | 
			
		||||
    private byte[] rom;  // Cartridge ROM
 | 
			
		||||
    private byte[] sram; // Cartridge SRAM
 | 
			
		||||
    byte[] rom;  // Cartridge ROM
 | 
			
		||||
    byte[] sram; // Cartridge SRAM
 | 
			
		||||
    byte[] wram; // System WRAM
 | 
			
		||||
 | 
			
		||||
    // Components
 | 
			
		||||
    Bus bus; // Memory bus
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -14,7 +18,7 @@ class JavaVUE extends VUE {
 | 
			
		|||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Memory access type sizes
 | 
			
		||||
    private static final int[] TYPE_SIZES = { 1, 1, 2, 2, 4 };
 | 
			
		||||
    static final int[] TYPE_SIZES = { 1, 1, 2, 2, 4 };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -24,6 +28,8 @@ class JavaVUE extends VUE {
 | 
			
		|||
 | 
			
		||||
    // Default constructor
 | 
			
		||||
    JavaVUE() {
 | 
			
		||||
        bus  = new Bus(this);
 | 
			
		||||
        wram = new byte[0x10000];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -47,19 +53,46 @@ class JavaVUE extends VUE {
 | 
			
		|||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Perform a read operation
 | 
			
		||||
    public boolean read(int address, byte[] data, int offset, int length) {
 | 
			
		||||
    // Read bytes from the CPU bus
 | 
			
		||||
    public boolean read(int address, byte[] dest, int offset, int length) {
 | 
			
		||||
        int count = 0; // Bytes to read in one iteration
 | 
			
		||||
 | 
			
		||||
        // Error checking
 | 
			
		||||
        if (data   == null ||
 | 
			
		||||
        if (
 | 
			
		||||
            dest   == null ||
 | 
			
		||||
            offset <  0    ||
 | 
			
		||||
            length <  0    ||
 | 
			
		||||
            length <  0    || length > 0x01000000 ||
 | 
			
		||||
            offset + length > data.length
 | 
			
		||||
            offset + length > dest.length
 | 
			
		||||
        ) return false;
 | 
			
		||||
 | 
			
		||||
        // Perform the operation
 | 
			
		||||
        for (; length > 0; address += count, length -= count, offset += count){
 | 
			
		||||
 | 
			
		||||
            // Determine the maximum number of bytes to process at once
 | 
			
		||||
            count = Math.min(length, 0x01000000 - (address & 0x00FFFFFF));
 | 
			
		||||
 | 
			
		||||
            // Process by component
 | 
			
		||||
            switch (address >> 24 & 7) {
 | 
			
		||||
                case 1: // VSU
 | 
			
		||||
                    // Will support debug reads
 | 
			
		||||
                    bus.readBytes(null, dest, address, 0     , count);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 3: // Fallthrough, unmapped
 | 
			
		||||
                case 4: // Cartridge expansion (not supported)
 | 
			
		||||
                    bus.readBytes(null, dest, address, 0     , count);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 5: /* System WRAM */
 | 
			
		||||
                    bus.readBytes(wram, dest, address, offset, count);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 6: /* Cartridge RAM */
 | 
			
		||||
                    bus.readBytes(sram, dest, address, offset, count);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 7: /* Cartridge ROM */
 | 
			
		||||
                    bus.readBytes(rom , dest, address, offset, count);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        };
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -81,4 +114,39 @@ class JavaVUE extends VUE {
 | 
			
		|||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Write bytes to the CPU bus
 | 
			
		||||
    public boolean write(int address, byte[] src, int offset, int length) {
 | 
			
		||||
        int count = 0; // Bytes to process in one iteration
 | 
			
		||||
 | 
			
		||||
        // Error checking
 | 
			
		||||
        if (
 | 
			
		||||
            src    == null ||
 | 
			
		||||
            offset <  0    ||
 | 
			
		||||
            length <  0    ||
 | 
			
		||||
            offset + length > src.length
 | 
			
		||||
        ) return false;
 | 
			
		||||
 | 
			
		||||
        // Perform the operation
 | 
			
		||||
        for (; length > 0; address += count, length -= count, offset += count){
 | 
			
		||||
 | 
			
		||||
            // Determine the maximum number of bytes to process at once
 | 
			
		||||
            count = Math.min(length, 0x01000000 - (address & 0x00FFFFFF));
 | 
			
		||||
 | 
			
		||||
            // Process by component
 | 
			
		||||
            switch (address >> 24 & 7) {
 | 
			
		||||
                case 5: /* System WRAM */
 | 
			
		||||
                    bus.writeBytes(wram, src, address, offset, count);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 6: /* Cartridge RAM */
 | 
			
		||||
                    bus.writeBytes(sram, src, address, offset, count);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 7: /* Cartridge ROM */
 | 
			
		||||
                    bus.writeBytes(rom , src, address, offset, count);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        };
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,13 +32,17 @@ 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,
 | 
			
		||||
    // Read bytes from the CPU bus
 | 
			
		||||
    public native boolean read(int address, byte[] dest, int offset,
 | 
			
		||||
        int length);
 | 
			
		||||
 | 
			
		||||
    // Provide new ROM data
 | 
			
		||||
    public native boolean setROM(byte[] data, int offset, int length);
 | 
			
		||||
 | 
			
		||||
    // Write bytes to the CPU bus
 | 
			
		||||
    public native boolean write(int address, byte[] src, int offset,
 | 
			
		||||
        int length);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,11 +61,15 @@ 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,
 | 
			
		||||
    // Read bytes from the CPU bus
 | 
			
		||||
    public abstract boolean read(int address, byte[] dest, int offset,
 | 
			
		||||
        int length);
 | 
			
		||||
 | 
			
		||||
    // Provide new ROM data
 | 
			
		||||
    public abstract boolean setROM(byte[] data, int offset, int length);
 | 
			
		||||
 | 
			
		||||
    // Write bytes to the CPU bus
 | 
			
		||||
    public abstract boolean write(int address, byte[] src, int offset,
 | 
			
		||||
        int length);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue