Finishing viewRead()/viewWrite()
This commit is contained in:
parent
cc25345960
commit
952605a8a4
20
makefile
20
makefile
|
@ -10,7 +10,7 @@ default:
|
||||||
@echo
|
@echo
|
||||||
@echo "Planet Virtual Boy Emulator"
|
@echo "Planet Virtual Boy Emulator"
|
||||||
@echo " https://www.planetvb.com/"
|
@echo " https://www.planetvb.com/"
|
||||||
@echo " August 3, 2020"
|
@echo " August 4, 2020"
|
||||||
@echo
|
@echo
|
||||||
@echo "Intended build environment: Debian i386 or amd64"
|
@echo "Intended build environment: Debian i386 or amd64"
|
||||||
@echo " gcc-multilib"
|
@echo " gcc-multilib"
|
||||||
|
@ -20,12 +20,12 @@ default:
|
||||||
@echo "Usage: make <recipe>"
|
@echo "Usage: make <recipe>"
|
||||||
@echo " Package recipes:"
|
@echo " Package recipes:"
|
||||||
@echo " build Compiles the native modules and desktop application"
|
@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 " clean Deletes all output files"
|
||||||
@echo " core Check the native core library for style errors"
|
@echo " core Check the native core library for style errors"
|
||||||
@echo " desktop Compiles the Java desktop application"
|
@echo " desktop Compiles the Java desktop application"
|
||||||
@echo " native Builds all native modules"
|
@echo " native Builds all native modules"
|
||||||
@echo " pack Bundles everything in a .jar file"
|
@echo " pack Bundles everything in a .jar file"
|
||||||
|
@echo " release Produces a .jar and deletes all intermediate files"
|
||||||
@echo " Native recipes:"
|
@echo " Native recipes:"
|
||||||
@echo " lin32 Builds native module linux_x86"
|
@echo " lin32 Builds native module linux_x86"
|
||||||
@echo " lin64 Builds native module linux_x86-64"
|
@echo " lin64 Builds native module linux_x86-64"
|
||||||
|
@ -46,14 +46,6 @@ build:
|
||||||
@make -s desktop
|
@make -s desktop
|
||||||
@make -s native
|
@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
|
# Delete all output files
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean: clean_most
|
clean: clean_most
|
||||||
|
@ -95,6 +87,14 @@ pack:
|
||||||
@jar -cfe $(jarname) Main *.class \
|
@jar -cfe $(jarname) Main *.class \
|
||||||
app images locale native src util vue makefile license.txt
|
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
|
# Delete only Java .class files
|
||||||
.PHONY: clean_desktop
|
.PHONY: clean_desktop
|
||||||
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. */
|
/* This file is included through vue.c and cannot be built directly. */
|
||||||
#ifdef VUEAPI
|
#ifdef VUEAPI
|
||||||
|
|
||||||
/* Read a value directly from host memory */
|
/* Read bytes from host memory */
|
||||||
static int32_t busReadMemory(uint8_t *data, int type) {
|
static void busReadBytes(uint8_t *src, uint8_t *dest, uint32_t address,
|
||||||
|
uint32_t size, uint32_t length) {
|
||||||
|
|
||||||
/* Host memory is little-endian */
|
/* There is no source data */
|
||||||
#ifndef VUE_BIGENDIAN
|
if (src == NULL)
|
||||||
switch (type) {
|
while (length-- > 0)
|
||||||
case VUE_S8 : return *(int8_t *)data;
|
*dest++ = 0;
|
||||||
case VUE_U8 : return *(uint8_t *)data;
|
|
||||||
case VUE_S16: return *(int16_t *)data;
|
/* Copy bytes from the source as a circular buffer */
|
||||||
case VUE_U16: return *(uint16_t *)data;
|
else for (size--; length-- > 0;)
|
||||||
case VUE_S32: return *(int32_t *)data;
|
*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 */
|
/* Host memory is big-endian */
|
||||||
#else
|
#ifdef VUE_BIGENDIAN
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case VUE_S8 : return (int8_t ) data[0];
|
case VUE_S32:
|
||||||
case VUE_U8 : return (uint8_t ) data[0];
|
value = (value >> 16 & 0x0000FFFF) | value << 16;
|
||||||
case VUE_S16: return (int16_t ) data[0] << 8 | data[1];
|
/* Fallthrough */
|
||||||
case VUE_U16: return (uint16_t) data[0] << 8 | data[1];
|
case VUE_S16:
|
||||||
case VUE_S32: return (int32_t )
|
case VUE_U16:
|
||||||
data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
value = (value >> 8 & 0x00FF00FF) | (value << 8 & 0xFF00FF00);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0; /* Unreachable, but the compiler doesn't know that */
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform a read operation */
|
/* Read a value from the CPU bus */
|
||||||
static int32_t busReadValue(VUE *vue, uint32_t address, int type, vbool debug){
|
static int32_t busReadValue(VUE *vue, uint32_t address, int type) {
|
||||||
address &= ~TYPE_SIZES[type] + 1;
|
address &= -TYPE_SIZES[type];
|
||||||
switch (address >> 24 & 7) {
|
switch (address >> 24 & 7) {
|
||||||
case 3: /* Unmapped */
|
case 1: /* Fallthrough */ /* VSU (write-only) */
|
||||||
case 4: return 0; /* Cartridge expansion */
|
case 3: /* Fallthrough */ /* Unmapped */
|
||||||
case 5: return busReadMemory(&vue->wram[address & 8191], type);
|
case 4: /* Cartridge expansion (not supported) */
|
||||||
case 6: return vue->sram == NULL ? 0 :
|
return 0;
|
||||||
busReadMemory(&vue->sram[address & (vue->sram_size - 1)], type);
|
case 5: return /* System WRAM */
|
||||||
case 7: return vue->rom == NULL ? 0 :
|
busReadMemory(vue->wram, address & 0xFFFF , type);
|
||||||
busReadMemory(&vue->rom [address & (vue->rom_size - 1)], 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 */
|
#endif /* VUEAPI */
|
||||||
|
|
|
@ -55,8 +55,9 @@ typedef struct {
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
VUEAPI void vueInitialize(VUE *vue);
|
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 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;
|
vue->sram = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform a read operation */
|
/* Read bytes from the CPU bus */
|
||||||
vbool vueRead(VUE *vue, uint32_t address, uint8_t *data, uint32_t length) {
|
vbool vueRead(VUE *vue, uint32_t address, uint8_t *dest, uint32_t length) {
|
||||||
uint32_t count; /* Bytes to read in one iteration */
|
uint32_t count; /* Bytes to read in one iteration */
|
||||||
|
|
||||||
/* Error checking */
|
/* Error checking */
|
||||||
if (
|
if (vue == NULL || dest == NULL)
|
||||||
vue == NULL ||
|
return VUE_FALSE;
|
||||||
data == NULL ||
|
|
||||||
length > 0x01000000
|
|
||||||
) return VUE_FALSE;
|
|
||||||
|
|
||||||
/* Perform the operation */
|
/* 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 */
|
/* Determine the maximum number of bytes to process at once */
|
||||||
count = 0x01000000 - (address & 0x00FFFFFF);
|
count = 0x01000000 - (address & 0x00FFFFFF);
|
||||||
|
@ -51,7 +48,20 @@ vbool vueRead(VUE *vue, uint32_t address, uint8_t *data, uint32_t length) {
|
||||||
|
|
||||||
/* Process by component */
|
/* Process by component */
|
||||||
switch (address >> 24 & 7) {
|
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;
|
vue->rom_size = size;
|
||||||
return VUE_TRUE;
|
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;
|
return JNI_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform a read access
|
// Read bytes from the CPU bus
|
||||||
JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_read
|
JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_read
|
||||||
(JNIEnv *env, jobject vue, jint address, jbyteArray data, jint offset,
|
(JNIEnv *env, jobject vue, jint address, jbyteArray data, jint offset,
|
||||||
jint length) {
|
jint length) {
|
||||||
|
@ -106,7 +106,6 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_read
|
||||||
data == NULL ||
|
data == NULL ||
|
||||||
offset < 0 ||
|
offset < 0 ||
|
||||||
length < 0 ||
|
length < 0 ||
|
||||||
length < 0 || length > 0x01000000 ||
|
|
||||||
offset + length > (*env)->GetArrayLength(env, data)
|
offset + length > (*env)->GetArrayLength(env, data)
|
||||||
) return JNI_FALSE;
|
) return JNI_FALSE;
|
||||||
|
|
||||||
|
@ -143,3 +142,24 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_setROM
|
||||||
vueSetROM(&core->vue, rom, length);
|
vueSetROM(&core->vue, rom, length);
|
||||||
return JNI_TRUE;
|
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 {
|
class JavaVUE extends VUE {
|
||||||
|
|
||||||
// Instance fields
|
// Instance fields
|
||||||
private byte[] rom; // Cartridge ROM
|
byte[] rom; // Cartridge ROM
|
||||||
private byte[] sram; // Cartridge SRAM
|
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
|
// 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
|
// Default constructor
|
||||||
JavaVUE() {
|
JavaVUE() {
|
||||||
|
bus = new Bus(this);
|
||||||
|
wram = new byte[0x10000];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,19 +53,46 @@ class JavaVUE extends VUE {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform a read operation
|
// Read bytes from the CPU bus
|
||||||
public boolean read(int address, byte[] data, int offset, int length) {
|
public boolean read(int address, byte[] dest, int offset, int length) {
|
||||||
|
int count = 0; // Bytes to read in one iteration
|
||||||
|
|
||||||
// Error checking
|
// Error checking
|
||||||
if (data == null ||
|
if (
|
||||||
|
dest == null ||
|
||||||
offset < 0 ||
|
offset < 0 ||
|
||||||
length < 0 ||
|
length < 0 ||
|
||||||
length < 0 || length > 0x01000000 ||
|
offset + length > dest.length
|
||||||
offset + length > data.length
|
|
||||||
) return false;
|
) return false;
|
||||||
|
|
||||||
// Perform the operation
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,4 +114,39 @@ class JavaVUE extends VUE {
|
||||||
return true;
|
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
|
// Determine whether the context is native-backed
|
||||||
public native boolean isNative();
|
public native boolean isNative();
|
||||||
|
|
||||||
// Perform a read operation
|
// Read bytes from the CPU bus
|
||||||
public native boolean read(int address, byte[] data, int offset,
|
public native boolean read(int address, byte[] dest, int offset,
|
||||||
int length);
|
int length);
|
||||||
|
|
||||||
// Provide new ROM data
|
// Provide new ROM data
|
||||||
public native boolean setROM(byte[] data, int offset, int length);
|
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
|
// Determine whether the context is native-backed
|
||||||
public abstract boolean isNative();
|
public abstract boolean isNative();
|
||||||
|
|
||||||
// Perform a read operation
|
// Read bytes from the CPU bus
|
||||||
public abstract boolean read(int address, byte[] data, int offset,
|
public abstract boolean read(int address, byte[] dest, int offset,
|
||||||
int length);
|
int length);
|
||||||
|
|
||||||
// Provide new ROM data
|
// Provide new ROM data
|
||||||
public abstract boolean setROM(byte[] data, int offset, int length);
|
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