Finalizing breakpoint architecture, correcting CPU conditions, tweaking top-level emulation logic

This commit is contained in:
Guy Perfect 2020-12-17 15:40:37 -06:00
parent 826e921dac
commit e13c56e1e7
12 changed files with 1527 additions and 1889 deletions

View File

@ -1,6 +1,6 @@
# Java include directory pathnames
# 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
include_windows = jni-windows-include
@ -10,12 +10,12 @@ default:
@echo $(include_linux)
@echo "Planet Virtual Boy Emulator"
@echo " https://www.planetvb.com/"
@echo " October 16, 2020"
@echo " December 17, 2020"
@echo
@echo "Intended build environment: Debian i386 or amd64"
@echo " gcc-multilib"
@echo " mingw-w64"
@echo " openjdk-14-jdk"
@echo " openjdk-15-jdk"
@echo
@echo "Usage: make <recipe>"
@echo " Package recipes:"
@ -69,7 +69,7 @@ core:
desktop: clean_desktop
@echo " Compiling Java desktop application"
@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
.PHONY: native

View File

@ -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 4: return vue->cpu.psw_s;
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;
}
return cpuTestCondition(vue, condition & 7) ^ 1;
@ -1174,8 +1174,8 @@ static vbool cpuException(Vue *vue) {
/* Process the simulation */
static void cpuEmulate(Vue *vue, int32_t cycles) {
/* The CPU is in permanent halt */
if (vue->cpu.stage == CPU_FATAL)
/* The CPU is halting */
if (vue->cpu.stage == CPU_FATAL || vue->cpu.stage == CPU_HALT)
return;
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 */
vue->cpu.cycles = 0;
switch (vue->cpu.stage) {
case CPU_EXCEPTION: if (cpuException (vue)) return; break;
case CPU_EXECUTE : if (cpuExecute (vue)) return; break;

View File

@ -49,31 +49,41 @@ public class Main {
useNative = true;
// Begin application operations
new App(useNative);
//new App(useNative);
/*
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);
if (brk.setCondition(exp))
System.out.println(brk.debug());
else System.out.println(
brk.getErrorCode (Breakpoint.CONDITION) + "\t" +
brk.getErrorPosition(Breakpoint.CONDITION) + ":" +
brk.getErrorText (Breakpoint.CONDITION)
System.out.println(brk.debugTokens());
else {
var err = brk.getConditionError();
System.out.println("Error " +
err.code + "\t" +
err.position + ":" +
err.text
);
}
*/
/*
exp = "123, 456 - 987 , f0-fffffff2";
System.out.println("\n" + exp);
if (brk.setAddresses(exp))
System.out.println(brk.test());
else System.out.println(
brk.getErrorCode (Breakpoint.ADDRESS) + "\t" +
brk.getErrorPosition(Breakpoint.ADDRESS) + ":" +
brk.getErrorText (Breakpoint.ADDRESS)
System.out.println(brk.debugRanges());
else {
var err = brk.getAddressError();
System.out.println("Error " +
err.code + "\t" +
err.position + ":" +
err.text
);
}
*/
}

View File

@ -1,636 +1,4 @@
// This file is included through NativeVUE.c and cannot be built directly. */
#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

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@ class CPU {
// Package fields
Access access; // Access state
int cycles; // Cycles until next stage
Ecxeption exception; // Exception code
Ecxeption exception; // Exception state
int fetch; // Fetch unit index
Instruction inst; // Instruction state
int irq; // Interrupt lines
@ -114,8 +114,8 @@ class CPU {
// Process the simulation
void emulate(int cycles) {
// The CPU is in permanent halt
if (stage == FATAL)
// The CPU is halting
if (stage == HALT || stage == FATAL)
return;
this.cycles = 0; // DEBUG: Stop processing after execute
@ -130,6 +130,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
}
// Processing by stage
this.cycles = 0;
switch (stage) {
case EXCEPTION: if (exception ()) return; break;
case EXECUTE : if (execute ()) return; break;
@ -273,7 +274,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
private boolean exception() {
// Application callback
vue.breakCode = vue.onException(exception);
vue.breakCode = vue.onException() ? 1 : 0;
if (vue.breakCode != 0)
return true;
@ -331,7 +332,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
private boolean execute() {
// Application callback
vue.breakCode = vue.onExecute(inst);
vue.breakCode = vue.onExecute() ? 1 : 0;
if (vue.breakCode != 0)
return true;
@ -471,7 +472,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
access.value = vue.read(address, type);
// Application callback
vue.breakCode = vue.onRead(access);
vue.breakCode = vue.onRead() ? 1 : 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 4: return psw_s;
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;
}
return testCondition(condition & 7) ^ 1;
@ -522,7 +523,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
access.value = value;
// Application callback
vue.breakCode = vue.onWrite(access);
vue.breakCode = vue.onWrite() ? 1 : 0;
if (vue.breakCode != 0)
return true;
if (access.type == Vue.CANCEL)

View File

@ -17,4 +17,10 @@ public class Ecxeption {
// Default constructor
Ecxeption() { }
// Cloning constructor
Ecxeption(Ecxeption o) {
this();
code = o.code;
}
}

View File

@ -82,6 +82,22 @@ public class Instruction {
// Default constructor
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;
}
///////////////////////////////////////////////////////////////////////////

View File

@ -9,7 +9,9 @@ class JavaVue extends Vue {
// Package fields
int breakCode; // Application break code
CPU cpu; // Processor
int hook; // Most recent breakpoint hook
GamePak pak; // Game pak
int[] stack; // Breakpoint evaluation stack
byte[] wram; // System WRAM
@ -31,6 +33,7 @@ class JavaVue extends Vue {
JavaVue() {
cpu = new CPU (this);
pak = new GamePak(this);
stack = new int[0];
wram = new byte[0x10000];
reset();
}
@ -52,12 +55,12 @@ class JavaVue extends Vue {
// Determine the number of cycles during which nothing will happen
int cycles = -1;
cycles = cpu .until(cycles);
//cycles = pad .until(cycles);
//cycles = link .until(cycles);
//cycles = timer.until(cycles);
//cycles = vip .until(cycles);
//cycles = vsu .until(cycles);
cycles = cpu .until(cycles);
// Range checking
if (cycles == -1) // No activity on any component
@ -66,17 +69,16 @@ class JavaVue extends Vue {
cycles = Math.min(cycles, maxCycles);
// Process all system components
breakCode = 0;
cpu .emulate(cycles);
//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;
//if (...)
// break;
// Update the number of cycles remaining
if (maxCycles >= 0)
@ -87,9 +89,14 @@ class JavaVue extends Vue {
return Math.max(0, maxCycles);
}
// Retrieve the application break code
public int getBreakCode() {
return breakCode;
// Evaluate an expression
public Object evaluate(String expression) {
return null;
}
// Retrieve the most recent exception code
public int getException() {
return cpu.exception.code;
}
// Retrieve a register value
@ -249,23 +256,23 @@ class JavaVue extends Vue {
}
// Exception break handler
int onException(Ecxeption exp) {
return 0;
boolean onException() {
return onHook(Breakpoint.EXCEPTION);
}
// Execute break handler
int onExecute(Instruction inst) {
return 0;
boolean onExecute() {
return onHook(Breakpoint.EXECUTE);
}
// Read break handler
int onRead(Access acc) {
return 0;
boolean onRead() {
return onHook(Breakpoint.READ);
}
// Write break handler
int onWrite(Access acc) {
return 0;
boolean onWrite() {
return onHook(Breakpoint.WRITE);
}
// 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;
}
}

View File

@ -259,102 +259,3 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVue_writeBytes
///////////////////////////////////////////////////////////////////////////////
// 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);
}

View File

@ -45,6 +45,12 @@ class NativeVue extends Vue {
private native int getBreakCode(long 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
private native int getRegister(long handle, 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
void updateRanges(Breakpoint brk) {
super.updateRanges(brk);
updateRanges(handle, breakpoints.indexOf(brk), brk.flattenRanges());
}
// A breakpoint's enabled/hook state has changed
void updateState(Breakpoint brk) {
super.updateState(brk);
updateState(handle, breakpoints.indexOf(brk),
brk.isEnabled(), brk.getHooks());
}
// A breakpoint's condition tokens have changed
void updateTokens(Breakpoint 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
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);
}

View File

@ -180,6 +180,13 @@ public abstract class Vue {
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
public Breakpoint[] listBreakpoints() {
return breakpoints.toArray(new Breakpoint[breakpoints.size()]);
@ -205,8 +212,8 @@ public abstract class Vue {
// Process the simulation
public abstract int emulate(int maxCycles);
// Retrieve the application break code
public abstract int getBreakCode();
// Retrieve the most recent exception code
public abstract int getException();
// Retrieve a register value
public abstract int getRegister(int index, boolean system);
@ -246,9 +253,6 @@ public abstract class Vue {
// Package Methods //
///////////////////////////////////////////////////////////////////////////
// Evaluate the condition in a breakpoint
abstract boolean evaluate(Breakpoint brk);
// A breakpoint's address ranges have changed
void updateRanges(Breakpoint brk) { }