Finalizing breakpoint architecture, correcting CPU conditions, tweaking top-level emulation logic
This commit is contained in:
parent
826e921dac
commit
e13c56e1e7
8
makefile
8
makefile
|
@ -1,6 +1,6 @@
|
||||||
# Java include directory pathnames
|
# Java include directory pathnames
|
||||||
# The Windows files need to be copied from a Windows JDK installation
|
# The Windows files need to be copied from a Windows JDK installation
|
||||||
include_linux = /usr/lib/jvm/java-14-openjdk-`\
|
include_linux = /usr/lib/jvm/java-15-openjdk-`\
|
||||||
uname -r | sed 's/.*-//'`/include
|
uname -r | sed 's/.*-//'`/include
|
||||||
include_windows = jni-windows-include
|
include_windows = jni-windows-include
|
||||||
|
|
||||||
|
@ -10,12 +10,12 @@ default:
|
||||||
@echo $(include_linux)
|
@echo $(include_linux)
|
||||||
@echo "Planet Virtual Boy Emulator"
|
@echo "Planet Virtual Boy Emulator"
|
||||||
@echo " https://www.planetvb.com/"
|
@echo " https://www.planetvb.com/"
|
||||||
@echo " October 16, 2020"
|
@echo " December 17, 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"
|
||||||
@echo " mingw-w64"
|
@echo " mingw-w64"
|
||||||
@echo " openjdk-14-jdk"
|
@echo " openjdk-15-jdk"
|
||||||
@echo
|
@echo
|
||||||
@echo "Usage: make <recipe>"
|
@echo "Usage: make <recipe>"
|
||||||
@echo " Package recipes:"
|
@echo " Package recipes:"
|
||||||
|
@ -69,7 +69,7 @@ core:
|
||||||
desktop: clean_desktop
|
desktop: clean_desktop
|
||||||
@echo " Compiling Java desktop application"
|
@echo " Compiling Java desktop application"
|
||||||
@javac -sourcepath src/desktop --release 10 -Xlint:unchecked \
|
@javac -sourcepath src/desktop --release 10 -Xlint:unchecked \
|
||||||
-h src/desktop/vue -d . src/desktop/Main.java
|
-Xlint:deprecation -h src/desktop/vue -d . src/desktop/Main.java
|
||||||
|
|
||||||
# Build all native modules
|
# Build all native modules
|
||||||
.PHONY: native
|
.PHONY: native
|
||||||
|
|
|
@ -436,7 +436,7 @@ static int8_t cpuTestCondition(Vue *vue, int32_t condition) {
|
||||||
case 3: return vue->cpu.psw_cy | vue->cpu.psw_z;
|
case 3: return vue->cpu.psw_cy | vue->cpu.psw_z;
|
||||||
case 4: return vue->cpu.psw_s;
|
case 4: return vue->cpu.psw_s;
|
||||||
case 5: return 1;
|
case 5: return 1;
|
||||||
case 6: return vue->cpu.psw_ov | vue->cpu.psw_s;
|
case 6: return vue->cpu.psw_ov ^ vue->cpu.psw_s;
|
||||||
case 7: return (vue->cpu.psw_ov ^ vue->cpu.psw_s) | vue->cpu.psw_z;
|
case 7: return (vue->cpu.psw_ov ^ vue->cpu.psw_s) | vue->cpu.psw_z;
|
||||||
}
|
}
|
||||||
return cpuTestCondition(vue, condition & 7) ^ 1;
|
return cpuTestCondition(vue, condition & 7) ^ 1;
|
||||||
|
@ -1174,8 +1174,8 @@ static vbool cpuException(Vue *vue) {
|
||||||
/* Process the simulation */
|
/* Process the simulation */
|
||||||
static void cpuEmulate(Vue *vue, int32_t cycles) {
|
static void cpuEmulate(Vue *vue, int32_t cycles) {
|
||||||
|
|
||||||
/* The CPU is in permanent halt */
|
/* The CPU is halting */
|
||||||
if (vue->cpu.stage == CPU_FATAL)
|
if (vue->cpu.stage == CPU_FATAL || vue->cpu.stage == CPU_HALT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
vue->cpu.cycles = 0; /* DEBUG: Stop processing after execute */
|
vue->cpu.cycles = 0; /* DEBUG: Stop processing after execute */
|
||||||
|
@ -1190,6 +1190,7 @@ vue->cpu.cycles = 0; /* DEBUG: Stop processing after execute */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Processing by stage */
|
/* Processing by stage */
|
||||||
|
vue->cpu.cycles = 0;
|
||||||
switch (vue->cpu.stage) {
|
switch (vue->cpu.stage) {
|
||||||
case CPU_EXCEPTION: if (cpuException (vue)) return; break;
|
case CPU_EXCEPTION: if (cpuException (vue)) return; break;
|
||||||
case CPU_EXECUTE : if (cpuExecute (vue)) return; break;
|
case CPU_EXECUTE : if (cpuExecute (vue)) return; break;
|
||||||
|
|
|
@ -49,31 +49,41 @@ public class Main {
|
||||||
useNative = true;
|
useNative = true;
|
||||||
|
|
||||||
// Begin application operations
|
// Begin application operations
|
||||||
new App(useNative);
|
//new App(useNative);
|
||||||
|
|
||||||
/*
|
|
||||||
var brk = new Breakpoint(null);
|
var brk = new Breakpoint(null);
|
||||||
|
|
||||||
String exp =
|
/*
|
||||||
"([sp - 8] & 3) << 6 != 12.0 + r6 * ecr && [0x0500008C + r8] == 0";
|
//String exp =
|
||||||
|
// "([sp - 8] & 3) << 6 != 12.0 + r6 * ecr && [0x0500008C + r8] == 0";
|
||||||
|
//String exp = "float true + -3 * 4";
|
||||||
|
String exp = "1100 ^ uword 1010";
|
||||||
System.out.println("\n" + exp);
|
System.out.println("\n" + exp);
|
||||||
if (brk.setCondition(exp))
|
if (brk.setCondition(exp))
|
||||||
System.out.println(brk.debug());
|
System.out.println(brk.debugTokens());
|
||||||
else System.out.println(
|
else {
|
||||||
brk.getErrorCode (Breakpoint.CONDITION) + "\t" +
|
var err = brk.getConditionError();
|
||||||
brk.getErrorPosition(Breakpoint.CONDITION) + ":" +
|
System.out.println("Error " +
|
||||||
brk.getErrorText (Breakpoint.CONDITION)
|
err.code + "\t" +
|
||||||
);
|
err.position + ":" +
|
||||||
|
err.text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
exp = "123, 456 - 987 , f0-fffffff2";
|
exp = "123, 456 - 987 , f0-fffffff2";
|
||||||
System.out.println("\n" + exp);
|
System.out.println("\n" + exp);
|
||||||
if (brk.setAddresses(exp))
|
if (brk.setAddresses(exp))
|
||||||
System.out.println(brk.test());
|
System.out.println(brk.debugRanges());
|
||||||
else System.out.println(
|
else {
|
||||||
brk.getErrorCode (Breakpoint.ADDRESS) + "\t" +
|
var err = brk.getAddressError();
|
||||||
brk.getErrorPosition(Breakpoint.ADDRESS) + ":" +
|
System.out.println("Error " +
|
||||||
brk.getErrorText (Breakpoint.ADDRESS)
|
err.code + "\t" +
|
||||||
);
|
err.position + ":" +
|
||||||
|
err.text
|
||||||
|
);
|
||||||
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,636 +1,4 @@
|
||||||
// This file is included through NativeVUE.c and cannot be built directly. */
|
// This file is included through NativeVUE.c and cannot be built directly. */
|
||||||
#ifdef NATIVEVUE
|
#ifdef NATIVEVUE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Token types
|
|
||||||
#define BINARY 4
|
|
||||||
#define FLOAT 1
|
|
||||||
#define UNARY 3
|
|
||||||
#define SYMBOL 2
|
|
||||||
#define WORD 0
|
|
||||||
|
|
||||||
// CPU stages
|
|
||||||
#define EXCEPTION 2
|
|
||||||
#define EXECUTE 1
|
|
||||||
|
|
||||||
// Operator IDs
|
|
||||||
#define ADD 2
|
|
||||||
#define BITWISE_AND 3
|
|
||||||
#define BITWISE_NOT 4
|
|
||||||
#define BITWISE_OR 5
|
|
||||||
#define BITWISE_XOR 6
|
|
||||||
#define CEIL 7
|
|
||||||
#define DIVIDE 8
|
|
||||||
#define EQUAL 9
|
|
||||||
#define FLOOR 10
|
|
||||||
//#define FLOAT 1 // Same as type
|
|
||||||
#define GREATER_EQUAL_SIGNED 11
|
|
||||||
#define GREATER_EQUAL_UNSIGNED 12
|
|
||||||
#define GREATER_SIGNED 13
|
|
||||||
#define GREATER_UNSIGNED 14
|
|
||||||
#define GROUP 15
|
|
||||||
#define LESS_EQUAL_SIGNED 16
|
|
||||||
#define LESS_EQUAL_UNSIGNED 17
|
|
||||||
#define LESS_SIGNED 18
|
|
||||||
#define LESS_UNSIGNED 19
|
|
||||||
#define LOGICAL_AND 20
|
|
||||||
#define LOGICAL_NOT 21
|
|
||||||
#define LOGICAL_OR 22
|
|
||||||
#define LOGICAL_XOR 23
|
|
||||||
#define MULTIPLY 24
|
|
||||||
#define NEGATE 25
|
|
||||||
#define NOT_EQUAL 26
|
|
||||||
#define READ_WORD 27
|
|
||||||
#define REMAINDER 28
|
|
||||||
#define ROUND 29
|
|
||||||
#define SHIFT_LEFT 30
|
|
||||||
#define SHIFT_RIGHT 31
|
|
||||||
#define SHIFT_RIGHT_ARITHMETIC 32
|
|
||||||
#define SUBTRACT 33
|
|
||||||
#define TRUNC 34
|
|
||||||
//#define WORD 0 // Same as type
|
|
||||||
#define XFLOAT 35
|
|
||||||
#define XWORD 36
|
|
||||||
|
|
||||||
// Functional symbol IDs
|
|
||||||
#define ADDRESS 0
|
|
||||||
#define CODE 1
|
|
||||||
#define COND 2
|
|
||||||
#define DISP 3
|
|
||||||
#define FORMAT 4
|
|
||||||
#define ID 5
|
|
||||||
#define IMM 6
|
|
||||||
#define OPCODE 7
|
|
||||||
#define REG1 8
|
|
||||||
#define REG2 9
|
|
||||||
#define REGID 10
|
|
||||||
#define SIZE 11
|
|
||||||
#define SUBOPCODE 12
|
|
||||||
#define VALUE 13
|
|
||||||
#define VECTOR 14
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Evaluation Helpers //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Resolve a float from word bits
|
|
||||||
static float asFloat(int32_t value) {
|
|
||||||
return *(float *)&value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve the word bits of a float
|
|
||||||
static int32_t asWord(float value) {
|
|
||||||
int32_t bits = *(int32_t *)&value;
|
|
||||||
int32_t exp = bits & 0x7F800000;
|
|
||||||
int32_t digits = bits & 0x007FFFFF;
|
|
||||||
return
|
|
||||||
!(bits & 0x7FFFFFFF) || // Zero
|
|
||||||
exp == 0x7F800000 || // Indefinite
|
|
||||||
!exp && digits != 0 // Denormal
|
|
||||||
? 0 : bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert a float to a word
|
|
||||||
static int32_t toWord(float value) {
|
|
||||||
value = roundf(value);
|
|
||||||
return value>=0x7FFFFFFF || value<(int32_t)0x80000000 ? 0 : (int) value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Binary Functions //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Evaluate +
|
|
||||||
static int32_t evalAdd(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
return leftWord && rightWord ? leftValue + rightValue : asWord(
|
|
||||||
(leftWord ? (float) leftValue : asFloat(leftValue )) +
|
|
||||||
(rightWord ? (float) rightValue : asFloat(rightValue))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate &
|
|
||||||
static int32_t evalBitwiseAnd(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
return (leftWord ? leftValue : toWord(asFloat(leftValue ))) &
|
|
||||||
(rightWord ? rightValue : toWord(asFloat(rightValue)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate |
|
|
||||||
static int32_t evalBitwiseOr(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
return (leftWord ? leftValue : toWord(asFloat(leftValue ))) |
|
|
||||||
(rightWord ? rightValue : toWord(asFloat(rightValue)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate ^
|
|
||||||
static int32_t evalBitwiseXOr(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
return (leftWord ? leftValue : toWord(asFloat(leftValue ))) ^
|
|
||||||
(rightWord ? rightValue : toWord(asFloat(rightValue)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate /
|
|
||||||
static int32_t evalDivide(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
return !(rightWord ? rightValue : rightValue & 0x7FFFFFFF) ? 0 :
|
|
||||||
leftWord && rightWord ? leftValue / rightValue : asWord(
|
|
||||||
(leftWord ? (float) leftValue : asFloat(leftValue )) /
|
|
||||||
(rightWord ? (float) rightValue : asFloat(rightValue))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate ==
|
|
||||||
static int32_t evalEqual(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
return leftWord && rightWord ? leftValue == rightValue : (
|
|
||||||
(leftWord ? (float) leftValue : asFloat(leftValue )) ==
|
|
||||||
(rightWord ? (float) rightValue : asFloat(rightValue))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate >=
|
|
||||||
static int32_t evalGreaterEqualSigned(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
return leftWord && rightWord ? leftValue >= rightValue : (
|
|
||||||
(leftWord ? (float) leftValue : asFloat(leftValue )) >=
|
|
||||||
(rightWord ? (float) rightValue : asFloat(rightValue))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate >=_
|
|
||||||
static int32_t evalGreaterEqualUnsigned(
|
|
||||||
int32_t leftWord,uint32_t leftValue,int32_t rightWord,uint32_t rightValue){
|
|
||||||
return leftWord && rightWord ? leftValue >= rightValue : (
|
|
||||||
(leftWord ? (float) leftValue : asFloat(leftValue )) >=
|
|
||||||
(rightWord ? (float) rightValue : asFloat(rightValue))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate >
|
|
||||||
static int32_t evalGreaterSigned(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
return leftWord && rightWord ? leftValue > rightValue : (
|
|
||||||
(leftWord ? (float) leftValue : asFloat(leftValue )) >
|
|
||||||
(rightWord ? (float) rightValue : asFloat(rightValue))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate >_
|
|
||||||
static int32_t evalGreaterUnsigned(
|
|
||||||
int32_t leftWord,uint32_t leftValue,int32_t rightWord,uint32_t rightValue){
|
|
||||||
return leftWord && rightWord ? leftValue > rightValue : (
|
|
||||||
(leftWord ? (float) leftValue : asFloat(leftValue )) >
|
|
||||||
(rightWord ? (float) rightValue : asFloat(rightValue))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate <=
|
|
||||||
static int32_t evalLessEqualSigned(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
return leftWord && rightWord ? leftValue <= rightValue : (
|
|
||||||
(leftWord ? (float) leftValue : asFloat(leftValue )) <=
|
|
||||||
(rightWord ? (float) rightValue : asFloat(rightValue))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate <=_
|
|
||||||
static int32_t evalLessEqualUnsigned(
|
|
||||||
int32_t leftWord,uint32_t leftValue,int32_t rightWord,uint32_t rightValue){
|
|
||||||
return leftWord && rightWord ? leftValue <= rightValue : (
|
|
||||||
(leftWord ? (float) leftValue : asFloat(leftValue )) <=
|
|
||||||
(rightWord ? (float) rightValue : asFloat(rightValue))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate <
|
|
||||||
static int32_t evalLessSigned(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
return leftWord && rightWord ? leftValue < rightValue : (
|
|
||||||
(leftWord ? (float) leftValue : asFloat(leftValue )) <
|
|
||||||
(rightWord ? (float) rightValue : asFloat(rightValue))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate <_
|
|
||||||
static int32_t evalLessUnsigned(
|
|
||||||
int32_t leftWord,uint32_t leftValue,int32_t rightWord,uint32_t rightValue){
|
|
||||||
return leftWord && rightWord ? leftValue < rightValue : (
|
|
||||||
(leftWord ? (float) leftValue : asFloat(leftValue )) <
|
|
||||||
(rightWord ? (float) rightValue : asFloat(rightValue))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate *
|
|
||||||
static int32_t evalMultiply(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
return leftWord && rightWord ? leftValue * rightValue : asWord(
|
|
||||||
(leftWord ? (float) leftValue : asFloat(leftValue )) *
|
|
||||||
(rightWord ? (float) rightValue : asFloat(rightValue))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate !=
|
|
||||||
static int32_t evalNotEqual(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
return leftWord && rightWord ? leftValue != rightValue : (
|
|
||||||
(leftWord ? (float) leftValue : asFloat(leftValue )) !=
|
|
||||||
(rightWord ? (float) rightValue : asFloat(rightValue))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate %
|
|
||||||
static int32_t evalRemainder(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
return !(rightWord ? rightValue : rightValue & 0x7FFFFFFF) ? 0 :
|
|
||||||
leftWord && rightWord ? leftValue % rightValue : asWord(fmodf(
|
|
||||||
(leftWord ? (float) leftValue : asFloat(leftValue )),
|
|
||||||
(rightWord ? (float) rightValue : asFloat(rightValue))
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate <<
|
|
||||||
static int32_t evalShiftLeft(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
leftValue = leftWord ? leftValue : toWord(asFloat(leftValue ));
|
|
||||||
leftValue = (rightWord ? rightValue : toWord(asFloat(rightValue))) & 31;
|
|
||||||
return leftValue << rightValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate >>
|
|
||||||
static int32_t evalShiftRightArithmetic(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
leftValue = leftWord ? leftValue : toWord(asFloat(leftValue ));
|
|
||||||
leftValue = (rightWord ? rightValue : toWord(asFloat(rightValue))) & 31;
|
|
||||||
return !rightValue ? leftValue :
|
|
||||||
leftValue >> rightValue & (1 << 32 - rightValue) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate >>>
|
|
||||||
static int32_t evalShiftRight(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
leftValue = leftWord ? leftValue : toWord(asFloat(leftValue ));
|
|
||||||
leftValue = (rightWord ? rightValue : toWord(asFloat(rightValue))) & 31;
|
|
||||||
if (!rightValue)
|
|
||||||
return leftValue;
|
|
||||||
leftValue >>= rightValue;
|
|
||||||
rightValue = 32 - rightValue;
|
|
||||||
return SIGN_EXTEND(rightValue, leftValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate -
|
|
||||||
static int32_t evalSubtract(
|
|
||||||
int32_t leftWord,int32_t leftValue,int32_t rightWord,int32_t rightValue) {
|
|
||||||
return leftWord && rightWord ? leftValue - rightValue : asWord(
|
|
||||||
(leftWord ? (float) leftValue : asFloat(leftValue )) -
|
|
||||||
(rightWord ? (float) rightValue : asFloat(rightValue))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Symbol Functions //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Evaluate address
|
|
||||||
static int32_t evalAddress(Vue *vue) {
|
|
||||||
if (vue->cpu.inst.format == 6)
|
|
||||||
return vue->cpu.program[vue->cpu.inst.reg1] + vue->cpu.inst.disp;
|
|
||||||
switch (vue->cpu.inst.id) {
|
|
||||||
case VUE_BCOND: case VUE_JAL: case VUE_JMP: case VUE_JR:
|
|
||||||
return vue->cpu.pc + vue->cpu.inst.disp;
|
|
||||||
case VUE_RETI:
|
|
||||||
return vue->cpu.psw_np ? vue->cpu.fepc : vue->cpu.eipc;
|
|
||||||
case VUE_TRAP:
|
|
||||||
return 0xFFFFFFA0 + vue->cpu.inst.imm & 0xFFFFFFF0;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate cond
|
|
||||||
static int32_t evalCond(Vue *vue) {
|
|
||||||
switch (vue->cpu.inst.id) {
|
|
||||||
case VUE_BCOND: return vue->cpu.inst.cond;
|
|
||||||
case VUE_SETF : return vue->cpu.inst.imm;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate disp
|
|
||||||
static int32_t evalDisp(Vue *vue) {
|
|
||||||
switch (vue->cpu.inst.format) {
|
|
||||||
case 3: case 4: case 6: return vue->cpu.inst.disp;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate imm
|
|
||||||
static int32_t evalImm(Vue *vue) {
|
|
||||||
switch (vue->cpu.inst.format) {
|
|
||||||
case 2: case 5: return vue->cpu.inst.imm;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate reg1
|
|
||||||
static int32_t evalReg1(Vue *vue) {
|
|
||||||
switch (vue->cpu.inst.format) {
|
|
||||||
case 1: case 5: case 6: case 7: return vue->cpu.inst.reg1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate reg2
|
|
||||||
static int32_t evalReg2(Vue *vue) {
|
|
||||||
switch (vue->cpu.inst.format) {
|
|
||||||
case 1: case 2: case 5: case 6: case 7: return vue->cpu.inst.reg2;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate regid
|
|
||||||
static int32_t evalRegId(Vue *vue) {
|
|
||||||
switch (vue->cpu.inst.id) {
|
|
||||||
case VUE_LDSR: case VUE_STSR: return vue->cpu.inst.imm;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate subopcode
|
|
||||||
static int32_t evalSubopcode(Vue *vue) {
|
|
||||||
switch (vue->cpu.inst.opcode) {
|
|
||||||
case 0x1F: return vue->cpu.inst.imm;
|
|
||||||
case 0x3E: return vue->cpu.inst.subopcode;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate value
|
|
||||||
static int evalValue(Vue *vue) {
|
|
||||||
return vue->cpu.inst.format == 6 ? vue->cpu.access.value : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate vector
|
|
||||||
static int evalVector(Vue *vue) {
|
|
||||||
return vue->cpu.inst.id == VUE_TRAP ? vue->cpu.inst.imm : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Unary Functions //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Evaluate ~
|
|
||||||
static int32_t evalBitwiseNot(int32_t isWord, int32_t value) {
|
|
||||||
return isWord ? ~value : ~toWord(asFloat(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate !
|
|
||||||
static int32_t evalLogicalNot(int32_t isWord, int32_t value) {
|
|
||||||
return isWord ? !value : !asFloat(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate -
|
|
||||||
static int32_t evalNegate(int32_t isWord, int32_t value) {
|
|
||||||
return isWord ? -value : asWord(-asFloat(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate ceil
|
|
||||||
static int32_t evalCeil(int32_t isWord, int32_t value) {
|
|
||||||
return isWord ? value : asWord(ceilf(asFloat(value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate float
|
|
||||||
static int32_t evalFloat(int32_t isWord, int32_t value) {
|
|
||||||
return isWord ? asWord((float) value) : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate floor
|
|
||||||
static int32_t evalFloor(int32_t isWord, int32_t value) {
|
|
||||||
return isWord ? value : asWord(floorf(asFloat(value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate []
|
|
||||||
static int32_t evalReadWord(int32_t isWord, int32_t value, Vue *vue) {
|
|
||||||
return vueRead(vue, isWord ? value : toWord(asFloat(value)), VUE_S32);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate round
|
|
||||||
static int32_t evalRound(int32_t isWord, int32_t value) {
|
|
||||||
return isWord ? value : asWord(roundf(asFloat(value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate trunc
|
|
||||||
static int32_t evalTrunc(int32_t isWord, int32_t value) {
|
|
||||||
return isWord ? value : asWord(truncf(asFloat(value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate word
|
|
||||||
static int32_t evalWord(int32_t isWord, int32_t value) {
|
|
||||||
return isWord ? value : toWord(asFloat(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate xfloat
|
|
||||||
static int32_t evalXFloat(int32_t isWord, int32_t value) {
|
|
||||||
return isWord ? asWord(asFloat(value)) : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Evaluation Functions //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Evaluate a binary operator
|
|
||||||
static int32_t evalBinary(int32_t id, int32_t *stack, int32_t size) {
|
|
||||||
int32_t rv = stack[size - 1];
|
|
||||||
int32_t rt = stack[size - 2];
|
|
||||||
int32_t rw = rt == WORD;
|
|
||||||
int32_t lv = stack[size - 3];
|
|
||||||
int32_t lt = stack[size - 4];
|
|
||||||
int32_t lw = lt == WORD;
|
|
||||||
int32_t type = rw && lw ? WORD : FLOAT;
|
|
||||||
int32_t value = 0;
|
|
||||||
switch (id) {
|
|
||||||
|
|
||||||
// Arithmetic
|
|
||||||
case ADD :
|
|
||||||
value = evalAdd (lw, lv, rw, rv); break;
|
|
||||||
case DIVIDE :
|
|
||||||
value = evalDivide (lw, lv, rw, rv); break;
|
|
||||||
case MULTIPLY :
|
|
||||||
value = evalMultiply (lw, lv, rw, rv); break;
|
|
||||||
case REMAINDER :
|
|
||||||
value = evalRemainder (lw, lv, rw, rv); break;
|
|
||||||
case SUBTRACT :
|
|
||||||
value = evalSubtract (lw, lv, rw, rv); break;
|
|
||||||
default:
|
|
||||||
type = WORD; switch (id) {
|
|
||||||
|
|
||||||
// Bitwise
|
|
||||||
case BITWISE_AND :
|
|
||||||
value = evalBitwiseAnd (lw, lv, rw, rv); break;
|
|
||||||
case BITWISE_OR :
|
|
||||||
value = evalBitwiseOr (lw, lv, rw, rv); break;
|
|
||||||
case BITWISE_XOR :
|
|
||||||
value = evalBitwiseXOr (lw, lv, rw, rv); break;
|
|
||||||
case SHIFT_LEFT :
|
|
||||||
value = evalShiftLeft (lw, lv, rw, rv); break;
|
|
||||||
case SHIFT_RIGHT :
|
|
||||||
value = evalShiftRight (lw, lv, rw, rv); break;
|
|
||||||
case SHIFT_RIGHT_ARITHMETIC:
|
|
||||||
value = evalShiftRightArithmetic(lw, lv, rw, rv); break;
|
|
||||||
|
|
||||||
// Relational
|
|
||||||
case EQUAL :
|
|
||||||
value = evalEqual (lw, lv, rw, rv); break;
|
|
||||||
case GREATER_EQUAL_SIGNED :
|
|
||||||
value = evalGreaterEqualSigned (lw, lv, rw, rv); break;
|
|
||||||
case GREATER_EQUAL_UNSIGNED:
|
|
||||||
value = evalGreaterEqualUnsigned(lw, lv, rw, rv); break;
|
|
||||||
case GREATER_SIGNED :
|
|
||||||
value = evalGreaterSigned (lw, lv, rw, rv); break;
|
|
||||||
case GREATER_UNSIGNED :
|
|
||||||
value = evalGreaterUnsigned (lw, lv, rw, rv); break;
|
|
||||||
case LESS_EQUAL_SIGNED :
|
|
||||||
value = evalLessEqualSigned (lw, lv, rw, rv); break;
|
|
||||||
case LESS_EQUAL_UNSIGNED :
|
|
||||||
value = evalLessEqualUnsigned (lw, lv, rw, rv); break;
|
|
||||||
case LESS_SIGNED :
|
|
||||||
value = evalLessSigned (lw, lv, rw, rv); break;
|
|
||||||
case LESS_UNSIGNED :
|
|
||||||
value = evalLessUnsigned (lw, lv, rw, rv); break;
|
|
||||||
case NOT_EQUAL :
|
|
||||||
value = evalNotEqual (lw, lv, rw, rv); break;
|
|
||||||
|
|
||||||
// Logical
|
|
||||||
default:
|
|
||||||
lw = (lv & (lw ? 0xFFFFFFFF : 0x7FFFFFFF)) != 0;
|
|
||||||
rw = (rv & (rw ? 0xFFFFFFFF : 0x7FFFFFFF)) != 0;
|
|
||||||
|
|
||||||
// Evaluate &&
|
|
||||||
case LOGICAL_AND:
|
|
||||||
type = lt; value = lv;
|
|
||||||
if (lw)
|
|
||||||
{ type = rt; value = rv; }
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Evaluate ||
|
|
||||||
case LOGICAL_OR:
|
|
||||||
type = lt; value = lv;
|
|
||||||
if (!lw)
|
|
||||||
{ type = rt; value = rv; }
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Evaluate ^^
|
|
||||||
case LOGICAL_XOR:
|
|
||||||
type = rt; value = rv;
|
|
||||||
if (lw == rw)
|
|
||||||
{ type = WORD; value = 0; }
|
|
||||||
else if (lw)
|
|
||||||
{ type = lt; value = lv; }
|
|
||||||
break;
|
|
||||||
}}
|
|
||||||
stack[size - 4] = type;
|
|
||||||
stack[size - 3] = value;
|
|
||||||
return size - 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate a functional symbol
|
|
||||||
static int32_t evalSymbol(Vue *vue, int32_t id, int32_t *stack, int32_t size) {
|
|
||||||
int32_t ret = 0;
|
|
||||||
if (id == VUE_PC)
|
|
||||||
ret = vue->cpu.pc;
|
|
||||||
else if (id >= 200)
|
|
||||||
ret = vueGetRegister(vue, id - 200, VUE_TRUE);
|
|
||||||
else if (id >= 100)
|
|
||||||
ret = vue->cpu.program[id - 100];
|
|
||||||
else if (vue->cpu.stage == EXCEPTION && id == CODE)
|
|
||||||
ret = vue->cpu.exception.code;
|
|
||||||
else if (vue->cpu.stage == EXECUTE) switch (id) {
|
|
||||||
case ADDRESS : ret = evalAddress (vue); break;
|
|
||||||
case COND : ret = evalCond (vue); break;
|
|
||||||
case DISP : ret = evalDisp (vue); break;
|
|
||||||
case FORMAT : ret = vue->cpu.inst.format; break;
|
|
||||||
case ID : ret = vue->cpu.inst.id ; break;
|
|
||||||
case IMM : ret = evalImm (vue); break;
|
|
||||||
case OPCODE : ret = vue->cpu.inst.opcode; break;
|
|
||||||
case REG1 : ret = evalReg1 (vue); break;
|
|
||||||
case REG2 : ret = evalReg2 (vue); break;
|
|
||||||
case REGID : ret = evalRegId (vue); break;
|
|
||||||
case SIZE : ret = vue->cpu.inst.size ; break;
|
|
||||||
case SUBOPCODE: ret = evalSubopcode (vue); break;
|
|
||||||
case VALUE : ret = evalValue (vue); break;
|
|
||||||
case VECTOR : ret = evalVector (vue); break;
|
|
||||||
}
|
|
||||||
stack[size++] = WORD;
|
|
||||||
stack[size++] = ret;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate a unary operator
|
|
||||||
static void evalUnary(Vue *vue, int32_t id, int32_t *stack, int32_t size) {
|
|
||||||
int32_t type = stack[size - 2];
|
|
||||||
int32_t value = stack[size - 1];
|
|
||||||
int32_t isWord = type == WORD;
|
|
||||||
switch (id) {
|
|
||||||
case BITWISE_NOT: value = evalBitwiseNot(isWord, value);
|
|
||||||
type = WORD ; break;
|
|
||||||
case LOGICAL_NOT: value = evalLogicalNot(isWord, value);
|
|
||||||
type = WORD ; break;
|
|
||||||
case NEGATE : value = evalNegate (isWord, value); break;
|
|
||||||
case CEIL : value = evalCeil (isWord, value); break;
|
|
||||||
case FLOAT : value = evalFloat (isWord, value);
|
|
||||||
type = FLOAT; break;
|
|
||||||
case FLOOR : value = evalFloor (isWord, value); break;
|
|
||||||
case READ_WORD : value = evalReadWord (isWord, value, vue);
|
|
||||||
type = WORD ; break;
|
|
||||||
case ROUND : value = evalRound (isWord, value); break;
|
|
||||||
case TRUNC : value = evalTrunc (isWord, value); break;
|
|
||||||
case WORD : value = evalWord (isWord, value);
|
|
||||||
type = WORD ; break;
|
|
||||||
case XFLOAT : value = evalXFloat (isWord, value);
|
|
||||||
type = FLOAT; break;
|
|
||||||
case XWORD : type = WORD;
|
|
||||||
}
|
|
||||||
stack[size - 2] = type;
|
|
||||||
stack[size - 1] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate a breakpoint condition for an emulation context
|
|
||||||
int32_t evaluate(Vue *vue, Breakpoint *brk, int32_t *stack) {
|
|
||||||
|
|
||||||
// The condition is empty
|
|
||||||
if (brk->numTokens == 0)
|
|
||||||
return brk->enabled;
|
|
||||||
|
|
||||||
// Process tokens
|
|
||||||
int size = 0;
|
|
||||||
for (int x = 0; x < brk->numTokens; x++) {
|
|
||||||
Token *tok = &brk->tokens[x];
|
|
||||||
switch (tok->type) {
|
|
||||||
case BINARY: size =
|
|
||||||
evalBinary( tok->value, stack, size); continue;
|
|
||||||
case SYMBOL: size =
|
|
||||||
evalSymbol(vue, tok->value, stack, size); continue;
|
|
||||||
case UNARY :
|
|
||||||
evalUnary (vue, tok->value, stack, size); continue;
|
|
||||||
}
|
|
||||||
stack[size++] = tok->type;
|
|
||||||
stack[size++] = tok->value;
|
|
||||||
}
|
|
||||||
return (stack[1] & (stack[0] == WORD ? 0xFFFFFFFF : 0x7FFFFFFF)) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // NATIVEVUE
|
#endif // NATIVEVUE
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -12,7 +12,7 @@ class CPU {
|
||||||
// Package fields
|
// Package fields
|
||||||
Access access; // Access state
|
Access access; // Access state
|
||||||
int cycles; // Cycles until next stage
|
int cycles; // Cycles until next stage
|
||||||
Ecxeption exception; // Exception code
|
Ecxeption exception; // Exception state
|
||||||
int fetch; // Fetch unit index
|
int fetch; // Fetch unit index
|
||||||
Instruction inst; // Instruction state
|
Instruction inst; // Instruction state
|
||||||
int irq; // Interrupt lines
|
int irq; // Interrupt lines
|
||||||
|
@ -114,8 +114,8 @@ class CPU {
|
||||||
// Process the simulation
|
// Process the simulation
|
||||||
void emulate(int cycles) {
|
void emulate(int cycles) {
|
||||||
|
|
||||||
// The CPU is in permanent halt
|
// The CPU is halting
|
||||||
if (stage == FATAL)
|
if (stage == HALT || stage == FATAL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.cycles = 0; // DEBUG: Stop processing after execute
|
this.cycles = 0; // DEBUG: Stop processing after execute
|
||||||
|
@ -130,6 +130,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
|
||||||
}
|
}
|
||||||
|
|
||||||
// Processing by stage
|
// Processing by stage
|
||||||
|
this.cycles = 0;
|
||||||
switch (stage) {
|
switch (stage) {
|
||||||
case EXCEPTION: if (exception ()) return; break;
|
case EXCEPTION: if (exception ()) return; break;
|
||||||
case EXECUTE : if (execute ()) return; break;
|
case EXECUTE : if (execute ()) return; break;
|
||||||
|
@ -273,7 +274,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
|
||||||
private boolean exception() {
|
private boolean exception() {
|
||||||
|
|
||||||
// Application callback
|
// Application callback
|
||||||
vue.breakCode = vue.onException(exception);
|
vue.breakCode = vue.onException() ? 1 : 0;
|
||||||
if (vue.breakCode != 0)
|
if (vue.breakCode != 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -331,7 +332,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
|
||||||
private boolean execute() {
|
private boolean execute() {
|
||||||
|
|
||||||
// Application callback
|
// Application callback
|
||||||
vue.breakCode = vue.onExecute(inst);
|
vue.breakCode = vue.onExecute() ? 1 : 0;
|
||||||
if (vue.breakCode != 0)
|
if (vue.breakCode != 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -471,7 +472,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
|
||||||
access.value = vue.read(address, type);
|
access.value = vue.read(address, type);
|
||||||
|
|
||||||
// Application callback
|
// Application callback
|
||||||
vue.breakCode = vue.onRead(access);
|
vue.breakCode = vue.onRead() ? 1 : 0;
|
||||||
return vue.breakCode != 0;
|
return vue.breakCode != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,7 +485,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
|
||||||
case 3: return psw_cy | psw_z;
|
case 3: return psw_cy | psw_z;
|
||||||
case 4: return psw_s;
|
case 4: return psw_s;
|
||||||
case 5: return 1;
|
case 5: return 1;
|
||||||
case 6: return psw_ov | psw_s;
|
case 6: return psw_ov ^ psw_s;
|
||||||
case 7: return psw_ov ^ psw_s | psw_z;
|
case 7: return psw_ov ^ psw_s | psw_z;
|
||||||
}
|
}
|
||||||
return testCondition(condition & 7) ^ 1;
|
return testCondition(condition & 7) ^ 1;
|
||||||
|
@ -522,7 +523,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
|
||||||
access.value = value;
|
access.value = value;
|
||||||
|
|
||||||
// Application callback
|
// Application callback
|
||||||
vue.breakCode = vue.onWrite(access);
|
vue.breakCode = vue.onWrite() ? 1 : 0;
|
||||||
if (vue.breakCode != 0)
|
if (vue.breakCode != 0)
|
||||||
return true;
|
return true;
|
||||||
if (access.type == Vue.CANCEL)
|
if (access.type == Vue.CANCEL)
|
||||||
|
|
|
@ -17,4 +17,10 @@ public class Ecxeption {
|
||||||
// Default constructor
|
// Default constructor
|
||||||
Ecxeption() { }
|
Ecxeption() { }
|
||||||
|
|
||||||
|
// Cloning constructor
|
||||||
|
Ecxeption(Ecxeption o) {
|
||||||
|
this();
|
||||||
|
code = o.code;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,22 @@ public class Instruction {
|
||||||
// Default constructor
|
// Default constructor
|
||||||
public Instruction() { }
|
public Instruction() { }
|
||||||
|
|
||||||
|
// Cloning constructor
|
||||||
|
Instruction(Instruction o) {
|
||||||
|
this();
|
||||||
|
bits = o.bits;
|
||||||
|
cond = o.cond;
|
||||||
|
disp = o.disp;
|
||||||
|
format = o.format;
|
||||||
|
id = o.id;
|
||||||
|
imm = o.imm;
|
||||||
|
opcode = o.opcode;
|
||||||
|
reg1 = o.reg1;
|
||||||
|
reg2 = o.reg2;
|
||||||
|
size = o.size;
|
||||||
|
subopcode = o.subopcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -9,7 +9,9 @@ class JavaVue extends Vue {
|
||||||
// Package fields
|
// Package fields
|
||||||
int breakCode; // Application break code
|
int breakCode; // Application break code
|
||||||
CPU cpu; // Processor
|
CPU cpu; // Processor
|
||||||
|
int hook; // Most recent breakpoint hook
|
||||||
GamePak pak; // Game pak
|
GamePak pak; // Game pak
|
||||||
|
int[] stack; // Breakpoint evaluation stack
|
||||||
byte[] wram; // System WRAM
|
byte[] wram; // System WRAM
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,9 +31,10 @@ class JavaVue extends Vue {
|
||||||
|
|
||||||
// Default constructor
|
// Default constructor
|
||||||
JavaVue() {
|
JavaVue() {
|
||||||
cpu = new CPU (this);
|
cpu = new CPU (this);
|
||||||
pak = new GamePak(this);
|
pak = new GamePak(this);
|
||||||
wram = new byte[0x10000];
|
stack = new int[0];
|
||||||
|
wram = new byte[0x10000];
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,12 +55,12 @@ class JavaVue extends Vue {
|
||||||
|
|
||||||
// Determine the number of cycles during which nothing will happen
|
// Determine the number of cycles during which nothing will happen
|
||||||
int cycles = -1;
|
int cycles = -1;
|
||||||
|
cycles = cpu .until(cycles);
|
||||||
//cycles = pad .until(cycles);
|
//cycles = pad .until(cycles);
|
||||||
//cycles = link .until(cycles);
|
//cycles = link .until(cycles);
|
||||||
//cycles = timer.until(cycles);
|
//cycles = timer.until(cycles);
|
||||||
//cycles = vip .until(cycles);
|
//cycles = vip .until(cycles);
|
||||||
//cycles = vsu .until(cycles);
|
//cycles = vsu .until(cycles);
|
||||||
cycles = cpu .until(cycles);
|
|
||||||
|
|
||||||
// Range checking
|
// Range checking
|
||||||
if (cycles == -1) // No activity on any component
|
if (cycles == -1) // No activity on any component
|
||||||
|
@ -66,17 +69,16 @@ class JavaVue extends Vue {
|
||||||
cycles = Math.min(cycles, maxCycles);
|
cycles = Math.min(cycles, maxCycles);
|
||||||
|
|
||||||
// Process all system components
|
// Process all system components
|
||||||
breakCode = 0;
|
cpu .emulate(cycles);
|
||||||
//pad .emulate(cycles);
|
//pad .emulate(cycles);
|
||||||
//link .emulate(cycles);
|
//link .emulate(cycles);
|
||||||
//timer.emulate(cycles);
|
//timer.emulate(cycles);
|
||||||
//vip .emulate(cycles);
|
//vip .emulate(cycles);
|
||||||
//vsu .emulate(cycles);
|
//vsu .emulate(cycles);
|
||||||
cpu .emulate(cycles);
|
|
||||||
|
|
||||||
// An application break was requested
|
// An application break was requested
|
||||||
if (breakCode != 0)
|
//if (...)
|
||||||
break;
|
// break;
|
||||||
|
|
||||||
// Update the number of cycles remaining
|
// Update the number of cycles remaining
|
||||||
if (maxCycles >= 0)
|
if (maxCycles >= 0)
|
||||||
|
@ -87,9 +89,14 @@ class JavaVue extends Vue {
|
||||||
return Math.max(0, maxCycles);
|
return Math.max(0, maxCycles);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the application break code
|
// Evaluate an expression
|
||||||
public int getBreakCode() {
|
public Object evaluate(String expression) {
|
||||||
return breakCode;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the most recent exception code
|
||||||
|
public int getException() {
|
||||||
|
return cpu.exception.code;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a register value
|
// Retrieve a register value
|
||||||
|
@ -249,23 +256,23 @@ class JavaVue extends Vue {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exception break handler
|
// Exception break handler
|
||||||
int onException(Ecxeption exp) {
|
boolean onException() {
|
||||||
return 0;
|
return onHook(Breakpoint.EXCEPTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute break handler
|
// Execute break handler
|
||||||
int onExecute(Instruction inst) {
|
boolean onExecute() {
|
||||||
return 0;
|
return onHook(Breakpoint.EXECUTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read break handler
|
// Read break handler
|
||||||
int onRead(Access acc) {
|
boolean onRead() {
|
||||||
return 0;
|
return onHook(Breakpoint.READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write break handler
|
// Write break handler
|
||||||
int onWrite(Access acc) {
|
boolean onWrite() {
|
||||||
return 0;
|
return onHook(Breakpoint.WRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a value from a byte buffer
|
// Read a value from a byte buffer
|
||||||
|
@ -370,4 +377,19 @@ class JavaVue extends Vue {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Private Methods //
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Check breakpoints during a hooked event
|
||||||
|
private boolean onHook(int hook) {
|
||||||
|
this.hook = hook;
|
||||||
|
for (var brk : breakpoints)
|
||||||
|
if (evaluate(brk))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,102 +259,3 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVue_writeBytes
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Private Methods //
|
// Private Methods //
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Produce a new breakpoint and add it to the collection
|
|
||||||
JNIEXPORT void JNICALL Java_vue_NativeVue_breakpoint
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
int32_t size; // Number of bytes to allocate
|
|
||||||
|
|
||||||
// Allocate memory for the breakpoint
|
|
||||||
core->numBreakpoints++;
|
|
||||||
size = core->numBreakpoints * sizeof (Breakpoint);
|
|
||||||
core->breakpoints = core->breakpoints == NULL ?
|
|
||||||
malloc(size) : realloc(core->breakpoints, size);
|
|
||||||
|
|
||||||
// Initialize the breakpoint
|
|
||||||
memset(&core->breakpoints[core->numBreakpoints-1], 0, sizeof (Breakpoint));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove a breakpoint from the collection
|
|
||||||
JNIEXPORT void JNICALL Java_vue_NativeVue_remove
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jint index) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
Breakpoint *brk = &core->breakpoints[index];
|
|
||||||
|
|
||||||
// Delete the breakpoint
|
|
||||||
if (brk->ranges != NULL) free(brk->ranges);
|
|
||||||
if (brk->tokens != NULL) free(brk->tokens);
|
|
||||||
|
|
||||||
// Move all subsequent breakpoints forward
|
|
||||||
if (index != core->numBreakpoints - 1)
|
|
||||||
memmove(brk, &brk[1],
|
|
||||||
(core->numBreakpoints - index) * sizeof (Breakpoint));
|
|
||||||
core->numBreakpoints--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A breakpoint's address ranges have changed
|
|
||||||
JNIEXPORT void JNICALL Java_vue_NativeVue_updateRanges
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jint index, jintArray ranges) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
Breakpoint *brk = &core->breakpoints[index];
|
|
||||||
jint *elems; // Array elements
|
|
||||||
int32_t size; // Number of bytes to allocate
|
|
||||||
|
|
||||||
// Determine the number of address ranges
|
|
||||||
brk->numRanges = (*env)->GetArrayLength(env, ranges) / 2;
|
|
||||||
if (brk->numRanges == 0) {
|
|
||||||
if (brk->ranges != NULL)
|
|
||||||
free(brk->ranges);
|
|
||||||
brk->ranges = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate memory for the address ranges
|
|
||||||
size = brk->numRanges * sizeof (Range);
|
|
||||||
brk->ranges = brk->ranges == NULL ?
|
|
||||||
malloc(size) : realloc(brk->ranges, size);
|
|
||||||
|
|
||||||
// Initialize address ranges
|
|
||||||
elems = (*env)->GetIntArrayElements(env, ranges, NULL);
|
|
||||||
memcpy(brk->ranges, elems, size);
|
|
||||||
(*env)->ReleaseIntArrayElements(env, ranges, elems, JNI_ABORT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A breakpoint's enabled/hook state has changed
|
|
||||||
JNIEXPORT void JNICALL Java_vue_NativeVue_updateState
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jint index, jboolean enabled,
|
|
||||||
jint hooks) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
Breakpoint *brk = &core->breakpoints[index];
|
|
||||||
brk->enabled = enabled;
|
|
||||||
brk->hooks = hooks;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A breakpoint's condition tokens have changed
|
|
||||||
JNIEXPORT void JNICALL Java_vue_NativeVue_updateTokens
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jint index, jintArray tokens) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
Breakpoint *brk = &core->breakpoints[index];
|
|
||||||
jint *elems; // Array elements
|
|
||||||
int32_t size; // Number of bytes to allocate
|
|
||||||
|
|
||||||
// Determine the number of condition tokens
|
|
||||||
brk->numTokens = (*env)->GetArrayLength(env, tokens) / 2;
|
|
||||||
if (brk->numTokens == 0) {
|
|
||||||
if (brk->tokens != NULL)
|
|
||||||
free(brk->tokens);
|
|
||||||
brk->tokens = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate memory for the condition tokens
|
|
||||||
size = brk->numTokens * sizeof (Token);
|
|
||||||
brk->tokens = brk->tokens == NULL ?
|
|
||||||
malloc(size) : realloc(brk->tokens, size);
|
|
||||||
|
|
||||||
// Initialize condition tokens
|
|
||||||
elems = (*env)->GetIntArrayElements(env, tokens, NULL);
|
|
||||||
memcpy(brk->tokens, elems, size);
|
|
||||||
(*env)->ReleaseIntArrayElements(env, tokens, elems, JNI_ABORT);
|
|
||||||
}
|
|
||||||
|
|
|
@ -45,6 +45,12 @@ class NativeVue extends Vue {
|
||||||
private native int getBreakCode(long handle);
|
private native int getBreakCode(long handle);
|
||||||
public int getBreakCode() { return getBreakCode(handle); }
|
public int getBreakCode() { return getBreakCode(handle); }
|
||||||
|
|
||||||
|
// Retrieve the most recent exception code
|
||||||
|
private native int getException(long handle);
|
||||||
|
public int getException() {
|
||||||
|
return getException(handle);
|
||||||
|
}
|
||||||
|
|
||||||
// Retrieve a register value
|
// Retrieve a register value
|
||||||
private native int getRegister(long handle, int index, boolean system);
|
private native int getRegister(long handle, int index, boolean system);
|
||||||
public int getRegister(int index, boolean system)
|
public int getRegister(int index, boolean system)
|
||||||
|
@ -119,20 +125,16 @@ class NativeVue extends Vue {
|
||||||
// A breakpoint's address ranges have changed
|
// A breakpoint's address ranges have changed
|
||||||
void updateRanges(Breakpoint brk) {
|
void updateRanges(Breakpoint brk) {
|
||||||
super.updateRanges(brk);
|
super.updateRanges(brk);
|
||||||
updateRanges(handle, breakpoints.indexOf(brk), brk.flattenRanges());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A breakpoint's enabled/hook state has changed
|
// A breakpoint's enabled/hook state has changed
|
||||||
void updateState(Breakpoint brk) {
|
void updateState(Breakpoint brk) {
|
||||||
super.updateState(brk);
|
super.updateState(brk);
|
||||||
updateState(handle, breakpoints.indexOf(brk),
|
|
||||||
brk.isEnabled(), brk.getHooks());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A breakpoint's condition tokens have changed
|
// A breakpoint's condition tokens have changed
|
||||||
void updateTokens(Breakpoint brk) {
|
void updateTokens(Breakpoint brk) {
|
||||||
super.updateTokens(brk);
|
super.updateTokens(brk);
|
||||||
updateTokens(handle, breakpoints.indexOf(brk), brk.flattenTokens());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -147,14 +149,4 @@ class NativeVue extends Vue {
|
||||||
// Remove a breakpoint from the collection
|
// Remove a breakpoint from the collection
|
||||||
private native void remove(long handle, int index);
|
private native void remove(long handle, int index);
|
||||||
|
|
||||||
// A breakpoint's address ranges have changed
|
|
||||||
private native void updateRanges(long handle, int index, int[] ranges);
|
|
||||||
|
|
||||||
// A breakpoint's enabled/hook state has changed
|
|
||||||
private native void updateState(long handle, int index, boolean enabled,
|
|
||||||
int hooks);
|
|
||||||
|
|
||||||
// A breakpoint's condition tokens have changed
|
|
||||||
private native void updateTokens(long handle, int index, int[] tokens);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,6 +180,13 @@ public abstract class Vue {
|
||||||
return brk;
|
return brk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Evaluate an expression
|
||||||
|
public Object evaluate(String expression) {
|
||||||
|
var brk = new Breakpoint(this);
|
||||||
|
brk.setCondition(expression);
|
||||||
|
return brk.evaluate(null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
// Produce an array of the current breakpoint collection
|
// Produce an array of the current breakpoint collection
|
||||||
public Breakpoint[] listBreakpoints() {
|
public Breakpoint[] listBreakpoints() {
|
||||||
return breakpoints.toArray(new Breakpoint[breakpoints.size()]);
|
return breakpoints.toArray(new Breakpoint[breakpoints.size()]);
|
||||||
|
@ -205,8 +212,8 @@ public abstract class Vue {
|
||||||
// Process the simulation
|
// Process the simulation
|
||||||
public abstract int emulate(int maxCycles);
|
public abstract int emulate(int maxCycles);
|
||||||
|
|
||||||
// Retrieve the application break code
|
// Retrieve the most recent exception code
|
||||||
public abstract int getBreakCode();
|
public abstract int getException();
|
||||||
|
|
||||||
// Retrieve a register value
|
// Retrieve a register value
|
||||||
public abstract int getRegister(int index, boolean system);
|
public abstract int getRegister(int index, boolean system);
|
||||||
|
@ -246,9 +253,6 @@ public abstract class Vue {
|
||||||
// Package Methods //
|
// Package Methods //
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Evaluate the condition in a breakpoint
|
|
||||||
abstract boolean evaluate(Breakpoint brk);
|
|
||||||
|
|
||||||
// A breakpoint's address ranges have changed
|
// A breakpoint's address ranges have changed
|
||||||
void updateRanges(Breakpoint brk) { }
|
void updateRanges(Breakpoint brk) { }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue