2020-08-03 02:21:59 +00:00
|
|
|
package vue;
|
|
|
|
|
|
|
|
// Java emulation core implementation
|
2020-08-03 18:51:46 +00:00
|
|
|
class JavaVUE extends VUE {
|
2020-08-03 02:21:59 +00:00
|
|
|
|
2020-08-08 23:40:22 +00:00
|
|
|
// Instance fields
|
|
|
|
Instruction inst; // Instruction state
|
|
|
|
|
2020-08-05 02:17:56 +00:00
|
|
|
// Components
|
|
|
|
Bus bus; // Memory bus
|
2020-08-06 01:40:23 +00:00
|
|
|
CPU cpu; // Processor
|
2020-08-04 01:34:02 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Constants //
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// Memory access type sizes
|
2020-08-05 02:17:56 +00:00
|
|
|
static final int[] TYPE_SIZES = { 1, 1, 2, 2, 4 };
|
2020-08-03 02:21:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Constructors //
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// Default constructor
|
|
|
|
JavaVUE() {
|
2020-08-08 23:40:22 +00:00
|
|
|
bus = new Bus(this);
|
|
|
|
cpu = new CPU(this);
|
|
|
|
inst = new Instruction();
|
2020-08-06 21:37:05 +00:00
|
|
|
reset();
|
2020-08-03 02:21:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Public Methods //
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2020-08-03 18:51:46 +00:00
|
|
|
// Release any used resources
|
|
|
|
public void dispose() { }; // No action needed
|
|
|
|
|
2020-08-06 01:40:23 +00:00
|
|
|
// Retrieve a register value
|
|
|
|
public int getRegister(int index, boolean system) {
|
2020-08-07 19:21:03 +00:00
|
|
|
|
|
|
|
// Non-indexed registers
|
|
|
|
if (system) switch (index) {
|
2020-08-08 02:24:09 +00:00
|
|
|
case VUE.JUMP_FROM: return
|
|
|
|
cpu.jumpFrom[cpu.psw_np != 0 ? 2 : cpu.psw_ep];
|
|
|
|
case VUE.JUMP_TO : return
|
|
|
|
cpu.jumpTo [cpu.psw_np != 0 ? 2 : cpu.psw_ep];
|
2020-08-07 19:21:03 +00:00
|
|
|
case VUE.PC : return cpu.pc;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Indexed registers
|
2020-08-06 01:40:23 +00:00
|
|
|
return
|
|
|
|
index < 0 || index > 31 ? 0 :
|
|
|
|
system ? cpu.getSystemRegister(index) :
|
|
|
|
cpu.program[index]
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
2020-08-03 02:21:59 +00:00
|
|
|
// Retrieve a copy of the ROM data
|
|
|
|
public byte[] getROM() {
|
2020-08-06 01:40:23 +00:00
|
|
|
|
|
|
|
// No ROM data
|
|
|
|
if (bus.rom == null)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
// Copy the ROM data
|
|
|
|
var ret = new byte[bus.rom.length];
|
|
|
|
System.arraycopy(bus.rom, 0, ret, 0, ret.length);
|
2020-08-03 02:21:59 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine whether the context is native-backed
|
|
|
|
public boolean isNative() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-08-05 02:17:56 +00:00
|
|
|
// 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
|
2020-08-04 01:34:02 +00:00
|
|
|
|
|
|
|
// Error checking
|
2020-08-05 02:17:56 +00:00
|
|
|
if (
|
|
|
|
dest == null ||
|
2020-08-04 01:34:02 +00:00
|
|
|
offset < 0 ||
|
|
|
|
length < 0 ||
|
2020-08-05 02:17:56 +00:00
|
|
|
offset + length > dest.length
|
2020-08-04 01:34:02 +00:00
|
|
|
) return false;
|
|
|
|
|
|
|
|
// Perform the operation
|
2020-08-05 02:17:56 +00:00
|
|
|
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)
|
2020-08-06 01:40:23 +00:00
|
|
|
bus.readBytes(null , dest, address, 0 , count);
|
2020-08-05 02:17:56 +00:00
|
|
|
break;
|
|
|
|
case 5: /* System WRAM */
|
2020-08-06 01:40:23 +00:00
|
|
|
bus.readBytes(bus.wram, dest, address, offset, count);
|
2020-08-05 02:17:56 +00:00
|
|
|
break;
|
|
|
|
case 6: /* Cartridge RAM */
|
2020-08-06 01:40:23 +00:00
|
|
|
bus.readBytes(bus.sram, dest, address, offset, count);
|
2020-08-05 02:17:56 +00:00
|
|
|
break;
|
|
|
|
case 7: /* Cartridge ROM */
|
2020-08-06 01:40:23 +00:00
|
|
|
bus.readBytes(bus.rom , dest, address, offset, count);
|
2020-08-05 02:17:56 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
2020-08-04 01:34:02 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-08-06 21:37:05 +00:00
|
|
|
// Initialize all system components
|
|
|
|
public void reset() {
|
|
|
|
bus.reset();
|
|
|
|
cpu.reset();
|
|
|
|
}
|
|
|
|
|
2020-08-06 01:40:23 +00:00
|
|
|
// Specify a register value
|
|
|
|
public int setRegister(int index, boolean system, int value) {
|
|
|
|
return
|
|
|
|
index == VUE.PC && system ? cpu.pc = value & 0xFFFFFFFE :
|
|
|
|
index < 0 || index > 31 ? 0 :
|
|
|
|
system ? cpu.setSystemRegister(index, value, true) :
|
2020-08-06 21:37:05 +00:00
|
|
|
index == 0 ? 0 : (cpu.program[index] = value)
|
2020-08-06 01:40:23 +00:00
|
|
|
;
|
|
|
|
}
|
|
|
|
|
2020-08-03 02:21:59 +00:00
|
|
|
// Provide new ROM data
|
|
|
|
public boolean setROM(byte[] data, int offset, int length) {
|
|
|
|
|
|
|
|
// Error checking
|
2020-08-04 01:34:02 +00:00
|
|
|
if (
|
|
|
|
data == null ||
|
|
|
|
offset < 0 ||
|
|
|
|
length < 1024 || length > 0x01000000 ||
|
|
|
|
(length & length - 1) != 0 ||
|
|
|
|
offset + length > data.length
|
|
|
|
) return false;
|
2020-08-03 02:21:59 +00:00
|
|
|
|
|
|
|
// Accept the new ROM data
|
2020-08-06 01:40:23 +00:00
|
|
|
bus.rom = new byte[length];
|
|
|
|
System.arraycopy(data, offset, bus.rom, 0, length);
|
2020-08-03 02:21:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-08-05 02:17:56 +00:00
|
|
|
// 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 */
|
2020-08-06 01:40:23 +00:00
|
|
|
bus.writeBytes(bus.wram, src, address, offset, count);
|
2020-08-05 02:17:56 +00:00
|
|
|
break;
|
|
|
|
case 6: /* Cartridge RAM */
|
2020-08-06 01:40:23 +00:00
|
|
|
bus.writeBytes(bus.sram, src, address, offset, count);
|
2020-08-05 02:17:56 +00:00
|
|
|
break;
|
|
|
|
case 7: /* Cartridge ROM */
|
2020-08-06 01:40:23 +00:00
|
|
|
bus.writeBytes(bus.rom , src, address, offset, count);
|
2020-08-05 02:17:56 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-08-03 02:21:59 +00:00
|
|
|
}
|