diff --git a/src/core/bus.c b/src/core/bus.c deleted file mode 100644 index 7abe224..0000000 --- a/src/core/bus.c +++ /dev/null @@ -1,140 +0,0 @@ -/* This file is included through vue.c and cannot be built directly. */ -#ifdef VUEAPI - -/* Read bytes from host memory */ -static void busReadBytes(uint8_t *src, uint8_t *dest, uint32_t address, - uint32_t size, uint32_t length) { - - /* 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 */ - #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 - - return value; -} - -/* 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 1: /* Fallthrough */ /* VSU (write-only) */ - case 3: /* Fallthrough */ /* Unmapped */ - case 4: /* Cartridge expansion (not supported) */ - return 0; - case 5: /* System WRAM */ - return busReadMemory(vue->bus.wram, address & 0xFFFF, type); - case 6: return busReadMemory(vue->bus.sram, /* Cartridge RAM */ - address & (vue->bus.sramSize - 1), type); - case 7: return busReadMemory(vue->bus.rom , /* Cartridge ROM */ - address & (vue->bus.romSize - 1), type); - } - return 0; /* Unreachable */ -} - -/* Perform a system reset */ -static void busReset(VUE *vue) { - int x; - for (x = 0; x < 0x10000; x++) - vue->bus.wram[x] = 0; -} - -/* 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->bus.wram, address & 0xFFFF, type, value); - break; - case 6: /* Cartridge RAM */ - busWriteMemory(vue->bus.sram, - address & (vue->bus.sramSize - 1), type, value); - break; - case 7: /* Cartridge ROM */ - busWriteMemory(vue->bus.rom , - address & (vue->bus.romSize - 1), type, value); - break; - } -} - -#endif /* VUEAPI */ diff --git a/src/core/cpu.c b/src/core/cpu.c index 04fb393..497da94 100644 --- a/src/core/cpu.c +++ b/src/core/cpu.c @@ -124,7 +124,7 @@ static void cpuDecode(VUE_INST *inst, int32_t bits) { } /* Read a system register */ -static int32_t cpuGetSystemRegister(VUE *vue, int index) { +static int32_t cpuGetSystemRegister(VUE *vue, int32_t index) { switch (index) { case VUE_ADTRE: return vue->cpu.adtre; case VUE_EIPC : return vue->cpu.eipc; @@ -159,7 +159,7 @@ static int32_t cpuGetSystemRegister(VUE *vue, int index) { } /* Write a system register */ -static int32_t cpuSetSystemRegister(VUE *vue, int index, int32_t value, +static int32_t cpuSetSystemRegister(VUE *vue, int32_t index, int32_t value, vbool debug) { switch (index) { case VUE_ADTRE: return vue->cpu.adtre = value & 0xFFFFFFFE; @@ -225,9 +225,9 @@ static int32_t cpuSetSystemRegister(VUE *vue, int index, int32_t value, return 1; /* Unreachable */ } -/* Perform a system reset */ +/* System reset */ static void cpuReset(VUE *vue) { - int x; + int32_t x; /* Configure instance fields */ vue->cpu.cycles = 0; /* Duration of first fetch */ @@ -251,7 +251,7 @@ static void cpuReset(VUE *vue) { } /* Test a condition */ -static int8_t cpuTest(VUE *vue, int condition) { +static int8_t cpuTest(VUE *vue, int32_t condition) { switch (condition) { case 0: return vue->cpu.psw_ov; case 1: return vue->cpu.psw_cy; diff --git a/src/core/gamepak.c b/src/core/gamepak.c new file mode 100644 index 0000000..32a3e6c --- /dev/null +++ b/src/core/gamepak.c @@ -0,0 +1,14 @@ +/* This file is included through vue.c and cannot be built directly. */ +#ifdef VUEAPI + +/***************************************************************************** + * Module Functions * + *****************************************************************************/ + +/* System reset */ +static void pakReset(VUE *vue) { + vue->pak.wcr_exp1w = 0; + vue->pak.wcr_rom1w = 0; +} + +#endif diff --git a/src/core/include/vue.h b/src/core/include/vue.h index fc43eb1..2685c5b 100644 --- a/src/core/include/vue.h +++ b/src/core/include/vue.h @@ -159,19 +159,12 @@ typedef struct { /* Emulation state */ typedef struct { - VUE_INST inst; /* Instruction state */ - - /* Memory bus */ - struct { - uint8_t *rom; /* Cartridge ROM */ - uint32_t romSize; /* Number of bytes in cartridge ROM */ - uint8_t *sram; /* Cartridge RAM */ - uint32_t sramSize; /* Number of bytes in cartridge RAM */ - uint8_t wram[0x10000]; /* System memory */ - } bus; + int32_t breakCode; /* Application break code */ + uint8_t wram[0x10000]; /* System memory */ /* CPU state */ struct { + VUE_INST inst; /* Instruction state */ uint32_t cycles; /* Cycles until next stage */ int32_t jumpFrom[3]; /* Source PCs of most recent jumps */ int32_t jumpTo [3]; /* Destination PCs of most recent jumps */ @@ -222,6 +215,16 @@ typedef struct { uint16_t ecr_fecc; /* Fatal Error Cause Code */ } cpu; + /* Game pak */ + struct { + uint8_t *ram; /* Cartridge SRAM */ + uint32_t ramSize; /* Number of bytes in cartridge SRAM */ + uint8_t *rom; /* Cartridge ROM */ + uint32_t romSize; /* Number of bytes in cartridge ROM */ + int8_t wcr_exp1w; /* Expansion one-wait mode */ + int8_t wcr_rom1w; /* ROM one-wait mode */ + } pak; + } VUE; @@ -230,13 +233,16 @@ typedef struct { * Function Prototypes * *****************************************************************************/ -VUEAPI int32_t vueGetRegister(VUE *vue, int index, vbool system); +VUEAPI int32_t vueEmulate (VUE *vue, int32_t maxCycles); +VUEAPI int32_t vueGetRegister(VUE *vue, int32_t index, vbool system); VUEAPI void vueInitialize (VUE *vue); -VUEAPI vbool vueRead (VUE *vue, uint32_t address, uint8_t *dest, uint32_t length); +VUEAPI int32_t vueRead (VUE *vue, uint32_t address, int32_t type); +VUEAPI vbool vueReadBytes (VUE *vue, uint32_t address, uint8_t *dest, uint32_t length); VUEAPI void vueReset (VUE *vue); -VUEAPI int32_t vueSetRegister(VUE *vue, int index, vbool system, int32_t value); +VUEAPI int32_t vueSetRegister(VUE *vue, int32_t index, vbool system, int32_t value); 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); +VUEAPI void vueWrite (VUE *vue, uint32_t address, int32_t type, int32_t value); +VUEAPI vbool vueWriteBytes (VUE *vue, uint32_t address, uint8_t *src, uint32_t length); diff --git a/src/core/vue.c b/src/core/vue.c index c63365b..a8fa671 100644 --- a/src/core/vue.c +++ b/src/core/vue.c @@ -18,7 +18,7 @@ *****************************************************************************/ /* Memory access type sizes */ -static const int TYPE_SIZES[] = { 1, 1, 2, 2, 4 }; +static const uint32_t TYPE_SIZES[] = { 1, 1, 2, 2, 4 }; @@ -26,8 +26,132 @@ static const int TYPE_SIZES[] = { 1, 1, 2, 2, 4 }; * Component Includes * *****************************************************************************/ -#include "bus.c" #include "cpu.c" +#include "gamepak.c" + + + +/***************************************************************************** + * Module Functions * + *****************************************************************************/ + +/* Read a value from a byte buffer */ +static int32_t readBuffer(uint8_t *data, uint32_t datlen, uint32_t address, + int32_t type) { + uint32_t size = TYPE_SIZES[type]; /* Size of data type */ + int32_t value = 0; + + /* Error checking */ + if (data == NULL) + return 0; + + /* Common processing */ + address &= (~size + 1) & (datlen - 1); + + /* The host is little-endian */ + #ifndef VUE_BIGENDIAN + switch (type) { + case VUE_S8 : value = *( int8_t *)&data[address]; break; + case VUE_U8 : value = *(uint8_t *)&data[address]; break; + case VUE_S16: value = *( int16_t *)&data[address]; break; + case VUE_U16: value = *(uint16_t *)&data[address]; break; + case VUE_S32: value = *( int32_t *)&data[address]; break; + } + + /* The host is big-endian */ + #else + switch (type) { + case VUE_S32: value = + data[address + 3] << 24 | + (data[address + 2] & 0xFF) << 16; + /* Fallthrough */ + case VUE_S16: /* Fallthrough */ + case VUE_U16: value |= + (data[address + 1] & 0xFF) << 8; + /* Fallthrough */ + case VUE_S8 : /* Fallthrough */ + case VUE_U8 : value |= + data[address ] & 0xFF; + } + + /* Sign-extend the value if appropriate */ + if (type & 1) { + size <<= 3; + value = SIGN_EXTEND(size, value); + } + #endif + + return value; +} + +/* Read bytes from a byte buffer */ +static void readBytes(uint8_t *data, uint32_t datlen, uint32_t address, + uint8_t *dest, uint32_t length) { + + /* The source does not exist */ + if (data == NULL) { + while (length--) + *dest++ = 0; + return; + } + + /* Transfer bytes from the source as a circular buffer */ + while (length--) + *dest++ = data[address++ & (datlen - 1)]; +} + +/* Write a value to a byte buffer */ +static void writeBuffer(uint8_t *data, uint32_t datlen, uint32_t address, + int32_t type, int32_t value) { + uint32_t size = TYPE_SIZES[type]; /* Size of data type */ + + /* Error checking */ + if (data == NULL) + return; + + /* Common processing */ + address &= (~size + 1) & (datlen - 1); + + /* The host is little-endian */ + #ifndef VUE_BIGENDIAN + switch (type) { + case VUE_S8 : /* Fallthrough */ + case VUE_U8 : *(int8_t *)&data[address] = (int8_t ) value; break; + case VUE_S16: /* Fallthrough */ + case VUE_U16: *(int16_t *)&data[address] = (int16_t ) value; break; + case VUE_S32: *(int32_t *)&data[address] = (int32_t ) value; break; + } + + /* The host is big-endian */ + #else + switch (type) { + case VUE_S32: + data[address + 3] = (uint8_t) (value >> 24); + data[address + 2] = (uint8_t) (value >> 16); + /* Fallthrough */ + case VUE_S16: /* Fallthrough */ + case VUE_U16: + data[address + 1] = (uint8_t) (value >> 8); + /* Fallthrough */ + case VUE_S8 : /* Fallthrough */ + case VUE_U8 : value |= + data[address ] = (uint8_t) value; + } + #endif +} + +/* Write bytes to a byte buffer */ +static void writeBytes(uint8_t *data, uint32_t datlen, uint32_t address, + uint8_t *src, uint32_t length) { + + /* The destination does not exist */ + if (data == NULL) + return; + + /* Transfer bytes to the destination as a circular buffer */ + while (length--) + data[address++ & (datlen - 1)] = *src++; +} @@ -35,8 +159,47 @@ static const int TYPE_SIZES[] = { 1, 1, 2, 2, 4 }; * Library Functions * *****************************************************************************/ +/* Process the simulation */ +int32_t vueEmulate(VUE *vue, int32_t maxCycles) { + int32_t cycles; /* Number of cycles to process */ + + /* Process up to the given number of cycles */ + do { + + /* Determine the number of cycles during which nothing will happen */ + cycles = maxCycles; + /*cycles = cpuUntil (vue, cycles);*/ + /*cycles = padUntil (vue, cycles);*/ + /*cycles = linkUntil (vue, cycles);*/ + /*cycles = timerUntil(vue, cycles);*/ + /*cycles = vipUntil (vue, cycles);*/ + /*cycles = vsuUntil (vue, cycles);*/ + + /* Process all system components */ + vue->breakCode = 0; + /*gamePad.emulate(cycles);*/ + /*gamePak.emulate(cycles);*/ + /*link .emulate(cycles);*/ + /*timer .emulate(cycles);*/ + /*vip .emulate(cycles);*/ + /*vsu .emulate(cycles);*/ + /*cpu .emulate(cycles);*/ + + /* An application break was requested */ + if (vue->breakCode != 0) + break; + + /* Update the number of cycles remaining */ + if (maxCycles >= 0) + maxCycles -= cycles; + } while (maxCycles != 0); + + /* A break condition has occurred */ + return maxCycles; +} + /* Retrieve the value of a register */ -int32_t vueGetRegister(VUE *vue, int index, vbool system) { +int32_t vueGetRegister(VUE *vue, int32_t index, vbool system) { /* Error checking */ if (vue == NULL) @@ -63,12 +226,22 @@ int32_t vueGetRegister(VUE *vue, int index, vbool system) { void vueInitialize(VUE *vue) { if (vue == NULL) return; - vue->bus.rom = NULL; - vue->bus.sram = NULL; + vue->pak.ram = NULL; + vue->pak.rom = NULL; +} + +/* Read a value from the CPU bus */ +int32_t vueRead(VUE *vue, uint32_t address, int32_t type) { + switch (address >> 24 & 7) { + case 5: return readBuffer(vue->wram , 0x10000,address,type); + case 6: return readBuffer(vue->pak.ram,vue->pak.ramSize,address,type); + case 7: return readBuffer(vue->pak.rom,vue->pak.romSize,address,type); + } + return 0; } /* Read bytes from the CPU bus */ -vbool vueRead(VUE *vue, uint32_t address, uint8_t *dest, uint32_t length) { +vbool vueReadBytes(VUE *vue, uint32_t address, uint8_t *dest, uint32_t length){ uint32_t count; /* Bytes to read in one iteration */ /* Error checking */ @@ -76,45 +249,46 @@ vbool vueRead(VUE *vue, uint32_t address, uint8_t *dest, uint32_t length) { return VUE_FALSE; /* Perform the operation */ - for (; length > 0; address += count, length -= count, dest += count) { - - /* Determine the maximum number of bytes to process at once */ + while (length > 0) { count = 0x01000000 - (address & 0x00FFFFFF); - if (count > length) + if (length < count) count = length; - - /* Process by component */ switch (address >> 24 & 7) { - 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: busReadBytes(vue->bus.wram, dest, /* System WRAM */ - address, 0x10000 , count); - break; - case 6: busReadBytes(vue->bus.sram, dest, /* Cartridge RAM */ - address, vue->bus.sramSize, count); - break; - case 7: busReadBytes(vue->bus.rom , dest, /* Cartridge ROM */ - address, vue->bus.romSize , count); - break; + case 5: readBytes(vue->wram , 0x10000, + address, dest, count); break; + case 6: readBytes(vue->pak.ram, vue->pak.ramSize, + address, dest, count); break; + case 7: readBytes(vue->pak.rom, vue->pak.romSize, + address, dest, count); break; + default: + for (address += count, length -= count; count--;) + *dest++ = 0; + continue; } - - }; + address += count; + length -= count; + dest += count; + } return VUE_TRUE; } /* Initialize all system components */ void vueReset(VUE *vue) { + uint32_t x; /* Iterator */ + + /* Error checking */ if (vue == NULL) return; - busReset(vue); + + /* Reset state */ cpuReset(vue); + pakReset(vue); + for (x = 0; x < 0x1000; x++) + vue->wram[x] = 0; } /* Specify a value for a register */ -int32_t vueSetRegister(VUE *vue, int index, vbool system, int32_t value) { +int32_t vueSetRegister(VUE *vue, int32_t index, vbool system, int32_t value) { return vue == NULL ? 0 : index == VUE_PC && system ? vue->cpu.pc = value & 0xFFFFFFFE : index < 0 || index > 31 ? 0 : @@ -135,13 +309,25 @@ vbool vueSetROM(VUE *vue, uint8_t *rom, uint32_t size) { ) return VUE_FALSE; /* Accept the new ROM buffer */ - vue->bus.rom = rom; - vue->bus.romSize = size; + vue->pak.rom = rom; + vue->pak.romSize = size; return VUE_TRUE; } +/* Write a value to the CPU bus */ +void vueWrite(VUE *vue, uint32_t address, int32_t type, int32_t value) { + switch (address >> 24 & 7) { + case 5: writeBuffer(vue->wram , 0x1000, + address, type, value); break; + case 6: writeBuffer(vue->pak.ram, vue->pak.ramSize, + address, type, value); break; + case 7: writeBuffer(vue->pak.rom, vue->pak.romSize, + address, type, value); break; + } +} + /* Write bytes to the CPU bus */ -vbool vueWrite(VUE *vue, uint32_t address, uint8_t *src, uint32_t length) { +vbool vueWriteBytes(VUE *vue, uint32_t address, uint8_t *src, uint32_t length){ uint32_t count; /* Bytes to write in one iteration */ /* Error checking */ @@ -149,26 +335,21 @@ vbool vueWrite(VUE *vue, uint32_t address, uint8_t *src, uint32_t length) { 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 */ + while (length > 0) { count = 0x01000000 - (address & 0x00FFFFFF); - if (count > length) + if (length < count) count = length; - - /* Process by component */ switch (address >> 24 & 7) { - case 5: /* System WRAM */ - busWriteBytes(vue->bus.wram, src, address, 0x10000, count); - break; - case 6: busWriteBytes(vue->bus.sram, src, /* Cartridge RAM */ - address, vue->bus.sramSize, count); - break; - case 7: busWriteBytes(vue->bus.rom , src, /* Cartridge ROM */ - address, vue->bus.romSize , count); - break; + case 5: writeBytes(vue->wram , 0x10000, + address, src, count); break; + case 6: writeBytes(vue->pak.ram, vue->pak.ramSize, + address, src, count); break; + case 7: writeBytes(vue->pak.rom, vue->pak.ramSize, + address, src, count); break; } - - }; + address += count; + length -= count; + src += count; + } return VUE_TRUE; } diff --git a/src/desktop/app/DisassemblerPane.java b/src/desktop/app/DisassemblerPane.java index 4669bf1..1159ed1 100644 --- a/src/desktop/app/DisassemblerPane.java +++ b/src/desktop/app/DisassemblerPane.java @@ -144,7 +144,7 @@ class DisassemblerPane extends JScrollPane { int offset = 0; // Disassemble from the current address - vue.read(address, data, 0, data.length); + vue.readBytes(address, data, 0, data.length); widths[3] = widths[4] = 0; for (int y = 0; y < count; y++) { var row = y < rows.size() ? rows.get(y) : addRow(); @@ -248,7 +248,7 @@ class DisassemblerPane extends JScrollPane { target &= 0xFFFFFFFE; // Load enough bytes to represent every fully visible instruction - vue.read(address, data, 0, data.length); + vue.readBytes(address, data, 0, data.length); // Iterate through instructions for (int x = 0, address = this.address; x < count; x++) { @@ -283,7 +283,7 @@ class DisassemblerPane extends JScrollPane { // Load bytes starting up to 8 instructions prior to the target address = target - 32; - vue.read(address, data, 0, data.length); + vue.readBytes(address, data, 0, data.length); // Iterate through instructions for (boolean found = false;;) { @@ -310,7 +310,7 @@ class DisassemblerPane extends JScrollPane { // Load bytes starting up to 8 instructions prior to the top row address = target - data.length + 4; - vue.read(address, data, 0, data.length); + vue.readBytes(address, data, 0, data.length); // Iterate through instructions var addresses = new int[row]; // Circular buffer diff --git a/src/desktop/app/MainWindow.java b/src/desktop/app/MainWindow.java index 1bc143d..b7a9452 100644 --- a/src/desktop/app/MainWindow.java +++ b/src/desktop/app/MainWindow.java @@ -65,7 +65,8 @@ class MainWindow extends JFrame { this.app = app; pwd = Util.PWD; vue = VUE.create(app.getUseNative()); - System.out.println("Native: " + (vue.isNative() ? "Yes" : "No")); + System.out.println("Native: " + + (vue.isNative() ? VUE.getNativeID() : "No")); // Configure video pane video = new JPanel(null) { diff --git a/src/desktop/app/MemoryWindow.java b/src/desktop/app/MemoryWindow.java index f32e3b4..298fad6 100644 --- a/src/desktop/app/MemoryWindow.java +++ b/src/desktop/app/MemoryWindow.java @@ -87,7 +87,7 @@ class MemoryWindow extends ChildWindow { var data = new byte[count * 16]; // Retrieve all visible bytes from the emulation context - parent.vue.read(address, data, 0, data.length); + parent.vue.readBytes(address, data, 0, data.length); // Update visible rows for (int x = 0; x < count; x++) { diff --git a/src/desktop/vue/Bus.java b/src/desktop/vue/Bus.java deleted file mode 100644 index 5033eb5..0000000 --- a/src/desktop/vue/Bus.java +++ /dev/null @@ -1,147 +0,0 @@ -package vue; - -// Java imports -import java.util.*; - -// Simulation of the CPU bus -class Bus { - - // Private fields - private JavaVUE vue; // Emulation state - - // Package fields - byte[] rom; // Cartridge ROM - byte[] sram; // Cartridge SRAM - byte[] wram; // System WRAM - - - - /////////////////////////////////////////////////////////////////////////// - // Constructors // - /////////////////////////////////////////////////////////////////////////// - - // Default constructor - Bus(JavaVUE vue) { - this.vue = vue; - wram = new byte[0x10000]; - } - - // 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 address, int type) { - - // There is no source data - if (data == null) - return 0; - - // Processing by type - address &= data.length - 1; - switch (type) { - case VUE.S8 : return data[address]; - case VUE.U8 : return data[address] & 0xFF; - case VUE.S16: return - data[address+1] << 8 | data[address ] & 0xFF; - case VUE.U16: return - (data[address+1] & 0xFF)<< 8 | data[address ] & 0xFF; - case VUE.S32: return - data[address+3] <<24 | (data[address+2] & 0xFF)<<16 | - (data[address+1] & 0xFF)<< 8 | (data[address ] & 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(wram, address & 0xFFFF , type); - case 6: return - readMemory(sram, address & sram.length - 1, type); - case 7: return - readMemory(rom , address & rom .length - 1, type); - } - return 0; // Unreachable - } - - // Perform a system reset - public void reset() { - Arrays.fill(wram, 0, 0x10000, (byte) 0); - } - - // 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 address, int type, int value) { - - // There is no source data - if (data == null) - return; - - // Processing by type - address &= data.length - 1; - switch (type) { - case VUE.S32: - data[address + 3] = (byte) (value >> 24); - data[address + 2] = (byte) (value >> 16); - // Fallthrough - case VUE.S16: // Fallthrough - case VUE.U16: - data[address + 1] = (byte) (value >> 8); - // Fallthrough - case VUE.S8 : // Fallthrough - case VUE.U8 : - data[address ] = (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(wram, address, type, value); break; - case 6: writeMemory(sram, address, type, value); break; - case 7: writeMemory(rom , address, type, value); break; - } - } - -} diff --git a/src/desktop/vue/CPU.java b/src/desktop/vue/CPU.java index 9786b7f..0eee643 100644 --- a/src/desktop/vue/CPU.java +++ b/src/desktop/vue/CPU.java @@ -10,11 +10,12 @@ class CPU { private JavaVUE vue; // Emulation state // Package fields - int cycles; // Cycles until next stage - int fetch; // Fetch unit index - int[] jumpFrom; // Source PCs of most recent jumps - int[] jumpTo; // Destination PCs of most recent jumps - int stage; // Current processing stage + int cycles; // Cycles until next stage + int fetch; // Fetch unit index + Instruction inst; // Instruction state + int[] jumpFrom; // Source PCs of most recent jumps + int[] jumpTo; // Destination PCs of most recent jumps + int stage; // Current processing stage // Program registers int[] program; diff --git a/src/desktop/vue/GamePak.java b/src/desktop/vue/GamePak.java new file mode 100644 index 0000000..ad2348d --- /dev/null +++ b/src/desktop/vue/GamePak.java @@ -0,0 +1,38 @@ +package vue; + +// Simulation of the Game Pak +class GamePak { + + // Package fields + byte[] ram; // Cartridge SRAM + byte[] rom; // Cartridge ROM + int wcr_exp1w; // Expansion one-wait mode + int wcr_rom1w; // ROM one-wait mode + + // Private fields + private JavaVUE vue; // Emulation state + + + + /////////////////////////////////////////////////////////////////////////// + // Constructors // + /////////////////////////////////////////////////////////////////////////// + + // Default constructor + GamePak(JavaVUE vue) { + this.vue = vue; + } + + + + /////////////////////////////////////////////////////////////////////////// + // Package Methods // + /////////////////////////////////////////////////////////////////////////// + + // System reset + void reset() { + wcr_exp1w = 0; + wcr_rom1w = 0; + } + +} diff --git a/src/desktop/vue/JavaVUE.java b/src/desktop/vue/JavaVUE.java index a28b21e..c61d0b2 100644 --- a/src/desktop/vue/JavaVUE.java +++ b/src/desktop/vue/JavaVUE.java @@ -1,14 +1,18 @@ package vue; +// Java imports +import java.util.*; + // Java emulation core implementation class JavaVUE extends VUE { - // Instance fields - Instruction inst; // Instruction state + // State fields + int breakCode; // Application break code + byte[] wram; // System WRAM - // Components - Bus bus; // Memory bus - CPU cpu; // Processor + // Package fields + CPU cpu; // Processor + GamePak pak; // Game pak @@ -27,9 +31,9 @@ class JavaVUE extends VUE { // Default constructor JavaVUE() { - bus = new Bus(this); - cpu = new CPU(this); - inst = new Instruction(); + cpu = new CPU (this); + pak = new GamePak(this); + wram = new byte[0x10000]; reset(); } @@ -42,6 +46,43 @@ class JavaVUE extends VUE { // Release any used resources public void dispose() { }; // No action needed + // Process the simulation + public int emulate(int maxCycles) { + + // Process up to the given number of cycles + do { + + // Determine the number of cycles during which nothing will happen + int cycles = maxCycles; + //cycles = cpu .until(cycles); + //cycles = pad .until(cycles); + //cycles = link .until(cycles); + //cycles = timer.until(cycles); + //cycles = vip .until(cycles); + //cycles = vsu .until(cycles); + + // Process all system components + breakCode = 0; + //pad .emulate(cycles); + //link .emulate(cycles); + //timer.emulate(cycles); + //vip .emulate(cycles); + //vsu .emulate(cycles); + //cpu .emulate(cycles); + + // An application break was requested + if (breakCode != 0) + break; + + // Update the number of cycles remaining + if (maxCycles >= 0) + maxCycles -= cycles; + } while (maxCycles != 0); + + // A break condition has occurred + return maxCycles; + } + // Retrieve a register value public int getRegister(int index, boolean system) { @@ -66,12 +107,12 @@ class JavaVUE extends VUE { public byte[] getROM() { // No ROM data - if (bus.rom == null) + if (pak.rom == null) return null; // Copy the ROM data - var ret = new byte[bus.rom.length]; - System.arraycopy(bus.rom, 0, ret, 0, ret.length); + var ret = new byte[pak.rom.length]; + System.arraycopy(pak.rom, 0, ret, 0, ret.length); return ret; } @@ -80,9 +121,18 @@ class JavaVUE extends VUE { return false; } + // Read a value from the CPU bus + public int read(int address, int type) { + switch (address >> 24 & 7) { + case 5: return readBuffer(wram , address, type); + case 6: return readBuffer(pak.ram, address, type); + case 7: return readBuffer(pak.rom, address, type); + } + return 0; + } + // 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 + public boolean readBytes(int address, byte[] dest, int offset, int length){ // Error checking if ( @@ -93,40 +143,26 @@ class JavaVUE extends VUE { ) 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 + while (length > 0) { + int count = Math.min(length, 0x01000000 - (address & 0x00FFFFFF)); 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(bus.wram, dest, address, offset, count); - break; - case 6: /* Cartridge RAM */ - bus.readBytes(bus.sram, dest, address, offset, count); - break; - case 7: /* Cartridge ROM */ - bus.readBytes(bus.rom , dest, address, offset, count); - break; + case 5: readBytes(wram ,address,dest,offset,count); break; + case 6: readBytes(pak.ram,address,dest,offset,count); break; + case 7: readBytes(pak.rom,address,dest,offset,count); break; + default: Arrays.fill(dest, offset, offset + count, (byte) 0); } - - }; + address += count; + length -= count; + offset += count; + } return true; } // Initialize all system components public void reset() { - bus.reset(); cpu.reset(); + pak.reset(); + Arrays.fill(wram, 0, 0x10000, (byte) 0); } // Specify a register value @@ -152,14 +188,22 @@ class JavaVUE extends VUE { ) return false; // Accept the new ROM data - bus.rom = new byte[length]; - System.arraycopy(data, offset, bus.rom, 0, length); + pak.rom = new byte[length]; + System.arraycopy(data, offset, pak.rom, 0, length); return true; } + // Write a value to the CPU bus + public void write(int address, int type, int value) { + switch (address >> 24 & 7) { + case 5: writeBuffer(wram , address, type, value); break; + case 6: writeBuffer(pak.ram, address, type, value); break; + case 7: writeBuffer(pak.rom, address, type, value); break; + } + } + // 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 + public boolean writeBytes(int address, byte[] src, int offset, int length){ // Error checking if ( @@ -170,26 +214,126 @@ class JavaVUE extends VUE { ) 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 + while (length > 0) { + int count = Math.min(length, 0x01000000 - (address & 0x00FFFFFF)); switch (address >> 24 & 7) { - case 5: /* System WRAM */ - bus.writeBytes(bus.wram, src, address, offset, count); - break; - case 6: /* Cartridge RAM */ - bus.writeBytes(bus.sram, src, address, offset, count); - break; - case 7: /* Cartridge ROM */ - bus.writeBytes(bus.rom , src, address, offset, count); - break; + case 5: writeBytes(wram ,address,src,offset,count); break; + case 6: writeBytes(pak.ram,address,src,offset,count); break; + case 7: writeBytes(pak.rom,address,src,offset,count); break; } - - }; + address += count; + length -= count; + offset += count; + } return true; } + + + /////////////////////////////////////////////////////////////////////////// + // Package Methods // + /////////////////////////////////////////////////////////////////////////// + + // Read a value from a byte buffer + static int readBuffer(byte[] data, int address, int type) { + + // Error checking + if (data == null) + return 0; + + // Processing by data type + int size = TYPE_SIZES[type]; + int value = 0; + address &= ~size + 1 & data.length - 1; + switch (type) { + case VUE.S32: value = + data[address + 3] << 24 | + (data[address + 2] & 0xFF) << 16; + // Fallthrough + case VUE.S16: // Fallthrough + case VUE.U16: value |= + (data[address + 1] & 0xFF) << 8; + // Fallthrough + case VUE.S8 : // Fallthrough + case VUE.U8 : value |= + data[address ] & 0xFF; + } + + // Sign-extend the value if appropriate + if ((type & 1) == 1) { + size = 32 - (size << 3); + value = value << size >> size; + } + + return value; + } + + // Read bytes from a byte buffer + static void readBytes(byte[] data, int address, byte[] dest, int offset, + int length) { + + // The source does not exist + if (data == null) { + Arrays.fill(dest, offset, offset + length, (byte) 0); + return; + } + + // Transfer bytes from the source as a circular buffer + while (length > 0) { + address &= data.length - 1; + int count = Math.min(length, data.length - address); + System.arraycopy(data, address, dest, offset, count); + address += count; + length -= count; + offset += count; + } + + } + + // Write a value to a byte buffer + static void writeBuffer(byte[] data, int address, int type, int value) { + + // Error checking + if (data == null) + return; + + // Processing by data type + int size = TYPE_SIZES[type]; + address &= ~size + 1 & data.length - 1; + switch (type) { + case VUE.S32: + data[address + 3] = (byte) (value >> 24); + data[address + 2] = (byte) (value >> 16); + // Fallthrough + case VUE.S16: // Fallthrough + case VUE.U16: + data[address + 1] = (byte) (value >> 8); + // Fallthrough + case VUE.S8 : // Fallthrough + case VUE.U8 : value |= + data[address ] = (byte) value; + } + + } + + // Write bytes to a byte buffer + static void writeBytes(byte[] data, int address, byte[] src, int offset, + int length) { + + // The destination does not exist + if (data == null) + return; + + // Transfer bytes to the destination as a circular buffer + while (length > 0) { + address &= data.length - 1; + int count = Math.min(length, data.length - address); + System.arraycopy(src, offset, data, address, count); + address += count; + length -= count; + offset += count; + } + + } + } diff --git a/src/desktop/vue/NativeVUE.c b/src/desktop/vue/NativeVUE.c index 6f67948..fd0a432 100644 --- a/src/desktop/vue/NativeVUE.c +++ b/src/desktop/vue/NativeVUE.c @@ -75,13 +75,20 @@ JNIEXPORT void JNICALL Java_vue_NativeVUE_construct JNIEXPORT void JNICALL Java_vue_NativeVUE_dispose (JNIEnv *env, jobject vue) { CORE *core = GetCore(env, vue); - if (core->vue.bus.rom != NULL) - free(core->vue.bus.rom); - if (core->vue.bus.sram != NULL) - free(core->vue.bus.sram); + 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, jint maxCycles) { + CORE *core = GetCore(env, vue); + return vueEmulate(&core->vue, maxCycles); +} + // Retrieve a register value JNIEXPORT jint JNICALL Java_vue_NativeVUE_getRegister (JNIEnv *env, jobject vue, jint index, jboolean system) { @@ -95,13 +102,13 @@ JNIEXPORT jbyteArray JNICALL Java_vue_NativeVUE_getROM CORE *core = GetCore(env, vue); // No ROM data - if (core->vue.bus.rom == NULL) + if (core->vue.pak.rom == NULL) return NULL; // Copy the ROM data - jbyteArray ret = (*env)->NewByteArray(env, (jint)core->vue.bus.romSize); + jbyteArray ret = (*env)->NewByteArray(env, (jint)core->vue.pak.romSize); jbyte *elems = (*env)->GetByteArrayElements(env, ret, NULL); - memcpy(elems, core->vue.bus.rom, core->vue.bus.romSize); + memcpy(elems, core->vue.pak.rom, core->vue.pak.romSize); (*env)->ReleaseByteArrayElements(env, ret, elems, 0); return ret; } @@ -112,8 +119,15 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_isNative return JNI_TRUE; } +// Read a value from the CPU bus +JNIEXPORT jint JNICALL Java_vue_NativeVUE_read + (JNIEnv *env, jobject vue, jint address, jint type) { + CORE *core = GetCore(env, vue); + return vueRead(&core->vue, address, type); +} + // Read bytes from the CPU bus -JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_read +JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_readBytes (JNIEnv *env, jobject vue, jint address, jbyteArray data, jint offset, jint length) { @@ -128,7 +142,7 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_read // Perform the operation CORE *core = GetCore(env, vue); jbyte *elems = (*env)->GetByteArrayElements(env, data, NULL); - vueRead(&core->vue, address, &elems[offset], length); + vueReadBytes(&core->vue, address, &elems[offset], length); (*env)->ReleaseByteArrayElements(env, data, elems, 0); return JNI_TRUE; } @@ -161,21 +175,28 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_setROM ) return JNI_FALSE; // Accept the new ROM data - uint8_t *rom = calloc(length, 1); + 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 = GetCore(env, vue); - if (core->vue.bus.rom != NULL) - free(core->vue.bus.rom); + if (core->vue.pak.rom != NULL) + free(core->vue.pak.rom); vueSetROM(&core->vue, rom, length); return JNI_TRUE; } -/* Write bytes to the CPU bus */ -JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_write +// Write a value to the CPU bus +JNIEXPORT void JNICALL Java_vue_NativeVUE_write + (JNIEnv *env, jobject vue, jint address, jint type, jint value) { + CORE *core = GetCore(env, vue); + vueWrite(&core->vue, address, type, value); +} + +// Write bytes to the CPU bus +JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_writeBytes (JNIEnv *env, jobject vue, jint address, jbyteArray data, jint offset, jint length) { @@ -190,7 +211,7 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVUE_write // Perform the operation CORE *core = GetCore(env, vue); jbyte *elems = (*env)->GetByteArrayElements(env, data, NULL); - vueWrite(&core->vue, address, &elems[offset], length); + vueWriteBytes(&core->vue, address, &elems[offset], length); (*env)->ReleaseByteArrayElements(env, data, elems, 0); return JNI_TRUE; } diff --git a/src/desktop/vue/NativeVUE.java b/src/desktop/vue/NativeVUE.java index 3bfe2a8..4dd0c23 100644 --- a/src/desktop/vue/NativeVUE.java +++ b/src/desktop/vue/NativeVUE.java @@ -26,6 +26,9 @@ class NativeVUE extends VUE { // Release any used resources public native void dispose(); + // Process the simulation + public native int emulate(int maxCycles); + // Retrieve a register value public native int getRegister(int index, boolean system); @@ -35,8 +38,11 @@ class NativeVUE extends VUE { // Determine whether the context is native-backed public native boolean isNative(); + // Read a value from the CPU bus + public native int read(int address, int type); + // Read bytes from the CPU bus - public native boolean read(int address, byte[] dest, int offset, + public native boolean readBytes(int address, byte[] dest, int offset, int length); // Initialize all system components @@ -48,8 +54,11 @@ class NativeVUE extends VUE { // Provide new ROM data public native boolean setROM(byte[] data, int offset, int length); + // Write a value to the CPU bus + public native void write(int address, int type, int value); + // Write bytes to the CPU bus - public native boolean write(int address, byte[] src, int offset, + public native boolean writeBytes(int address, byte[] src, int offset, int length); diff --git a/src/desktop/vue/VUE.java b/src/desktop/vue/VUE.java index c35c957..d6beae3 100644 --- a/src/desktop/vue/VUE.java +++ b/src/desktop/vue/VUE.java @@ -158,6 +158,9 @@ public abstract class VUE { // Release any used resources public abstract void dispose(); + // Process the simulation + public abstract int emulate(int maxCycles); + // Retrieve a register value public abstract int getRegister(int index, boolean system); @@ -167,8 +170,11 @@ public abstract class VUE { // Determine whether the context is native-backed public abstract boolean isNative(); + // Read a value from the CPU bus + public abstract int read(int address, int type); + // Read bytes from the CPU bus - public abstract boolean read(int address, byte[] dest, int offset, + public abstract boolean readBytes(int address, byte[] dest, int offset, int length); // Initialize all system components @@ -180,8 +186,11 @@ public abstract class VUE { // Provide new ROM data public abstract boolean setROM(byte[] data, int offset, int length); + // Write a value to the CPU bus + public abstract void write(int address, int type, int value); + // Write bytes to the CPU bus - public abstract boolean write(int address, byte[] src, int offset, + public abstract boolean writeBytes(int address, byte[] src, int offset, int length); }