diff --git a/makefile b/makefile index 0f12504..edcabb3 100644 --- a/makefile +++ b/makefile @@ -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 " @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 diff --git a/src/core/cpu.c b/src/core/cpu.c index b26eb30..b99829a 100644 --- a/src/core/cpu.c +++ b/src/core/cpu.c @@ -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; diff --git a/src/desktop/Main.java b/src/desktop/Main.java index 7e5710a..960fe6e 100644 --- a/src/desktop/Main.java +++ b/src/desktop/Main.java @@ -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 + ); + } */ } diff --git a/src/desktop/vue/Breakpoint.c b/src/desktop/vue/Breakpoint.c index 63d169a..b2ce744 100644 --- a/src/desktop/vue/Breakpoint.c +++ b/src/desktop/vue/Breakpoint.c @@ -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 diff --git a/src/desktop/vue/Breakpoint.java b/src/desktop/vue/Breakpoint.java index 35b6c46..1515485 100644 --- a/src/desktop/vue/Breakpoint.java +++ b/src/desktop/vue/Breakpoint.java @@ -3,21 +3,22 @@ package vue; // Java imports import java.util.*; -// Breakpoint definition +// Breakpoint descriptor public class Breakpoint { // Instance fields - private String addresses; // Un-processed address ranges - private String condition; // Un-processed condition - private int[] errCode; // Error codes - private int[] errPosition; // Character position of errors - private String[] errText; // Offending error text - private int hooks; // Applied breakpoint types - private boolean isEnabled; // Breakpoint is active - private String name; // Display name - private int[][] ranges; // Applicable address ranges - private Token[] tokens; // Condition tokens - private Vue vue; // Containing emulation context + private Error addressError; // Address parsing error + private String addresses; // Un-processed address ranges + private String condition; // Un-processed condition + private Error conditionError; // Condition parsing error + private int dataType; // Condition evaluation data type + private int depth; // Stack size for condition evaluation + private int hooks; // Applied breakpoint types + private boolean isEnabled; // Breakpoint is active + private String name; // Display name + private int[][] ranges; // Applicable address ranges + private Token[] tokens; // Condition tokens + private Vue vue; // Containing emulation context @@ -26,86 +27,42 @@ public class Breakpoint { /////////////////////////////////////////////////////////////////////////// // Error codes - public static final int BADTYPE = -1; - public static final int NONE = 0; - public static final int BADLITERAL = 1; - public static final int BADTOKEN = 2; - public static final int EARLYEOF = 3; - public static final int EMPTY = 4; - public static final int INVALID = 5; - public static final int NESTING = 6; - public static final int UNEXPECTED = 7; + public static final int NONE = 0; // Parsing was successful + public static final int BADLITERAL = 1; // Primitive parse failed + public static final int BADOPERAND = 2; // Operator/operand type mismatch + public static final int BADTOKEN = 3; // No token matched + public static final int EARLYEOF = 4; // Last token not value or close + public static final int INVALID = 5; // Operator not allowed here + public static final int NESTING = 6; // ()[] mismatch, underflow + public static final int UNEXPECTED = 7; // Character not allowed here - // Error types - public static final int ADDRESS = 0; - public static final int CONDITION = 1; - - // Breakpoint hooks - private static final int EXCEPTION = 0x00000001; - private static final int EXECUTE = 0x00000002; - private static final int READ = 0x00000004; - private static final int WRITE = 0x00000008; + // Hook flags + static final int EXCEPTION = 0x00000001; + static final int EXECUTE = 0x00000002; + static final int FRAME = 0x00000004; + static final int READ = 0x00000008; + static final int WRITE = 0x00000010; // Token types - private static final int BINARY = 4; - private static final int CLOSE = 6; - private static final int FLOAT = 1; - private static final int UNARY = 3; - private static final int OPEN = 5; - private static final int SYMBOL = 2; - private static final int WORD = 0; + private static final int BOOL = 0; // Value types + private static final int SIGNED = 1; + private static final int UNSIGNED = 2; + private static final int FLOAT = 3; + private static final int SYMBOL = 4; // Symbol types + private static final int PROREG = 5; + private static final int SYSREG = 6; + private static final int UNARY = 7; // Operator types + private static final int BINARY = 8; + private static final int OPEN = 9; + private static final int CLOSE = 10; // Expected token modes adjacent to any given token // 0 = Value, unary or open expected, 1 = Binary or close expected - private static final int MODES_AFTER = 0b1000111; - private static final int MODES_BEFORE = 0b1010000; - - // Operator IDs - private static final int ADD = 2; - private static final int BITWISE_AND = 3; - private static final int BITWISE_NOT = 4; - private static final int BITWISE_OR = 5; - private static final int BITWISE_XOR = 6; - private static final int CEIL = 7; - private static final int DIVIDE = 8; - private static final int EQUAL = 9; - private static final int FLOOR = 10; - //private static final int FLOAT = 1; // Same as type - private static final int GREATER_EQUAL_SIGNED = 11; - private static final int GREATER_EQUAL_UNSIGNED = 12; - private static final int GREATER_SIGNED = 13; - private static final int GREATER_UNSIGNED = 14; - private static final int GROUP = 15; - private static final int LESS_EQUAL_SIGNED = 16; - private static final int LESS_EQUAL_UNSIGNED = 17; - private static final int LESS_SIGNED = 18; - private static final int LESS_UNSIGNED = 19; - private static final int LOGICAL_AND = 20; - private static final int LOGICAL_NOT = 21; - private static final int LOGICAL_OR = 22; - private static final int LOGICAL_XOR = 23; - private static final int MULTIPLY = 24; - private static final int NEGATE = 25; - private static final int NOT_EQUAL = 26; - private static final int READ_WORD = 27; - private static final int REMAINDER = 28; - private static final int ROUND = 29; - private static final int SHIFT_LEFT = 30; - private static final int SHIFT_RIGHT = 31; - private static final int SHIFT_RIGHT_ARITHMETIC = 32; - private static final int SUBTRACT = 33; - private static final int TRUNC = 34; - //private static final int WORD = 0; // Same as type - private static final int XFLOAT = 35; - private static final int XWORD = 36; - - // Token definitions - private static final HashMap LITDEFS; - private static final HashMap OPDEFS; - private static final HashMap SYMDEFS; + private static final int MODES_AFTER = 0b10001111111; + private static final int MODES_BEFORE = 0b10100000000; // Functional symbol IDs - //private static final int ADDRESS = 0; // Same as error type + private static final int ADDRESS = 0; private static final int CODE = 1; private static final int COND = 2; private static final int DISP = 3; @@ -121,147 +78,291 @@ public class Breakpoint { private static final int VALUE = 13; private static final int VECTOR = 14; + // Evaluation operator IDs + private static final int GROUP = 0; // () + private static final int XS32 = 1; // xs32, xword + private static final int XU32 = 2; // xu32, xuword + private static final int XFLOAT = 3; // xfloat + private static final int READ8 = 4; // [] + private static final int READ16 = 5; // [] + private static final int READ32 = 6; // [] + private static final int BOOL_ = - 2; // bool + private static final int S32 = - 3; // s32, word + private static final int U32 = - 4; // u32, uword + private static final int FLOAT_ = - 5; // float + private static final int ADD = - 6; // + + private static final int AND_B = - 7; // & + private static final int AND_L = - 8; // && + private static final int CEIL = - 9; // ceil + private static final int DIVIDE = -10; // / + private static final int EQUAL = -11; // == + private static final int FLOOR = -12; // floor + private static final int GREATER = -13; // > + private static final int GREQUAL = -14; // >= + private static final int LEFT_L = -15; // << + private static final int LEQUAL = -16; // <= + private static final int LESS = -17; // < + private static final int MULTIPLY = -18; // * + private static final int NEQUAL = -19; // != + private static final int NOT_B = -20; // ~ + private static final int NOT_L = -21; // ! + private static final int NEGATE = -22; // - + private static final int OR_B = -23; // | + private static final int OR_L = -24; // || + private static final int REMAINDER = -25; // % + private static final int RIGHT_A = -26; // >> + private static final int RIGHT_L = -27; // >>> + private static final int ROUND = -28; // round + private static final int S8 = -29; // s8, byte + private static final int S16 = -30; // s16, halfword + private static final int SUBTRACT = -31; // - + private static final int TRUNC = -32; // trunc + private static final int U8 = -33; // u8, ubyte + private static final int U16 = -34; // u16, uhalfword + private static final int XOR_B = -36; // ^ + private static final int XOR_L = -37; // ^^ + + // Integer-float conversion + private static final float MAX_WORD = (float) Math.pow(2, 31); + private static final float MAX_UWORD = (float) Math.pow(2, 32); + + // Token definitions + private static final HashMap OPDEFS; + private static final HashMap SYMDEFS; + // Static initializer static { - LITDEFS = new HashMap(); - OPDEFS = new HashMap(); - SYMDEFS = new HashMap(); + OPDEFS = new HashMap(); + SYMDEFS = new HashMap(); // Operator definitions - OPDEFS.put("(" , new OpDef( 0, OPEN , GROUP )); - OPDEFS.put(")" , new OpDef( 0, CLOSE , GROUP )); - OPDEFS.put("[" , new OpDef( 0, OPEN , READ_WORD )); - OPDEFS.put("]" , new OpDef( 0, CLOSE , READ_WORD )); - OPDEFS.put("~" , new OpDef( 1, UNARY , BITWISE_NOT )); - OPDEFS.put("!" , new OpDef( 1, UNARY , LOGICAL_NOT )); - OPDEFS.put("-" , new OpDef( 1, UNARY , NEGATE )); - OPDEFS.put("ceil" , new OpDef( 1, UNARY , CEIL )); - OPDEFS.put("float" , new OpDef( 1, UNARY , FLOAT )); - OPDEFS.put("floor" , new OpDef( 1, UNARY , FLOOR )); - OPDEFS.put("round" , new OpDef( 1, UNARY , ROUND )); - OPDEFS.put("trunc" , new OpDef( 1, UNARY , TRUNC )); - OPDEFS.put("word" , new OpDef( 1, UNARY , WORD )); - OPDEFS.put("xfloat", new OpDef( 1, UNARY , XFLOAT )); - OPDEFS.put("xword" , new OpDef( 1, UNARY , XWORD )); - OPDEFS.put("/" , new OpDef( 2, BINARY, DIVIDE )); - OPDEFS.put("*" , new OpDef( 2, BINARY, MULTIPLY )); - OPDEFS.put("%" , new OpDef( 2, BINARY, REMAINDER )); - OPDEFS.put("+" , new OpDef( 3, BINARY, ADD )); - OPDEFS.put("<<" , new OpDef( 4, BINARY, SHIFT_LEFT )); - OPDEFS.put(">>" , new OpDef( 4, BINARY, SHIFT_RIGHT )); - OPDEFS.put(">>>" , new OpDef( 4, BINARY, SHIFT_RIGHT_ARITHMETIC)); - OPDEFS.put(">" , new OpDef( 5, BINARY, GREATER_SIGNED )); - OPDEFS.put(">_" , new OpDef( 5, BINARY, GREATER_UNSIGNED )); - OPDEFS.put(">=" , new OpDef( 5, BINARY, GREATER_EQUAL_SIGNED )); - OPDEFS.put(">=_" , new OpDef( 5, BINARY, GREATER_EQUAL_UNSIGNED)); - OPDEFS.put("<" , new OpDef( 5, BINARY, LESS_SIGNED )); - OPDEFS.put("<_" , new OpDef( 5, BINARY, LESS_UNSIGNED )); - OPDEFS.put("<=" , new OpDef( 5, BINARY, LESS_EQUAL_SIGNED )); - OPDEFS.put("<=_" , new OpDef( 5, BINARY, LESS_EQUAL_UNSIGNED )); - OPDEFS.put("==" , new OpDef( 6, BINARY, EQUAL )); - OPDEFS.put("!=" , new OpDef( 6, BINARY, NOT_EQUAL )); - OPDEFS.put("&" , new OpDef( 7, BINARY, BITWISE_AND )); - OPDEFS.put("^" , new OpDef( 8, BINARY, BITWISE_XOR )); - OPDEFS.put("|" , new OpDef( 9, BINARY, BITWISE_OR )); - OPDEFS.put("&&" , new OpDef(10, BINARY, LOGICAL_AND )); - OPDEFS.put("^^" , new OpDef(11, BINARY, LOGICAL_XOR )); - OPDEFS.put("||" , new OpDef(12, BINARY, LOGICAL_OR )); + OPDEFS.put("(" , new Def( 0, OPEN , GROUP )); + OPDEFS.put(")" , new Def( 0, CLOSE , GROUP )); + OPDEFS.put("[" , new Def( 0, OPEN , READ32 )); + OPDEFS.put("]" , new Def( 0, CLOSE , READ32 )); + OPDEFS.put("~" , new Def( 1, UNARY , NOT_B )); + OPDEFS.put("!" , new Def( 1, UNARY , NOT_L )); + OPDEFS.put("-" , new Def( 1, UNARY , NEGATE )); + OPDEFS.put("bool" , new Def( 1, UNARY , BOOL_ )); + OPDEFS.put("byte" , new Def( 1, UNARY , S8 )); + OPDEFS.put("ceil" , new Def( 1, UNARY , CEIL )); + OPDEFS.put("float" , new Def( 1, UNARY , FLOAT_ )); + OPDEFS.put("floor" , new Def( 1, UNARY , FLOOR )); + OPDEFS.put("halfword" , new Def( 1, UNARY , S16 )); + OPDEFS.put("round" , new Def( 1, UNARY , ROUND )); + OPDEFS.put("s8" , new Def( 1, UNARY , S8 )); + OPDEFS.put("s16" , new Def( 1, UNARY , S16 )); + OPDEFS.put("s32" , new Def( 1, UNARY , S32 )); + OPDEFS.put("trunc" , new Def( 1, UNARY , TRUNC )); + OPDEFS.put("u8" , new Def( 1, UNARY , U8 )); + OPDEFS.put("u16" , new Def( 1, UNARY , U16 )); + OPDEFS.put("u32" , new Def( 1, UNARY , U32 )); + OPDEFS.put("ubyte" , new Def( 1, UNARY , U8 )); + OPDEFS.put("uhalfword", new Def( 1, UNARY , U16 )); + OPDEFS.put("uword" , new Def( 1, UNARY , U32 )); + OPDEFS.put("word" , new Def( 1, UNARY , S32 )); + OPDEFS.put("xfloat" , new Def( 1, UNARY , XFLOAT )); + OPDEFS.put("xs32" , new Def( 1, UNARY , XS32 )); + OPDEFS.put("xu32" , new Def( 1, UNARY , XU32 )); + OPDEFS.put("xuword" , new Def( 1, UNARY , XU32 )); + OPDEFS.put("xword" , new Def( 1, UNARY , XS32 )); + OPDEFS.put("/" , new Def( 2, BINARY, DIVIDE )); + OPDEFS.put("*" , new Def( 2, BINARY, MULTIPLY )); + OPDEFS.put("%" , new Def( 2, BINARY, REMAINDER)); + OPDEFS.put("+" , new Def( 3, BINARY, ADD )); + OPDEFS.put("<<" , new Def( 4, BINARY, LEFT_L )); + OPDEFS.put(">>" , new Def( 4, BINARY, RIGHT_A )); + OPDEFS.put(">>>" , new Def( 4, BINARY, RIGHT_L )); + OPDEFS.put(">" , new Def( 5, BINARY, GREATER )); + OPDEFS.put(">=" , new Def( 5, BINARY, GREQUAL )); + OPDEFS.put("<" , new Def( 5, BINARY, LESS )); + OPDEFS.put("<=" , new Def( 5, BINARY, LEQUAL )); + OPDEFS.put("==" , new Def( 6, BINARY, EQUAL )); + OPDEFS.put("!=" , new Def( 6, BINARY, NEQUAL )); + OPDEFS.put("&" , new Def( 7, BINARY, AND_B )); + OPDEFS.put("^" , new Def( 8, BINARY, XOR_B )); + OPDEFS.put("|" , new Def( 9, BINARY, OR_B )); + OPDEFS.put("&&" , new Def(10, BINARY, AND_L )); + OPDEFS.put("^^" , new Def(11, BINARY, XOR_L )); + OPDEFS.put("||" , new Def(12, BINARY, OR_L )); - // Instruction ID literal definitions - LITDEFS.put("add_imm", 0); LITDEFS.put("mulu" , 38); - LITDEFS.put("add_reg", 1); LITDEFS.put("not" , 39); - LITDEFS.put("addf.s" , 2); LITDEFS.put("notbsu" , 40); - LITDEFS.put("addi" , 3); LITDEFS.put("or" , 41); - LITDEFS.put("and" , 4); LITDEFS.put("orbsu" , 42); - LITDEFS.put("andbsu" , 5); LITDEFS.put("ori" , 43); - LITDEFS.put("andi" , 6); LITDEFS.put("ornbsu" , 44); - LITDEFS.put("andnbsu", 7); LITDEFS.put("out.b" , 45); - LITDEFS.put("bcond" , 8); LITDEFS.put("out.h" , 46); - LITDEFS.put("caxi" , 9); LITDEFS.put("out.w" , 47); - LITDEFS.put("cli" , 10); LITDEFS.put("reti" , 48); - LITDEFS.put("cmp_imm", 11); LITDEFS.put("rev" , 49); - LITDEFS.put("cmp_reg", 12); LITDEFS.put("sar_imm", 50); - LITDEFS.put("cmpf.s" , 13); LITDEFS.put("sar_reg", 51); - LITDEFS.put("cvt.sw" , 14); LITDEFS.put("sch0bsd", 52); - LITDEFS.put("cvt.ws" , 15); LITDEFS.put("sch0bsu", 53); - LITDEFS.put("div" , 16); LITDEFS.put("sch1bsd", 54); - LITDEFS.put("divf.s" , 17); LITDEFS.put("sch1bsu", 55); - LITDEFS.put("divu" , 18); LITDEFS.put("sei" , 56); - LITDEFS.put("halt" , 19); LITDEFS.put("setf" , 57); - LITDEFS.put("in.b" , 20); LITDEFS.put("shl_imm", 58); - LITDEFS.put("in.h" , 21); LITDEFS.put("shl_reg", 59); - LITDEFS.put("in.w" , 22); LITDEFS.put("shr_imm", 60); - LITDEFS.put("jal" , 23); LITDEFS.put("shr_reg", 61); - LITDEFS.put("jmp" , 24); LITDEFS.put("st.b" , 62); - LITDEFS.put("jr" , 25); LITDEFS.put("st.h" , 63); - LITDEFS.put("ld.b" , 26); LITDEFS.put("st.w" , 64); - LITDEFS.put("ld.h" , 27); LITDEFS.put("stsr" , 65); - LITDEFS.put("ld.w" , 28); LITDEFS.put("sub" , 66); - LITDEFS.put("ldsr" , 29); LITDEFS.put("subf.s" , 67); - LITDEFS.put("mov_imm", 30); LITDEFS.put("trap" , 68); - LITDEFS.put("mov_reg", 31); LITDEFS.put("trnc.sw", 69); - LITDEFS.put("movbsu" , 32); LITDEFS.put("xb" , 70); - LITDEFS.put("movea" , 33); LITDEFS.put("xh" , 71); - LITDEFS.put("movhi" , 34); LITDEFS.put("xor" , 72); - LITDEFS.put("mpyhw" , 35); LITDEFS.put("xorbsu" , 73); - LITDEFS.put("mul" , 36); LITDEFS.put("xori" , 74); - LITDEFS.put("mulf.s" , 37); LITDEFS.put("xornbsu", 75); - LITDEFS.put("illegal", -1); + // Boolean symbol definitions + SYMDEFS.put("false", new Def(BOOL, 0)); + SYMDEFS.put("true" , new Def(BOOL, 1)); + + // Condition code symbol definitions + SYMDEFS.put("c" , new Def(SIGNED, 1)); + SYMDEFS.put("e" , new Def(SIGNED, 2)); + SYMDEFS.put("f" , new Def(SIGNED, 13)); + SYMDEFS.put("ge", new Def(SIGNED, 14)); + SYMDEFS.put("gt", new Def(SIGNED, 15)); + SYMDEFS.put("h" , new Def(SIGNED, 11)); + SYMDEFS.put("l" , new Def(SIGNED, 1)); + SYMDEFS.put("le", new Def(SIGNED, 7)); + SYMDEFS.put("lt", new Def(SIGNED, 6)); + SYMDEFS.put("n" , new Def(SIGNED, 4)); + SYMDEFS.put("nc", new Def(SIGNED, 9)); + SYMDEFS.put("ne", new Def(SIGNED, 10)); + SYMDEFS.put("nh", new Def(SIGNED, 3)); + SYMDEFS.put("nl", new Def(SIGNED, 9)); + SYMDEFS.put("nv", new Def(SIGNED, 8)); + SYMDEFS.put("nz", new Def(SIGNED, 10)); + SYMDEFS.put("p" , new Def(SIGNED, 12)); + SYMDEFS.put("t" , new Def(SIGNED, 5)); + SYMDEFS.put("v" , new Def(SIGNED, 0)); + SYMDEFS.put("z" , new Def(SIGNED, 2)); + + // Instruction ID symbol definitions + SYMDEFS.put("illegal", new Def(SIGNED, Vue.ILLEGAL)); + SYMDEFS.put("add_imm", new Def(SIGNED, Vue.ADD_IMM)); + SYMDEFS.put("add_reg", new Def(SIGNED, Vue.ADD_REG)); + SYMDEFS.put("addf.s" , new Def(SIGNED, Vue.ADDF_S )); + SYMDEFS.put("addi" , new Def(SIGNED, Vue.ADDI )); + SYMDEFS.put("and" , new Def(SIGNED, Vue.AND )); + SYMDEFS.put("andbsu" , new Def(SIGNED, Vue.ANDBSU )); + SYMDEFS.put("andi" , new Def(SIGNED, Vue.ANDI )); + SYMDEFS.put("andnbsu", new Def(SIGNED, Vue.ANDNBSU)); + SYMDEFS.put("bcond" , new Def(SIGNED, Vue.BCOND )); + SYMDEFS.put("caxi" , new Def(SIGNED, Vue.CAXI )); + SYMDEFS.put("cli" , new Def(SIGNED, Vue.CLI )); + SYMDEFS.put("cmp_imm", new Def(SIGNED, Vue.CMP_IMM)); + SYMDEFS.put("cmp_reg", new Def(SIGNED, Vue.CMP_REG)); + SYMDEFS.put("cmpf.s" , new Def(SIGNED, Vue.CMPF_S )); + SYMDEFS.put("cvt.sw" , new Def(SIGNED, Vue.CVT_SW )); + SYMDEFS.put("cvt.ws" , new Def(SIGNED, Vue.CVT_WS )); + SYMDEFS.put("div" , new Def(SIGNED, Vue.DIV )); + SYMDEFS.put("divf.s" , new Def(SIGNED, Vue.DIVF_S )); + SYMDEFS.put("divu" , new Def(SIGNED, Vue.DIVU )); + SYMDEFS.put("halt" , new Def(SIGNED, Vue.HALT )); + SYMDEFS.put("in.b" , new Def(SIGNED, Vue.IN_B )); + SYMDEFS.put("in.h" , new Def(SIGNED, Vue.IN_H )); + SYMDEFS.put("in.w" , new Def(SIGNED, Vue.IN_W )); + SYMDEFS.put("jal" , new Def(SIGNED, Vue.JAL )); + SYMDEFS.put("jmp" , new Def(SIGNED, Vue.JMP )); + SYMDEFS.put("jr" , new Def(SIGNED, Vue.JR )); + SYMDEFS.put("ld.b" , new Def(SIGNED, Vue.LD_B )); + SYMDEFS.put("ld.h" , new Def(SIGNED, Vue.LD_H )); + SYMDEFS.put("ld.w" , new Def(SIGNED, Vue.LD_W )); + SYMDEFS.put("ldsr" , new Def(SIGNED, Vue.LDSR )); + SYMDEFS.put("mov_imm", new Def(SIGNED, Vue.MOV_IMM)); + SYMDEFS.put("mov_reg", new Def(SIGNED, Vue.MOV_REG)); + SYMDEFS.put("movbsu" , new Def(SIGNED, Vue.MOVBSU )); + SYMDEFS.put("movea" , new Def(SIGNED, Vue.MOVEA )); + SYMDEFS.put("movhi" , new Def(SIGNED, Vue.MOVHI )); + SYMDEFS.put("mpyhw" , new Def(SIGNED, Vue.MPYHW )); + SYMDEFS.put("mul" , new Def(SIGNED, Vue.MUL )); + SYMDEFS.put("mulf.s" , new Def(SIGNED, Vue.MULF_S )); + SYMDEFS.put("mulu" , new Def(SIGNED, Vue.MULU )); + SYMDEFS.put("not" , new Def(SIGNED, Vue.NOT )); + SYMDEFS.put("notbsu" , new Def(SIGNED, Vue.NOTBSU )); + SYMDEFS.put("or" , new Def(SIGNED, Vue.OR )); + SYMDEFS.put("orbsu" , new Def(SIGNED, Vue.ORBSU )); + SYMDEFS.put("ori" , new Def(SIGNED, Vue.ORI )); + SYMDEFS.put("ornbsu" , new Def(SIGNED, Vue.ORNBSU )); + SYMDEFS.put("out.b" , new Def(SIGNED, Vue.OUT_B )); + SYMDEFS.put("out.h" , new Def(SIGNED, Vue.OUT_H )); + SYMDEFS.put("out.w" , new Def(SIGNED, Vue.OUT_W )); + SYMDEFS.put("reti" , new Def(SIGNED, Vue.RETI )); + SYMDEFS.put("rev" , new Def(SIGNED, Vue.REV )); + SYMDEFS.put("sar_imm", new Def(SIGNED, Vue.SAR_IMM)); + SYMDEFS.put("sar_reg", new Def(SIGNED, Vue.SAR_REG)); + SYMDEFS.put("sch0bsd", new Def(SIGNED, Vue.SCH0BSD)); + SYMDEFS.put("sch0bsu", new Def(SIGNED, Vue.SCH0BSU)); + SYMDEFS.put("sch1bsd", new Def(SIGNED, Vue.SCH1BSD)); + SYMDEFS.put("sch1bsu", new Def(SIGNED, Vue.SCH1BSU)); + SYMDEFS.put("sei" , new Def(SIGNED, Vue.SEI )); + SYMDEFS.put("setf" , new Def(SIGNED, Vue.SETF )); + SYMDEFS.put("shl_imm", new Def(SIGNED, Vue.SHL_IMM)); + SYMDEFS.put("shl_reg", new Def(SIGNED, Vue.SHL_REG)); + SYMDEFS.put("shr_imm", new Def(SIGNED, Vue.SHR_IMM)); + SYMDEFS.put("shr_reg", new Def(SIGNED, Vue.SHR_REG)); + SYMDEFS.put("st.b" , new Def(SIGNED, Vue.ST_B )); + SYMDEFS.put("st.h" , new Def(SIGNED, Vue.ST_H )); + SYMDEFS.put("st.w" , new Def(SIGNED, Vue.ST_W )); + SYMDEFS.put("stsr" , new Def(SIGNED, Vue.STSR )); + SYMDEFS.put("sub" , new Def(SIGNED, Vue.SUB )); + SYMDEFS.put("subf.s" , new Def(SIGNED, Vue.SUBF_S )); + SYMDEFS.put("trap" , new Def(SIGNED, Vue.TRAP )); + SYMDEFS.put("trnc.sw", new Def(SIGNED, Vue.TRNC_SW)); + SYMDEFS.put("xb" , new Def(SIGNED, Vue.XB )); + SYMDEFS.put("xh" , new Def(SIGNED, Vue.XH )); + SYMDEFS.put("xor" , new Def(SIGNED, Vue.XOR )); + SYMDEFS.put("xorbsu" , new Def(SIGNED, Vue.XORBSU )); + SYMDEFS.put("xori" , new Def(SIGNED, Vue.XORI )); + SYMDEFS.put("xornbsu", new Def(SIGNED, Vue.XORNBSU)); // Functional symbol definitions - SYMDEFS.put("address" , ADDRESS ); - SYMDEFS.put("code" , CODE ); - SYMDEFS.put("cond" , COND ); - SYMDEFS.put("disp" , DISP ); - SYMDEFS.put("format" , FORMAT ); - SYMDEFS.put("imm" , IMM ); - SYMDEFS.put("id" , ID ); - SYMDEFS.put("opcode" , OPCODE ); - SYMDEFS.put("reg1" , REG1 ); - SYMDEFS.put("reg2" , REG2 ); - SYMDEFS.put("regid" , REGID ); - SYMDEFS.put("size" , SIZE ); - SYMDEFS.put("subopcode", SUBOPCODE); - SYMDEFS.put("value" , VALUE ); - SYMDEFS.put("vector" , VECTOR ); + SYMDEFS.put("address" , new Def(SYMBOL, ADDRESS )); + SYMDEFS.put("code" , new Def(SYMBOL, CODE )); + SYMDEFS.put("cond" , new Def(SYMBOL, COND )); + SYMDEFS.put("disp" , new Def(SYMBOL, DISP )); + SYMDEFS.put("format" , new Def(SYMBOL, FORMAT )); + SYMDEFS.put("id" , new Def(SYMBOL, ID )); + SYMDEFS.put("imm" , new Def(SYMBOL, IMM )); + SYMDEFS.put("opcode" , new Def(SYMBOL, OPCODE )); + SYMDEFS.put("reg1" , new Def(SYMBOL, REG1 )); + SYMDEFS.put("reg2" , new Def(SYMBOL, REG2 )); + SYMDEFS.put("regid" , new Def(SYMBOL, REGID )); + SYMDEFS.put("size" , new Def(SYMBOL, SIZE )); + SYMDEFS.put("subopcode", new Def(SYMBOL, SUBOPCODE)); + SYMDEFS.put("value" , new Def(SYMBOL, VALUE )); + SYMDEFS.put("vector" , new Def(SYMBOL, VECTOR )); // Program register symbol definitions - SYMDEFS.put("r0" , 100); SYMDEFS.put("r16", 116); - SYMDEFS.put("r1" , 101); SYMDEFS.put("r17", 117); - SYMDEFS.put("r2" , 102); SYMDEFS.put("r18", 118); - SYMDEFS.put("r3" , 103); SYMDEFS.put("r19", 119); - SYMDEFS.put("r4" , 104); SYMDEFS.put("r20", 120); - SYMDEFS.put("r5" , 105); SYMDEFS.put("r21", 121); - SYMDEFS.put("r6" , 106); SYMDEFS.put("r22", 122); - SYMDEFS.put("r7" , 107); SYMDEFS.put("r23", 123); - SYMDEFS.put("r8" , 108); SYMDEFS.put("r24", 124); - SYMDEFS.put("r9" , 109); SYMDEFS.put("r25", 125); - SYMDEFS.put("r10", 110); SYMDEFS.put("r26", 126); - SYMDEFS.put("r11", 111); SYMDEFS.put("r27", 127); - SYMDEFS.put("r12", 112); SYMDEFS.put("r28", 128); - SYMDEFS.put("r13", 113); SYMDEFS.put("r29", 129); - SYMDEFS.put("r14", 114); SYMDEFS.put("r30", 130); - SYMDEFS.put("r15", 115); SYMDEFS.put("r31", 131); - SYMDEFS.put("hp" , 102); SYMDEFS.put("gp" , 104); - SYMDEFS.put("sp" , 103); SYMDEFS.put("tp" , 105); - SYMDEFS.put("lp" , 131); + SYMDEFS.put("r0" , new Def(PROREG, 0)); + SYMDEFS.put("r1" , new Def(PROREG, 1)); + SYMDEFS.put("r2" , new Def(PROREG, 2)); + SYMDEFS.put("r3" , new Def(PROREG, 3)); + SYMDEFS.put("r4" , new Def(PROREG, 4)); + SYMDEFS.put("r5" , new Def(PROREG, 5)); + SYMDEFS.put("r6" , new Def(PROREG, 6)); + SYMDEFS.put("r7" , new Def(PROREG, 7)); + SYMDEFS.put("r8" , new Def(PROREG, 8)); + SYMDEFS.put("r9" , new Def(PROREG, 9)); + SYMDEFS.put("r10", new Def(PROREG, 10)); + SYMDEFS.put("r11", new Def(PROREG, 11)); + SYMDEFS.put("r12", new Def(PROREG, 12)); + SYMDEFS.put("r13", new Def(PROREG, 13)); + SYMDEFS.put("r14", new Def(PROREG, 14)); + SYMDEFS.put("r15", new Def(PROREG, 15)); + SYMDEFS.put("r16", new Def(PROREG, 16)); + SYMDEFS.put("r17", new Def(PROREG, 17)); + SYMDEFS.put("r18", new Def(PROREG, 18)); + SYMDEFS.put("r19", new Def(PROREG, 19)); + SYMDEFS.put("r20", new Def(PROREG, 20)); + SYMDEFS.put("r21", new Def(PROREG, 21)); + SYMDEFS.put("r22", new Def(PROREG, 22)); + SYMDEFS.put("r23", new Def(PROREG, 23)); + SYMDEFS.put("r24", new Def(PROREG, 24)); + SYMDEFS.put("r25", new Def(PROREG, 25)); + SYMDEFS.put("r26", new Def(PROREG, 26)); + SYMDEFS.put("r27", new Def(PROREG, 27)); + SYMDEFS.put("r28", new Def(PROREG, 28)); + SYMDEFS.put("r29", new Def(PROREG, 29)); + SYMDEFS.put("r30", new Def(PROREG, 30)); + SYMDEFS.put("r31", new Def(PROREG, 31)); + SYMDEFS.put("gp" , new Def(PROREG, Vue.GP)); + SYMDEFS.put("hp" , new Def(PROREG, Vue.HP)); + SYMDEFS.put("lp" , new Def(PROREG, Vue.LP)); + SYMDEFS.put("sp" , new Def(PROREG, Vue.SP)); + SYMDEFS.put("tp" , new Def(PROREG, Vue.TP)); // System register symbol definitions - SYMDEFS.put("adtre", 200 + Vue.ADTRE); - SYMDEFS.put("chcw" , 200 + Vue.CHCW ); - SYMDEFS.put("ecr" , 200 + Vue.ECR ); - SYMDEFS.put("eipc" , 200 + Vue.EIPC ); - SYMDEFS.put("eipsw", 200 + Vue.EIPSW); - SYMDEFS.put("fepc" , 200 + Vue.FEPC ); - SYMDEFS.put("fepsw", 200 + Vue.FEPSW); - SYMDEFS.put("pc" , Vue.PC ); - SYMDEFS.put("psw" , 200 + Vue.PSW ); - SYMDEFS.put("sr29" , 229 ); - SYMDEFS.put("sr31" , 231 ); - LITDEFS.put("pir" , 0x00005346); - LITDEFS.put("tkcw" , 0x000000E0); - LITDEFS.put("sr30" , 0x00000004); - }; + SYMDEFS.put("adtre", new Def(SYSREG, Vue.ADTRE )); + SYMDEFS.put("chcw" , new Def(SYSREG, Vue.CHCW )); + SYMDEFS.put("ecr" , new Def(SYSREG, Vue.ECR )); + SYMDEFS.put("eipc" , new Def(SYSREG, Vue.EIPC )); + SYMDEFS.put("eipsw", new Def(SYSREG, Vue.EIPSW )); + SYMDEFS.put("fepc" , new Def(SYSREG, Vue.FEPC )); + SYMDEFS.put("fepsw", new Def(SYSREG, Vue.FEPSW )); + SYMDEFS.put("pc" , new Def(SYSREG, Vue.PC )); + SYMDEFS.put("pir" , new Def(SIGNED, 0x00005346)); + SYMDEFS.put("psw" , new Def(SYSREG, Vue.PSW )); + SYMDEFS.put("tkcw" , new Def(SIGNED, 0x000000E0)); + SYMDEFS.put("sr29" , new Def(SYSREG, 29 )); + SYMDEFS.put("sr30" , new Def(SIGNED, 0x00000004)); + SYMDEFS.put("sr31" , new Def(SYSREG, 31 )); + } @@ -269,45 +370,62 @@ public class Breakpoint { // Classes // /////////////////////////////////////////////////////////////////////////// - // Operator definition - private static class OpDef { - int id; // Identifier + // Operator or value definition + private static class Def { + int id; // Operator/symbol ID or literal value int precedence; // Operator precedence - int type; // Operator category + int type; // Token category - // Constructor - OpDef(int precedence, int type, int id) { + // Default constructor + Def() { } + + // Precedence constructor + Def(int precedence, int type, int id) { this.id = id; this.precedence = precedence; this.type = type; } + // Value constructor + Def(int type, int id) { + this(0, type, id); + } + + } + + // Parsing error descriptor + public static class Error { + public final int code; // Error code + public final int position; // Character position of error + public final String text; // Offending token + + // Constructor + private Error(int code, int position, String text) { + this.code = code; + this.position = position; + this.text = text; + } + } // Expression token - private static class Token { - int id; // Operator or symbol identifier - Token left; // Left operand - Token parent; // Containing operator - int precedence; // Operator precedence - Token right; // Right operand - int start; // Character position in expression - String text; // Display text - int type; // Token category - int value; // Literal value + private static class Token extends Def { + int dataType; // Effective type at runtime + Token left; // Left node + Token parent; // Parent node + Token right; // Right node + int start; // Character position in expression + String text; // Display text // Constructor Token(int type, int start, String text) { + dataType = type == PROREG || type == SYMBOL || + type == SYSREG ? SIGNED : type; this.start = start; this.text = text; this.type = type; } - // Retrieve the applicable serialized "value" - int flatten() { - return type == FLOAT || type == WORD ? value : id; - } - } @@ -316,17 +434,16 @@ public class Breakpoint { // Constructors // /////////////////////////////////////////////////////////////////////////// - // Default constructor + // Package constructor public Breakpoint(Vue vue) { - addresses = ""; - condition = ""; - errCode = new int [] { NONE, NONE }; - errPosition = new int [] { 0, 0 }; - errText = new String[] { "", "" }; - name = ""; - ranges = new int[0][]; - tokens = new Token[0]; - this.vue = vue; + addressError = new Error(NONE, 0, ""); + addresses = ""; + condition = ""; + conditionError = new Error(NONE, 0, ""); + name = ""; + ranges = new int[0][]; + tokens = new Token[0]; + this.vue = vue; } @@ -335,118 +452,49 @@ public class Breakpoint { // Public Methods // /////////////////////////////////////////////////////////////////////////// - // Produce a string representation of the internal token list - public String debug() { - var ret = new StringBuilder(); - - // Determine the maximum width of the text fields - int max = 0; - for (var tok : tokens) - max = Math.max(max, tok.text.length()); - - // Output all tokens - var last = tokens[tokens.length - 1]; - for (var tok : tokens) { - - // Text - ret.append(String.format("%-" + max + "s ", tok.text)); - - // Type - String type = null; - switch (tok.type) { - case BINARY: type = "Binary"; break; - case FLOAT : type = "Float" ; break; - case SYMBOL: type = "Symbol"; break; - case UNARY : type = "Unary" ; break; - case WORD : type = "Word" ; break; - } - ret.append(String.format("%-6s ", type)); - - // Value or ID - switch (tok.type) { - case BINARY: // Fallthrough - case SYMBOL: // Fallthrough - case UNARY : - ret.append(Integer.toString(tok.id)); - break; - case FLOAT: - ret.append(String.format("%.6f", - Float.intBitsToFloat(tok.value))); - break; - case WORD: - ret.append(String.format( - (Math.abs(tok.value) & 0xFFFF0000) != 0 ? - "0x%08X" : "%d", tok.value)); - } - - // Advance to the next line - if (tok != last) - ret.append("\n"); - } - - return ret.toString(); - } - - // Produce a string representation of the internal address ranges - public String test() { - var ret = new StringBuilder(); - for (int x = 0; x < ranges.length; x++) { - var range = ranges[x]; - if (x > 0) - ret.append("\n"); - ret.append(String.format("%08X", range[0])); - if (range[0] != range[1]) - ret.append(String.format("-%08X", range[1])); - } - return ret.toString(); - } - - // Evaluate the condition against its emulation context + // Evaluate the condition against the emulation context public boolean evaluate() { - return vue == null ? false : vue.evaluate(this); + return vue == null || conditionError.code != NONE ? + false : tokens.length == 0 ? true : + evaluate(null, null, null) != 0; } - // Retrieve the most recent input addresses + // Retrieve the most recent address text public String getAddresses() { return addresses; } - // Retrieve the most recent input condition + // Retrieve the most recent condition text public String getCondition() { return condition; } - // Retrieve the most recent error code - public int getErrorCode(int type) { - return type < 0 || type > 1 ? BADTYPE : errCode[type]; + // Retrieve the most recent address parsing error + public Error getAddressError() { + return addressError; } - // Retrieve the most recent error character position - public int getErrorPosition(int type) { - return type < 0 || type > 1 ? BADTYPE : errPosition[type]; + // Retrieve the most recent condition parsing error + public Error getConditionError() { + return conditionError; } - // Retrieve the most recent error text - public String getErrorText(int type) { - return type < 0 || type > 1 ? null : errText[type]; - } - - // Retrieve whether the breakpoint hooks exceptions + // Determine whether the breakpoint hooks exceptions public boolean getException() { return (hooks & EXCEPTION) != 0; } - // Retrieve whether the breakpoint hooks executions + // Determine whether the breakpoint hooks executions public boolean getExecute() { return (hooks & EXECUTE) != 0; } - // Retrieve whether the breakpoint hooks reads + // Determine whether the breakpoint hooks reads public boolean getRead() { return (hooks & READ) != 0; } - // Retrieve whether the breakpoint hooks writes + // Determine whether the breakpoint hooks writes public boolean getWrite() { return (hooks & WRITE) != 0; } @@ -513,9 +561,7 @@ public class Breakpoint { // Could not parse the address catch (Exception e) { - errCode [ADDRESS] = BADLITERAL; - errPosition[ADDRESS] = start + 1; - errText [ADDRESS] = text; + addressError = new Error(BADLITERAL, start + 1, text); if (vue != null) vue.updateRanges(this); return false; @@ -563,9 +609,7 @@ public class Breakpoint { } // Invalid character - errCode [ADDRESS] = UNEXPECTED; - errPosition[ADDRESS] = x + 1; - errText [ADDRESS] = Character.toString(c); + addressError = new Error(UNEXPECTED, x + 1, Character.toString(c)); if (vue != null) vue.updateRanges(this); return false; @@ -573,9 +617,7 @@ public class Breakpoint { // Unexpected end of input if (mode == 0 && ranges.size() > 0) { - errCode [ADDRESS] = EARLYEOF; - errPosition[ADDRESS] = x + 1; - errText [ADDRESS] = ""; + addressError = new Error(EARLYEOF, x + 1, ""); if (vue != null) vue.updateRanges(this); return false; @@ -587,9 +629,7 @@ public class Breakpoint { // Parsing was successful this.ranges = ranges.toArray(new int[ranges.size()][]); - errCode [ADDRESS] = NONE; - errPosition[ADDRESS] = 0; - errText [ADDRESS] = ""; + addressError = new Error(NONE, 0, ""); if (vue != null) vue.updateRanges(this); return true; @@ -600,13 +640,12 @@ public class Breakpoint { // Configure instance fields this.condition = condition == null ? condition = "" : condition; - errCode [CONDITION] = NONE; - errPosition[CONDITION] = 0; - errText [CONDITION] = ""; - tokens = new Token[0]; + conditionError = new Error(NONE, 0, ""); + depth = 0; + tokens = new Token[0]; // Process the expression - var tokens = parse(); + var tokens = parseTokens(); if (tokens == null || !validate(tokens)) { if (vue != null) vue.updateTokens(this); @@ -614,15 +653,16 @@ public class Breakpoint { } tree(tokens); - // The expression is empty - if (tokens.size() == 0) { + // Perform operator-specific pre-processing on the expression + Token tok = tokens.size() == 0 ? null : transform(tokens.remove(0)); + if (conditionError.code != NONE) { if (vue != null) vue.updateTokens(this); - return true; + return false; } // Produce an RPN-ordered list of tokens - var tok = tokens.remove(0); + dataType = tok == null ? BOOL : tok.dataType; while (tok != null) { // Traverse to left child node @@ -646,6 +686,7 @@ public class Breakpoint { this.tokens = tokens.toArray(new Token[tokens.size()]); // The expression was successfully parsed + depth = depth(); if (vue != null) vue.updateTokens(this); return true; @@ -697,56 +738,77 @@ public class Breakpoint { // Package Methods // /////////////////////////////////////////////////////////////////////////// - // Evaluate the condition for a Java emulation context - boolean evaluate(int[] stack) { - - // The condition is empty + // Cast a value to the condition evaluation's data type + Object cast(int value) { + if (conditionError.code != NONE) + return conditionError; if (tokens.length == 0) - return isEnabled && errCode[CONDITION] == NONE; - - // Process tokens - int size = 0; - for (var tok : tokens) { - switch (tok.type) { - case BINARY: size = - evalBinary(tok.id, stack, size); continue; - case SYMBOL: size = - evalSymbol(tok.id, stack, size); continue; - case UNARY : - evalUnary (tok.id, stack, size); continue; - } - stack[size++] = tok.type; - stack[size++] = tok.value; + return null; + switch (dataType) { + case BOOL : return (Boolean) (value != 0); + case FLOAT : return (Float ) Float.intBitsToFloat(value); + case UNSIGNED: return (Long ) (value & 0xFFFFFFFFL); } - return (stack[1] & (stack[0] == WORD ? 0xFFFFFFFF : 0x7FFFFFFF)) != 0; + return (Integer) value; } - // Determine the required stack size to evaluate the expression - int depth() { + // Evaluate the condition, returning only the computed value + int evaluate(int[] stack, Instruction inst, Access acc) { // Error checking - if (errCode[CONDITION] != NONE) + if (conditionError.code != NONE) return 0; + if (tokens.length == 0) + return 1; + if (stack == null) + stack = new int[depth]; - // Count the maximum size of the stack - int max = 0; + // Process all tokens int size = 0; for (var tok : tokens) switch (tok.type) { - case BINARY: size--; break; - case FLOAT : // Fallthrough - case SYMBOL: // Fallthrough - case WORD : max = Math.max(max, ++size); + + // Binary operator + case BINARY: + stack[size - 2] = + evalBinary(tok.id, stack[size - 2], stack[size - 1]); + break; + + // Literal + case BOOL: + case FLOAT: + case SIGNED: + case UNSIGNED: + stack[size++] = tok.id; + break; + + // CPU register + case PROREG: + case SYSREG: + stack[size++] = vue.getRegister(tok.id, tok.type == SYSREG); + break; + + // Symbol + case SYMBOL: + stack[size++] = 0; + break; + + // Unary operator + case UNARY: + stack[size - 1] = evalUnary(tok.id, stack[size - 1]); + break; } - return max; + + // Return the remaining stack value + return stack[0]; } // Produce a one-dimensional array from the address ranges int[] flattenRanges() { var ret = new int[ranges.length * 2]; - for (int x = 0; x < ranges.length; x++) { + for (int x = 0, y = 0; x < ranges.length; x++) { var range = ranges[x]; - ret[x / 2 ] = range[0]; - ret[x / 2 + 1] = range[1]; + ret[y++] = range[0]; + ret[y++] = range[1]; } return ret; } @@ -754,14 +816,19 @@ public class Breakpoint { // Produce a one-dimensional array from the condition tokens int[] flattenTokens() { var ret = new int[tokens.length * 2]; - for (int x = 0; x < tokens.length; x++) { + for (int x = 0, y = 0; x < tokens.length; x++) { var token = tokens[x]; - ret[x / 2 ] = token.type; - ret[x / 2 + 1] = token.flatten(); + ret[y++] = token.type; + ret[y++] = token.id; } return ret; } + // Retrieve the required condition evaluation stack size + int getDepth() { + return depth; + } + // Retrieve the bit mask for enabled hooks int getHooks() { return hooks; @@ -785,23 +852,188 @@ public class Breakpoint { /////////////////////////////////////////////////////////////////////////// - // Private Methods // + // Condition Methods // /////////////////////////////////////////////////////////////////////////// - // Adjust a float value as needed - private static float fixFloat(float value) { - int bits = Float.floatToRawIntBits(value); - int exp = bits & 0x7F800000; - int digits = bits & 0x007FFFFF; - return - (bits & 0x7FFFFFFF) == 0 || // Zero - exp == 0x7F800000 || // Indefinite - exp == 0 && digits != 0 // Denormal - ? 0 : value; + // Determine whether a token is a literal + private static boolean isLiteral(Token tok) { + switch (tok.type) { + case BOOL: + case FLOAT: + case SIGNED: + case UNSIGNED: return true; + } + return false; } - // Parse a condition into tokens - private ArrayList parse() { + // Remove a token from a tree + private static Token remove(Token tok) { + if (tok.parent != null) { + if (tok.parent.left == tok) + tok.parent.left = tok.right; + else tok.parent.right = tok.right; + } + tok.right.parent = tok.parent; + return tok.right; + } + + // Parse a literal + private Token parseLiteral(char[] chars, int start) { + boolean isFloat = chars[start] == '.'; // The figure is a float + boolean isHex = false; // The figure is in hexadecimal + + // Process through the end of the expression + for (int x = start + 1; x < chars.length; x++) { + char c = chars[x]; + + // The literal begins with "0x" + if (c == 'x' || c == 'X') { + + // "x" cannot appear here + if (isFloat || x != start + 1 || chars[start] != '0') { + conditionError = + new Error(UNEXPECTED, x + 1, Character.toString(c)); + return null; + } + + // Configure as a hexadecimal integer + isHex = true; + continue; + } + + // The literal contains "." + if (c == '.') { + + // "." cannot appear here + if (isHex || isFloat) { + conditionError = + new Error(UNEXPECTED, x + 1, Character.toString(c)); + return null; + } + + // Configure as a float + isFloat = true; + continue; + } + + // The character is part of the token + if ( + c >= '0' && c <= '9' || + isHex && (c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F') + ) continue; + + // Produce a new token + var ret = new Token(SIGNED, start, + new String(chars, start, x - start)); + + // Parse the literal value + try { + if (isFloat) { + ret.dataType = ret.type = FLOAT; + ret.id = Float.floatToRawIntBits( + adjust(Float.parseFloat(ret.text))); + } else { + long val = !isHex ? Long.parseLong(ret.text) : + Long.parseLong(ret.text.substring(2), 16); + if (val >= 0x80000000L && val <= 0xFFFFFFFFL) + ret.dataType = ret.type = UNSIGNED; + else if (val < 0x80000000 || val > 0x7FFFFFFF) + throw new Exception(); + ret.id = (int) val; + } + return ret; + } + + // Could not parse the value + catch (Exception e) { + conditionError = new Error(BADLITERAL, ret.start+1, ret.text); + return null; + } + + } // x + + return null; // Unreachable + } + + // Parse an operator + private Token parseOperator(char[] chars, int start) { + int x; // Iterator + + // Locate the entire potential token + for (x = start + 1; x < chars.length; x++) { + char c = chars[x]; + if ( + c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == ' ' || c == '\t' + ) break; + } // x + + // Find the longest operator within the token + for (int y = x; y > start; y--) { + String text = new String(chars, start, y - start); + var def = OPDEFS.get(text); + + // An operator was found + if (def != null) { + var ret = new Token(def.type, start, text); + ret.id = def.id; + ret.precedence = def.precedence; + return ret; + } + + } // y + + // No operator was identified + conditionError = new Error(BADTOKEN, start + 1, + new String(chars, start, x - start)); + return null; + } + + // Parse a symbol (which may be an operator) + private Token parseSymbol(char[] chars, int start) { + + // Process through the end of the expression + for (int x = start + 1; x < chars.length; x++) { + char c = chars[x]; + + // The character is part of the token + if ( + c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == '_' || c == '.' + ) continue; + + // Produce a new token + var ret = new Token(SYMBOL, start, + new String(chars, start, x - start)); + String text = ret.text.toLowerCase(); + + // The token is an operator or symbol + var def = OPDEFS .get(text); + if (def == null) + def = SYMDEFS.get(text); + if (def != null) { + ret.id = def.id; + ret.precedence = def.precedence; + ret.type = def.type; + if (def.type <= FLOAT) + ret.dataType = def.type; + return ret; + } + + // The token is not recognized + conditionError = new Error(BADTOKEN, ret.start + 1, ret.text); + return null; + } // x + + return null; // Unreachable + } + + // Parse condition text into tokens + private ArrayList parseTokens() { var tokens = new ArrayList(); // Parse the expression @@ -834,184 +1066,265 @@ public class Breakpoint { return tokens; } - // Parse a literal - private Token parseLiteral(char[] chars, int start) { - boolean isFloat = chars[start] == '.'; // The figure is a float - boolean isHex = false; // The figure is in hexadecimal + // Perform implicit pre-processing operations + private Token transform(Token tok) { + var err = new Error(BADOPERAND, tok.start + 1, tok.text); - // Process through the end of the expression - for (int x = start + 1; x < chars.length; x++) { - char c = chars[x]; + // Transform child tokens + if ( + tok.left != null && (tok.left = transform(tok.left )) == null || + tok.right != null && (tok.right = transform(tok.right)) == null + ) return null; - // The literal begins with "0x" - if (c == 'x' || c == 'X') { + // Unary operators + if (tok.type == UNARY) { + int id = tok.id; + boolean literal = isLiteral(tok.right); + int newType = -1; + tok.dataType = tok.right.dataType; + tok.id = -tok.id * 4 + tok.dataType; - // "x" cannot appear here - if (isFloat || x != start + 1 || chars[start] != '0') { - errCode [CONDITION] = UNEXPECTED; - errPosition[CONDITION] = x + 1; - errText [CONDITION] = Character.toString(c); + // Process by ID + switch (id) { + + // Cast to Boolean + case BOOL_: + if (tok.right.dataType == BOOL) + return remove(tok); + newType = BOOL; + break; + + // Round Up + case CEIL: + if (tok.right.dataType != FLOAT) + return remove(tok); + break; + + // Cast to Float + case FLOAT_: + if (tok.right.dataType == FLOAT) + return remove(tok); + if (tok.right.type == UNARY && tok.right.id == READ32) + tok.id = id = XFLOAT; + newType = FLOAT; + break; + + // Round Down + case FLOOR: + if (tok.right.dataType != FLOAT) + return remove(tok); + break; + + // Negate + case NEGATE: + if (tok.right.dataType != UNSIGNED) + break; + conditionError = err; return null; - } - // Configure as a hexadecimal integer - isHex = true; - continue; - } - - // The literal contains "." - if (c == '.') { - - // "." cannot appear here - if (isHex || isFloat) { - errCode [CONDITION] = UNEXPECTED; - errPosition[CONDITION] = x + 1; - errText [CONDITION] = Character.toString(c); + // Not Bitwise + case NOT_B: + if (tok.right.dataType != FLOAT) + break; + conditionError = err; return null; - } - // Configure as a float - isFloat = true; - continue; + // Not Logical + case NOT_L: + newType = BOOL; + break; + + // Round to Nearest + case ROUND: + if (tok.right.dataType != FLOAT) + return remove(tok); + break; + + // Cast to Signed Byte + case S8: + if (tok.right.type == UNARY && tok.right.id == READ32) + tok.right.id = READ8; + newType = SIGNED; + break; + + // Cast to Signed Halfword + case S16: + if (tok.right.type == UNARY && tok.right.id == READ32) + tok.right.id = READ16; + newType = SIGNED; + break; + + // Cast to Signed Word + case S32: + newType = SIGNED; + break; + + // Truncate + case TRUNC: + if (tok.right.dataType != FLOAT) + return remove(tok); + break; + + // Cast to Unsigned Byte + case U8: + if (tok.right.type == UNARY && tok.right.id == READ32) + tok.right.id = READ8; + newType = UNSIGNED; + break; + + // Cast to Unsigned Halfword + case U16: + if (tok.right.type == UNARY && tok.right.id == READ32) + tok.right.id = READ16; + newType = UNSIGNED; + break; + + // Cast to Unsigned Word + case U32: + newType = UNSIGNED; + break; + + // Reinterpret as Signed Word + case XS32: + tok.right.dataType = SIGNED; + return remove(tok); + + // Reinterpret as Unsigned Word + case XU32: + tok.right.dataType = UNSIGNED; + return remove(tok); + + // Reinterpret as Float + case XFLOAT: + newType = FLOAT; + break; } - // The character is part of the token - if ( - c >= '0' && c <= '9' || - isHex && (c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F') - ) continue; - - // Produce a new token - var ret = new Token(WORD, start, - new String(chars, start, x - start)); - - // Parse the literal value - try { - if (isHex) ret.value = (int) - Long.parseLong(ret.text.substring(2), 16); - else if (isFloat) { - ret.type = FLOAT; - ret.value = Float.floatToRawIntBits( - fixFloat(Float.parseFloat(ret.text))); - } else ret.value = Integer.parseInt(ret.text); - return ret; + // The operand is not a literal + if (!literal) { + if (newType != -1) + tok.dataType = newType; + return tok; } - // Could not parse the value - catch (Exception e) { - errCode [CONDITION] = BADLITERAL; - errPosition[CONDITION] = x + 1; - errText [CONDITION] = ret.text; - return null; + // Pre-process the literal operand + tok.right.id = evalUnary(id, tok.right); + if (newType != -1) + tok.right.type = tok.right.dataType = newType; + return remove(tok); + } + + // Binary operators + if (tok.type == BINARY) { + int id = tok.id; + boolean literal = isLiteral(tok.left) && isLiteral(tok.right); + tok.dataType = Math.max(tok.left.dataType, tok.right.dataType); + tok.id = -id * 4 + tok.dataType; + + // Process by ID + switch (id) { + + // Boolean logical operations + case EQUAL : // Equal + case GREATER: // Greater + case GREQUAL: // Greater or Equal + case LEQUAL : // Less or Equal + case LESS : // Less + case NEQUAL : // Not Equal + tok.dataType = BOOL; + break; + + // Non-boolean logical operations + case AND_L: // And Logical + case OR_L : // Or Logical + case XOR_L: // Exclusive Or Logical + break; + + // Bitwise operations + case AND_B : // And Bitwise + case LEFT_L : // Shift Left + case OR_B : // Or Bitwise + case RIGHT_A: // Shift Right Arithmetic + case RIGHT_L: // Shift Right Logical + case XOR_B : // Exclusive Or Bitwise + if (tok.dataType == FLOAT) { + conditionError = err; + return null; + } + // Fallthrough + + // Arithmetic operations + case ADD : // Add + case DIVIDE : // Divide + case MULTIPLY : // Multiply + case REMAINDER: // Remainder + case SUBTRACT : // Subtract + if (tok.dataType == BOOL) + tok.dataType = SIGNED; + break; } - } // x + // Convert operands + for (int op = 0; op < 2; op++) { + var top = op == 0 ? tok.left : tok.right; - return null; // Unreachable - } - - // Parse an operator - private Token parseOperator(char[] chars, int start) { - - // Process through the end of the expression - for (int x = start + 1; x < chars.length; x++) { - char c = chars[x]; - - // The character could be part of the token - if (!( - c >= 'a' && c <= 'z' || - c >= 'A' && c <= 'Z' || - c >= '0' && c <= '9' || - c == ' ' || c == '\t' - )) continue; - - // Produce a new token - var ret = new Token(0, start, null); - - // Find the longest operator match - for (int length = x - start; length >= 1; length--) { - String text = new String(chars, start, length); - var def = OPDEFS.get(text); - - // There is no matching operator - if (def == null) + // The operand is already the result type + if (top.dataType == tok.dataType) continue; - // A matching operator was found - ret.id = def.id; - ret.precedence = def.precedence; - ret.text = text; - ret.type = def.type; - return ret; + // Select the ID of the conversion operation + int cvt = 0; + switch (tok.dataType) { + case BOOL : cvt = BOOL_ ; break; + case FLOAT : cvt = FLOAT_; break; + case SIGNED : cvt = S32 ; break; + case UNSIGNED: cvt = U32 ; break; + } + + // Convert the literal operand directly + if (isLiteral(top)) { + top.id = evalUnary(cvt, top); + top.type = top.dataType = tok.dataType; + } + + // Insert a conversion token + else { + var imp = new Token(UNARY, -1, ""); + switch (tok.dataType) { + case BOOL : imp.text = "bool" ; break; + case FLOAT : imp.text = "float"; break; + case SIGNED : imp.text = "s32" ; break; + case UNSIGNED: imp.text = "u32" ; break; + } + imp.dataType = tok.dataType; + imp.id = -cvt * 4 + top.dataType; + imp.parent = tok; + imp.right = top; + top.parent = imp; + top = imp; + } + + // Common processing + if (op == 0) + tok.left = top; + else tok.right = top; } - // The operator was not identified - errCode [CONDITION] = BADTOKEN; - errPosition[CONDITION] = start + 1; - errText [CONDITION] = Character.toString(chars[start]); - return null; - } // x - - return null; // Unreachable - } - - // Parse a symbol (which may be an operator) - private Token parseSymbol(char[] chars, int start) { - - // Process through the end of the expression - for (int x = start + 1; x < chars.length; x++) { - char c = chars[x]; - - // The character is part of the token - if ( - c >= 'a' && c <= 'z' || - c >= 'A' && c <= 'Z' || - c >= '0' && c <= '9' || - c == '_' || c == '.' - ) continue; - - // Produce a new token - var ret = new Token(SYMBOL, start, - new String(chars, start, x - start)); - String text = ret.text.toLowerCase(); - - // The token is an operator - var def = OPDEFS.get(text); - if (def != null) { - ret.id = def.id; - ret.precedence = def.precedence; - ret.type = def.type; - return ret; + // Common processing + if (literal) { + tok.type = tok.dataType; + tok.id = evalBinary(tok.id, tok.left.id, tok.right.id); + tok.left = tok.right = null; } + return tok; + } - // The token is a literal - Integer value = LITDEFS.get(text); - if (value != null) { - ret.type = WORD; - ret.value = value; - return ret; - } - - // The token is a symbol - value = SYMDEFS.get(text); - if (value != null) { - ret.id = value; - ret.type = SYMBOL; - return ret; - } - - // The token is not recognized - errCode [CONDITION] = BADTOKEN; - errPosition[CONDITION] = x + 1; - errText [CONDITION] = ret.text; - return null; - } // x - - return null; // Unreachable + // Value token + return tok; } // Build an expression tree from a list of tokens - private void tree(ArrayList tokens) { + private static void tree(ArrayList tokens) { // Process all operators while (tokens.size() > 1) { @@ -1067,9 +1380,9 @@ public class Breakpoint { // Apply the group operators tokens.remove(end + 1); - if (tokens.remove(start - 1).id == READ_WORD) { - var tok = new Token(UNARY, 0, "{Read Word}"); - tok.id = READ_WORD; + if (tokens.remove(start - 1).id == READ32) { + var tok = new Token(UNARY, -1, "[]"); + tok.id = READ32; tok.right = tokens.remove(start - 1); tok.right.parent = tok; tokens.add(start - 1, tok); @@ -1092,9 +1405,7 @@ public class Breakpoint { // The token is invalid if (tok.id != NEGATE) { - errCode [CONDITION] = INVALID; - errPosition[CONDITION] = tok.start; - errText [CONDITION] = tok.text; + conditionError = new Error(INVALID, tok.start+1, tok.text); return false; } @@ -1107,9 +1418,7 @@ public class Breakpoint { // Nesting error if (tok.type == CLOSE && (stack.empty() || stack.pop().id != tok.id)) { - errCode [CONDITION] = NESTING; - errPosition[CONDITION] = tok.start; - errText [CONDITION] = tok.text; + conditionError = new Error(NESTING, tok.start + 1, tok.text); return false; } @@ -1122,11 +1431,11 @@ public class Breakpoint { continue; } - // A group was not closed - if (!stack.empty()) { - errCode [CONDITION] = EARLYEOF; - errPosition[CONDITION] = condition.length(); - errText [CONDITION] = stack.pop().text; + // A group was not closed, or a binary operation was incomplete + if (!stack.empty() || mode == 0) { + conditionError = + new Error(EARLYEOF, condition.length(), ""); + return false; } // Successfully parsed the condition @@ -1135,540 +1444,548 @@ public class Breakpoint { + /////////////////////////////////////////////////////////////////////////// + // Private Methods // + /////////////////////////////////////////////////////////////////////////// + + // Adjust a float value as needed + private static float adjust(float value) { + int bits = Float.floatToRawIntBits(value); + int exp = bits & 0x7F800000; + return + (bits & 0x7FFFFFFF) == 0 || // Zero + exp == 0x7F800000 || // Indefinite + exp == 0 // Denormal + ? 0 : value; + } + + // Determine the required stack size to evaluate the expression + private int depth() { + + // Error checking + if (conditionError.code != NONE) + return 0; + + // Count the maximum size of the stack + int max = 0; + int size = 0; + for (var tok : tokens) switch (tok.type) { + case BINARY: size--; break; + case UNARY : break; + default : max = Math.max(max, ++size); + } + return max; + } + + // Remove the fraction part of a float + private static float trunc(float x) { + return (float) (x < 0 ? Math.ceil(x) : Math.floor(x)); + } + + + + /////////////////////////////////////////////////////////////////////////// + // Debugging Methods // + /////////////////////////////////////////////////////////////////////////// + + // Produce a string representation of the condition token list + public String debugTokens() { + var ret = new StringBuilder(); + + // The condition was not successfully parsed + if (conditionError.code != NONE) + return "Error"; + + // Determine the maximum width of the text fields + int max = 0; + for (var tok : tokens) + max = Math.max(max, tok.text.length()); + + // Output all tokens + var last = tokens[tokens.length - 1]; + for (var tok : tokens) { + + // Text + ret.append(String.format("%-" + max + "s ", tok.text)); + + // Type + String type = null; + switch (tok.type) { + case BINARY : type = "Binary" ; break; + case BOOL : type = "Bool" ; break; + case FLOAT : type = "Float" ; break; + case PROREG : type = "ProReg" ; break; + case SYSREG : type = "SysReg" ; break; + case SIGNED : type = "Signed" ; break; + case SYMBOL : type = "Symbol" ; break; + case UNARY : type = "Unary" ; break; + case UNSIGNED: type = "Unsigned"; break; + default: type = Integer.toString(tok.type); + } + ret.append(String.format("%-8s ", type)); + + // Data type + switch (tok.dataType) { + case BOOL : type = "Bool" ; break; + case FLOAT : type = "Float" ; break; + case SIGNED : type = "Signed" ; break; + case UNSIGNED: type = "Unsigned"; break; + default: type = Integer.toString(tok.dataType); + } + ret.append(String.format("%-8s ", type)); + + // Operator + if (tok.type == BINARY || tok.type == UNARY) { + String id = Integer.toString(tok.id); + switch (-tok.id / 4) { + case 0 : id = "REINTERPRET"; break; + case READ8 : id = "READ8" ; break; + case READ16 : id = "READ16" ; break; + case READ32 : id = "READ32" ; break; + case ADD : id = "ADD" ; break; + case AND_B : id = "AND_B" ; break; + case AND_L : id = "AND_L" ; break; + case BOOL_ : id = "BOOL_" ; break; + case CEIL : id = "CEIL" ; break; + case DIVIDE : id = "DIVIDE" ; break; + case EQUAL : id = "EQUAL" ; break; + case FLOAT_ : id = "FLOAT_" ; break; + case FLOOR : id = "FLOOR" ; break; + case GREATER : id = "GREATER" ; break; + case GREQUAL : id = "GREQUAL" ; break; + case LEFT_L : id = "LEFT_L" ; break; + case LEQUAL : id = "LEQUAL" ; break; + case LESS : id = "LESS" ; break; + case MULTIPLY : id = "MULTIPLY" ; break; + case NEQUAL : id = "NEQUAL" ; break; + case NOT_B : id = "NOT_B" ; break; + case NOT_L : id = "NOT_L" ; break; + case NEGATE : id = "NEGATE" ; break; + case OR_B : id = "OR_B" ; break; + case OR_L : id = "OR_L" ; break; + case REMAINDER: id = "REMAINDER" ; break; + case RIGHT_A : id = "RIGHT_A" ; break; + case RIGHT_L : id = "RIGHT_L" ; break; + case ROUND : id = "ROUND" ; break; + case S8 : id = "S8" ; break; + case S16 : id = "S16" ; break; + case S32 : id = "S32" ; break; + case SUBTRACT : id = "SUBTRACT" ; break; + case TRUNC : id = "TRUNC" ; break; + case U8 : id = "U8" ; break; + case U16 : id = "U16" ; break; + case U32 : id = "U32" ; break; + case XFLOAT : id = "XFLOAT" ; break; + case XOR_B : id = "XOR_B" ; break; + case XOR_L : id = "XOR_L" ; break; + case XS32 : id = "XS32" ; break; + case XU32 : id = "XU32" ; break; + default: ret.append(Integer.toString(tok.id)); + } + ret.append(String.format("%-11s", id)); + } + + // Symbol or literal + else switch (tok.type) { + case PROREG: + case SYSREG: + case SYMBOL: + ret.append(Integer.toString(tok.id)); + break; + case FLOAT: + ret.append(String.format("%.6f", + Float.intBitsToFloat(tok.id))); + break; + case BOOL: + case SIGNED: + ret.append(Integer.toString(tok.id)); + break; + case UNSIGNED: + ret.append(Long.toString(tok.id & 0xFFFFFFFFL)); + break; + default: ret.append("Error"); + } + + // Advance to the next line + if (tok != last) + ret.append("\n"); + } + + return ret.toString(); + } + + // Produce a string representation of the internal address ranges + public String debugRanges() { + var ret = new StringBuilder(); + + // The address ranges were not successfully parsed + if (addressError.code != NONE) + return "Error"; + + // Process ranges + for (int x = 0; x < ranges.length; x++) { + var range = ranges[x]; + if (x > 0) + ret.append("\n"); + ret.append(String.format("%08X", range[0])); + if (range[0] != range[1]) + ret.append(String.format("-%08X", range[1])); + } + return ret.toString(); + } + + + /////////////////////////////////////////////////////////////////////////// // Evaluation Methods // /////////////////////////////////////////////////////////////////////////// - // Resolve a float from word bits - private static float asFloat(int value) { - return Float.intBitsToFloat(value); - } - - // Resolve the word bits of a float - private static int asWord(float value) { - return Float.floatToRawIntBits(fixFloat(value)); - } - - // Convert an unsigned word to a float - private static float ufloat(int value) { - return (float) (value & 0xFFFFFFFFL); - } - - // Convert a float to a word - private static int toWord(float value) { - value = (float) Math.round(value); - return value >= 0x7FFFFFFF || value < 0x80000000 ? 0 : (int) value; - } - - // Evaluate a binary operator - private static int evalBinary(int id, int[] stack, int size) { - int rv = stack[size - 1]; - int rt = stack[size - 2]; - boolean rw = rt == WORD; - int lv = stack[size - 3]; - int lt = stack[size - 4]; - boolean lw = lt == WORD; - int type = rw && lw ? WORD : FLOAT; - int 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 - private int evalSymbol(int id, int[] stack, int size) { - int ret = 0; - var vue = (JavaVue) this.vue; - if (id == Vue.PC) - ret = vue.cpu.pc; - else if (id >= 200) - ret = vue.cpu.getSystemRegister(id - 200); - else if (id >= 100) - ret = vue.cpu.program[id - 100]; - else if (vue.cpu.stage == CPU.EXCEPTION && id == CODE) - ret = vue.cpu.exception.code; - else if (vue.cpu.stage == CPU.EXECUTE) switch (id) { - case ADDRESS : ret = evalAddress (); break; - case COND : ret = evalCond (); break; - case DISP : ret = evalDisp (); break; - case FORMAT : ret = vue.cpu.inst.format; break; - case ID : ret = vue.cpu.inst.id ; break; - case IMM : ret = evalImm (); break; - case OPCODE : ret = vue.cpu.inst.opcode; break; - case REG1 : ret = evalReg1 (); break; - case REG2 : ret = evalReg2 (); break; - case REGID : ret = evalRegId (); break; - case SIZE : ret = vue.cpu.inst.size ; break; - case SUBOPCODE: ret = evalSubopcode (); break; - case VALUE : ret = evalValue (); break; - case VECTOR : ret = evalVector (); break; - } - stack[size++] = WORD; - stack[size++] = ret; - return size; + // Evaluate a unary operator given a token + private int evalUnary(int id, Token tok) { + return evalUnary(-id * 4 + tok.dataType, tok.id); } // Evaluate a unary operator - private void evalUnary(int id, int[] stack, int size) { - int type = stack[size - 2]; - int value = stack[size - 1]; - boolean isWord = type == WORD; + private int evalUnary(int id, int operand) { + + // Processing by ID 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); - 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; + + // Cast to Boolean + case -BOOL_ * 4 + BOOL: // Removed by parser + case -BOOL_ * 4 + FLOAT: + case -BOOL_ * 4 + SIGNED: + case -BOOL_ * 4 + UNSIGNED: + return operand == 0 ? 0 : 1; + + // Round up + case -CEIL * 4 + BOOL: // Removed by parser + case -CEIL * 4 + FLOAT: + case -CEIL * 4 + SIGNED: // Removed by parser + case -CEIL * 4 + UNSIGNED: // Removed by parser + return Float.floatToIntBits(adjust((float) + Math.ceil(Float.intBitsToFloat(operand)))); + + // Cast to Float + case -FLOAT_ * 4 + BOOL: + case -FLOAT_ * 4 + FLOAT: // Removed by parser + case -FLOAT_ * 4 + SIGNED: + return Float.floatToIntBits(adjust(operand)); + case -FLOAT_ * 4 + UNSIGNED: + return Float.floatToIntBits(adjust(operand & 0xFFFFFFFFL)); + + // Round down + case -FLOOR * 4 + BOOL: // Removed by parser + case -FLOOR * 4 + FLOAT: + case -FLOOR * 4 + SIGNED: // Removed by parser + case -FLOOR * 4 + UNSIGNED: // Removed by parser + return Float.floatToIntBits(adjust((float) + Math.floor(Float.intBitsToFloat(operand)))); + + // Bitwise Not + case -NOT_B * 4 + BOOL: + case -NOT_B * 4 + FLOAT: // Prevented by parser + case -NOT_B * 4 + SIGNED: + case -NOT_B * 4 + UNSIGNED: + return ~operand; + + // Logical Not + case -NOT_L * 4 + BOOL: + case -NOT_L * 4 + FLOAT: + case -NOT_L * 4 + SIGNED: + case -NOT_L * 4 + UNSIGNED: + return operand == 0 ? 1 : 0; + + // Negate + case -NEGATE * 4 + BOOL: + case -NEGATE * 4 + SIGNED: + case -NEGATE * 4 + UNSIGNED: // Removed by parser + return -operand; + case -NEGATE * 4 + FLOAT: + return Float.floatToIntBits(adjust( + -Float.intBitsToFloat(operand))); + + // Read Byte + case READ8: + return vue.read(operand, Vue.S8); + + // Read Halfword + case READ16: + return vue.read(operand, Vue.S16); + + // Read Word + case READ32: + return vue.read(operand, Vue.S32); + + // Round to Nearest + case -ROUND * 4 + BOOL: // Removed by parser + case -ROUND * 4 + FLOAT: + case -ROUND * 4 + SIGNED: // Removed by parser + case -ROUND * 4 + UNSIGNED: // Removed by parser + return Float.floatToIntBits(adjust((float) + Math.round(Float.intBitsToFloat(operand)))); + + // Cast to Signed Byte + case -S8 * 4 + FLOAT: + operand = evalUnary(-S32 * 4 + FLOAT, operand); + // Fallthrough + case -S8 * 4 + BOOL: + case -S8 * 4 + SIGNED: + case -S8 * 4 + UNSIGNED: + return operand << 24 >> 24; + + // Cast to Signed Halfword + case -S16 * 4 + FLOAT: + operand = evalUnary(-S32 * 4 + FLOAT, operand); + // Fallthrough + case -S16 * 4 + BOOL: + case -S16 * 4 + SIGNED: + case -S16 * 4 + UNSIGNED: + return operand << 24 >> 24; + + // Cast to Signed Word + case -S32 * 4 + BOOL: + case -S32 * 4 + SIGNED: // Removed by parser + case -S32 * 4 + UNSIGNED: + return operand; + case -S32 * 4 + FLOAT: + float val = Float.intBitsToFloat(operand); + return val >= -MAX_WORD && val < MAX_WORD ? (int) val : 0; + + // Truncate + case -TRUNC * 4 + BOOL: // Removed by parser + case -TRUNC * 4 + FLOAT: + case -TRUNC * 4 + SIGNED: // Removed by parser + case -TRUNC * 4 + UNSIGNED: // Removed by parser + return Float.floatToIntBits(adjust( + trunc(Float.intBitsToFloat(operand)))); + + // Cast to Unsigned Byte + case -U8 * 4 + FLOAT: + operand = evalUnary(-S32 * 4 + FLOAT, operand); + case -U8 * 4 + BOOL: + case -U8 * 4 + SIGNED: + case -U8 * 4 + UNSIGNED: + return operand << 24 >>> 24; + + // Cast to Unsigned Halfword + case -U16 * 4 + FLOAT: + operand = evalUnary(-S32 * 4 + FLOAT, operand); + case -U16 * 4 + BOOL: + case -U16 * 4 + SIGNED: + case -U16 * 4 + UNSIGNED: + return operand << 16 >>> 16; + + // Cast to Unsigned Word + case -U32 * 4 + BOOL: + case -U32 * 4 + SIGNED: + case -U32 * 4 + UNSIGNED: // Removed by parser + return operand; + case -U32 * 4 + FLOAT: + float va1 = Float.intBitsToFloat(operand); + return va1 >= 0 && va1 < MAX_UWORD ? (int) (long) va1 : 0; + + // Reinterpret as Float + case XFLOAT: + return Float.floatToIntBits(adjust( + Float.intBitsToFloat(operand))); + + // Reinterpret as Signed Word, Reinterpret as Unsigned Word + case XS32: // Removed by parser + case XU32: // Removed by parser } - stack[size - 2] = type; - stack[size - 1] = value; - } - - - /////////////////////////////////////////////////////////////////////////// - // Binary Methods // - /////////////////////////////////////////////////////////////////////////// - - // Evaluate + - private static int evalAdd( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return leftWord && rightWord ? leftValue + rightValue : asWord( - (leftWord ? (float) leftValue : asFloat(leftValue )) + - (rightWord ? (float) rightValue : asFloat(rightValue)) - ); - } - - // Evaluate & - private static int evalBitwiseAnd( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return (leftWord ? leftValue : toWord(asFloat(leftValue ))) & - (rightWord ? rightValue : toWord(asFloat(rightValue))); - } - - // Evaluate | - private static int evalBitwiseOr( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return (leftWord ? leftValue : toWord(asFloat(leftValue ))) | - (rightWord ? rightValue : toWord(asFloat(rightValue))); - } - - // Evaluate ^ - private static int evalBitwiseXOr( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return (leftWord ? leftValue : toWord(asFloat(leftValue ))) ^ - (rightWord ? rightValue : toWord(asFloat(rightValue))); - } - - // Evaluate / - private static int evalDivide( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return (rightWord ? rightValue : rightValue & 0x7FFFFFFF) == 0 ? 0 : - leftWord && rightWord ? leftValue / rightValue : asWord( - (leftWord ? (float) leftValue : asFloat(leftValue )) / - (rightWord ? (float) rightValue : asFloat(rightValue)) - ); - } - - // Evaluate == - private static int evalEqual( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return (leftWord && rightWord ? leftValue == rightValue : ( - (leftWord ? (float) leftValue : asFloat(leftValue )) == - (rightWord ? (float) rightValue : asFloat(rightValue)) - )) ? 1 : 0; - } - - // Evaluate >= - private static int evalGreaterEqualSigned( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return (leftWord && rightWord ? leftValue >= rightValue : ( - (leftWord ? (float) leftValue : asFloat(leftValue )) >= - (rightWord ? (float) rightValue : asFloat(rightValue)) - )) ? 1 : 0; - } - - // Evaluate >=_ - private static int evalGreaterEqualUnsigned( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return (leftWord && rightWord ? - Integer.compareUnsigned(leftValue, rightValue) >= 0 : ( - (leftWord ? ufloat(leftValue ) : asFloat(leftValue )) >= - (rightWord ? ufloat(rightValue) : asFloat(rightValue)) - )) ? 1 : 0; - } - - // Evaluate > - private static int evalGreaterSigned( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return (leftWord && rightWord ? leftValue > rightValue : ( - (leftWord ? (float) leftValue : asFloat(leftValue )) > - (rightWord ? (float) rightValue : asFloat(rightValue)) - )) ? 1 : 0; - } - - // Evaluate >_ - private static int evalGreaterUnsigned( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return (leftWord && rightWord ? - Integer.compareUnsigned(leftValue, rightValue) > 0 : ( - (leftWord ? ufloat(leftValue ) : asFloat(leftValue )) > - (rightWord ? ufloat(rightValue) : asFloat(rightValue)) - )) ? 1 : 0; - } - - // Evaluate <= - private static int evalLessEqualSigned( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return (leftWord && rightWord ? leftValue <= rightValue : ( - (leftWord ? (float) leftValue : asFloat(leftValue )) <= - (rightWord ? (float) rightValue : asFloat(rightValue)) - )) ? 1 : 0; - } - - // Evaluate <=_ - private static int evalLessEqualUnsigned( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return (leftWord && rightWord ? - Integer.compareUnsigned(leftValue, rightValue) <= 0 : ( - (leftWord ? ufloat(leftValue ) : asFloat(leftValue )) <= - (rightWord ? ufloat(rightValue) : asFloat(rightValue)) - )) ? 1 : 0; - } - - // Evaluate < - private static int evalLessSigned( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return (leftWord && rightWord ? leftValue < rightValue : ( - (leftWord ? (float) leftValue : asFloat(leftValue )) < - (rightWord ? (float) rightValue : asFloat(rightValue)) - )) ? 1 : 0; - } - - // Evaluate <_ - private static int evalLessUnsigned( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return (leftWord && rightWord ? - Integer.compareUnsigned(leftValue, rightValue) < 0 : ( - (leftWord ? ufloat(leftValue ) : asFloat(leftValue )) < - (rightWord ? ufloat(rightValue) : asFloat(rightValue)) - )) ? 1 : 0; - } - - // Evaluate * - private static int evalMultiply( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return leftWord && rightWord ? leftValue * rightValue : asWord( - (leftWord ? (float) leftValue : asFloat(leftValue )) * - (rightWord ? (float) rightValue : asFloat(rightValue)) - ); - } - - // Evaluate != - private static int evalNotEqual( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return (leftWord && rightWord ? leftValue != rightValue : ( - (leftWord ? (float) leftValue : asFloat(leftValue )) != - (rightWord ? (float) rightValue : asFloat(rightValue)) - )) ? 1 : 0; - } - - // Evaluate % - private static int evalRemainder( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return (rightWord ? rightValue : rightValue & 0x7FFFFFFF) == 0 ? 0 : - leftWord && rightWord ? leftValue % rightValue : asWord( - (leftWord ? (float) leftValue : asFloat(leftValue )) % - (rightWord ? (float) rightValue : asFloat(rightValue)) - ); - } - - // Evaluate << - private static int evalShiftLeft( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - leftValue = leftWord ? leftValue : toWord(asFloat(leftValue )); - leftValue = (rightWord ? rightValue : toWord(asFloat(rightValue)))&31; - return leftValue << rightValue; - } - - // Evaluate >>> - private static int evalShiftRight( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - leftValue = leftWord ? leftValue : toWord(asFloat(leftValue )); - leftValue = (rightWord ? rightValue : toWord(asFloat(rightValue)))&31; - return leftValue >>> rightValue; - } - - // Evaluate >> - private static int evalShiftRightArithmetic( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - leftValue = leftWord ? leftValue : toWord(asFloat(leftValue )); - leftValue = (rightWord ? rightValue : toWord(asFloat(rightValue)))&31; - return leftValue >> rightValue; - } - - // Evaluate - - private static int evalSubtract( - boolean leftWord, int leftValue, boolean rightWord, int rightValue) { - return leftWord && rightWord ? leftValue - rightValue : asWord( - (leftWord ? (float) leftValue : asFloat(leftValue )) - - (rightWord ? (float) rightValue : asFloat(rightValue)) - ); - } - - - - /////////////////////////////////////////////////////////////////////////// - // Symbol Methods // - /////////////////////////////////////////////////////////////////////////// - - // Evaluate address - private int evalAddress() { - var vue = (JavaVue) this.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 != 0 ? vue.cpu.fepc : vue.cpu.eipc; - case Vue.TRAP: - return 0xFFFFFFA0 + vue.cpu.inst.imm & 0xFFFFFFF0; - } + // Unreachable return 0; } - // Evaluate cond - private int evalCond() { - var vue = (JavaVue) this.vue; - switch (vue.cpu.inst.id) { - case Vue.BCOND: return vue.cpu.inst.cond; - case Vue.SETF : return vue.cpu.inst.imm; + // Evaluate a binary operator + private static int evalBinary(int id, int left, int right) { + + // Processing by ID + switch (id) { + + // Add + case -ADD * 4 + BOOL: + case -ADD * 4 + SIGNED: + case -ADD * 4 + UNSIGNED: + return left + right; + case -ADD * 4 + FLOAT: + return Float.floatToIntBits(adjust( + Float.intBitsToFloat(left ) + + Float.intBitsToFloat(right) + )); + + // And Bitwise + case -AND_B * 4 + BOOL: + case -AND_B * 4 + FLOAT: // Prevented by parser + case -AND_B * 4 + SIGNED: + case -AND_B * 4 + UNSIGNED: + return left & right; + + // And Logical + case -AND_L * 4 + BOOL: + case -AND_L * 4 + FLOAT: + case -AND_L * 4 + SIGNED: + case -AND_L * 4 + UNSIGNED: + return left == 0 ? left : right; + + // Divide + case -DIVIDE * 4 + BOOL: + case -DIVIDE * 4 + SIGNED: + return right == 0 ? 0 : left / right; + case -DIVIDE * 4 + UNSIGNED: + return right == 0 ? 0 : + (int) ((left & 0xFFFFFFFFL) / (right & 0xFFFFFFFFL)); + case -DIVIDE * 4 + FLOAT: + return right == 0 ? 0 : Float.floatToIntBits(adjust( + Float.intBitsToFloat(left ) / + Float.intBitsToFloat(right) + )); + + // Equal + case -EQUAL * 4 + BOOL: + case -EQUAL * 4 + FLOAT: + case -EQUAL * 4 + SIGNED: + case -EQUAL * 4 + UNSIGNED: + return left == right ? 1 : 0; + + // Greater + case -GREATER * 4 + BOOL: + case -GREATER * 4 + SIGNED: + return left > right ? 1 : 0; + case -GREATER * 4 + UNSIGNED: + return Integer.compareUnsigned(left, right) > 0 ? 1 : 0; + case -GREATER * 4 + FLOAT: + return Float.intBitsToFloat(left) > + Float.intBitsToFloat(right) ? 1 : 0; + + // Greater or Equal + case -GREQUAL * 4 + BOOL: + case -GREQUAL * 4 + SIGNED: + return left >= right ? 1 : 0; + case -GREQUAL * 4 + UNSIGNED: + return Integer.compareUnsigned(left, right) >= 0 ? 1 : 0; + case -GREQUAL * 4 + FLOAT: + return Float.intBitsToFloat(left) >= + Float.intBitsToFloat(right) ? 1 : 0; + + // Shift Left + case -LEFT_L * 4 + BOOL: + case -LEFT_L * 4 + FLOAT: // Prevented by parser + case -LEFT_L * 4 + SIGNED: + case -LEFT_L * 4 + UNSIGNED: + return left << (right & 31); + + // Less or Equal + case -LEQUAL * 4 + BOOL: + case -LEQUAL * 4 + SIGNED: + return left <= right ? 1 : 0; + case -LEQUAL * 4 + UNSIGNED: + return Integer.compareUnsigned(left, right) <= 0 ? 1 : 0; + case -LEQUAL * 4 + FLOAT: + return Float.intBitsToFloat(left) <= + Float.intBitsToFloat(right) ? 1 : 0; + + // Less + case -LESS * 4 + BOOL: + case -LESS * 4 + SIGNED: + return left < right ? 1 : 0; + case -LESS * 4 + UNSIGNED: + return Integer.compareUnsigned(left, right) < 0 ? 1 : 0; + case -LESS * 4 + FLOAT: + return Float.intBitsToFloat(left) < + Float.intBitsToFloat(right) ? 1 : 0; + + // Multiply + case -MULTIPLY * 4 + BOOL: + case -MULTIPLY * 4 + SIGNED: + return left * right; + case -MULTIPLY * 4 + UNSIGNED: + return (int) ((left & 0xFFFFFFFFL) * (right & 0xFFFFFFFFL)); + case -MULTIPLY * 4 + FLOAT: + return Float.floatToIntBits(adjust( + Float.intBitsToFloat(left ) * + Float.intBitsToFloat(right) + )); + + // Not Equal + case -NEQUAL * 4 + BOOL: + case -NEQUAL * 4 + FLOAT: + case -NEQUAL * 4 + SIGNED: + case -NEQUAL * 4 + UNSIGNED: + return left != right ? 1 : 0; + + // Or Bitwise + case -OR_B * 4 + BOOL: + case -OR_B * 4 + FLOAT: // Prevented by parser + case -OR_B * 4 + SIGNED: + case -OR_B * 4 + UNSIGNED: + return left | right; + + // Or Logical + case -OR_L * 4 + BOOL: + case -OR_L * 4 + FLOAT: + case -OR_L * 4 + SIGNED: + case -OR_L * 4 + UNSIGNED: + return left != 0 ? left : right; + + // Remainder + case -REMAINDER * 4 + BOOL: + case -REMAINDER * 4 + SIGNED: + return right == 0 ? 0 : left % right; + case -REMAINDER * 4 + UNSIGNED: + return right == 0 ? 0 : + (int) ((left & 0xFFFFFFFFL) % (right & 0xFFFFFFFFL)); + case -REMAINDER * 4 + FLOAT: + return right == 0 ? 0 : Float.floatToIntBits(adjust( + Float.intBitsToFloat(left ) % + Float.intBitsToFloat(right) + )); + + // Shift Right Arithmetic + case -RIGHT_A * 4 + BOOL: + case -RIGHT_A * 4 + FLOAT: // Prevented by parser + case -RIGHT_A * 4 + SIGNED: + case -RIGHT_A * 4 + UNSIGNED: + return left >> (right & 31); + + // Shift Right Logical + case -RIGHT_L * 4 + BOOL: + case -RIGHT_L * 4 + FLOAT: // Prevented by parser + case -RIGHT_L * 4 + SIGNED: + case -RIGHT_L * 4 + UNSIGNED: + return left >>> (right & 31); + + // Subtract + case -SUBTRACT * 4 + BOOL: + case -SUBTRACT * 4 + SIGNED: + case -SUBTRACT * 4 + UNSIGNED: + return left - right; + case -SUBTRACT * 4 + FLOAT: + return Float.floatToIntBits(adjust( + Float.intBitsToFloat(left) - + Float.intBitsToFloat(right) + )); + + // Exclusive Or Bitwise + case -XOR_B * 4 + BOOL: + case -XOR_B * 4 + FLOAT: // Prevented by parser + case -XOR_B * 4 + SIGNED: + case -XOR_B * 4 + UNSIGNED: + return left ^ right; + + // Exclusive Or Logical + case -XOR_L * 4 + BOOL: + case -XOR_L * 4 + FLOAT: + case -XOR_L * 4 + SIGNED: + case -XOR_L * 4 + UNSIGNED: + return left != 0 && right != 0 ? 0 : left != 0 ? left : right; + } + + // Unreachable return 0; } - // Evaluate disp - private int evalDisp() { - var vue = (JavaVue) this.vue; - switch (vue.cpu.inst.format) { - case 3: case 4: case 6: return vue.cpu.inst.disp; - } - return 0; - } - - // Evaluate imm - private int evalImm() { - var vue = (JavaVue) this.vue; - switch (vue.cpu.inst.format) { - case 2: case 5: return vue.cpu.inst.imm; - } - return 0; - } - - // Evaluate reg1 - private int evalReg1() { - var vue = (JavaVue) this.vue; - switch (vue.cpu.inst.format) { - case 1: case 5: case 6: case 7: return vue.cpu.inst.reg1; - } - return 0; - } - - // Evaluate reg2 - private int evalReg2() { - var vue = (JavaVue) this.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 - private int evalRegId() { - var vue = (JavaVue) this.vue; - switch (vue.cpu.inst.id) { - case Vue.LDSR: case Vue.STSR: return vue.cpu.inst.imm; - } - return 0; - } - - // Evaluate subopcode - private int evalSubopcode() { - var vue = (JavaVue) this.vue; - switch (vue.cpu.inst.opcode) { - case 0x1F: return vue.cpu.inst.imm; - case 0x3E: return vue.cpu.inst.subopcode; - } - return 0; - } - - // Evaluate value - private int evalValue() { - var vue = (JavaVue) this.vue; - return vue.cpu.inst.format == 6 ? vue.cpu.access.value : 0; - } - - // Evaluate vector - private int evalVector() { - var vue = (JavaVue) this.vue; - return vue.cpu.inst.id == Vue.TRAP ? vue.cpu.inst.imm : 0; - } - - - - /////////////////////////////////////////////////////////////////////////// - // Unary Methods // - /////////////////////////////////////////////////////////////////////////// - - // Evaluate ~ - private static int evalBitwiseNot(boolean isWord, int value) { - return isWord ? ~value : ~toWord(asFloat(value)); - } - - // Evaluate ! - private static int evalLogicalNot(boolean isWord, int value) { - return (isWord ? value != 0 : (value & 0x7FFFFFFF) != 0) ? 1 : 0; - } - - // Evaluate - - private static int evalNegate(boolean isWord, int value) { - return isWord ? -value : asWord(-asFloat(value)); - } - - // Evaluate ceil - private static int evalCeil(boolean isWord, int value) { - return isWord ? value : asWord((float) Math.ceil(asFloat(value))); - } - - // Evaluate float - private static int evalFloat(boolean isWord, int value) { - return isWord ? asWord((float) value) : value; - } - - // Evaluate floor - private static int evalFloor(boolean isWord, int value) { - return isWord ? value : asWord((float) Math.floor(asFloat(value))); - } - - // Evaluate [] - private int evalReadWord(boolean isWord, int value) { - var vue = (JavaVue) this.vue; - return vue.read(isWord ? value : toWord(asFloat(value)), Vue.S32); - } - - // Evaluate round - private static int evalRound(boolean isWord, int value) { - return isWord ? value : asWord((float) Math.round(asFloat(value))); - } - - // Evaluate trunc - private static int evalTrunc(boolean isWord, int value) { - return isWord ? value : asWord((float) (value < 0 ? - Math.ceil(asFloat(value)) : Math.ceil(asFloat(value)))); - } - - // Evaluate word - private static int evalWord(boolean isWord, int value) { - return isWord ? value : toWord(asFloat(value)); - } - - // Evaluate xfloat - private static int evalXFloat(boolean isWord, int value) { - return isWord ? asWord(asFloat(value)) : value; - } - -} +} \ No newline at end of file diff --git a/src/desktop/vue/CPU.java b/src/desktop/vue/CPU.java index 80fe0bb..20d689b 100644 --- a/src/desktop/vue/CPU.java +++ b/src/desktop/vue/CPU.java @@ -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) diff --git a/src/desktop/vue/Ecxeption.java b/src/desktop/vue/Ecxeption.java index 76fb7d1..42905d7 100644 --- a/src/desktop/vue/Ecxeption.java +++ b/src/desktop/vue/Ecxeption.java @@ -17,4 +17,10 @@ public class Ecxeption { // Default constructor Ecxeption() { } + // Cloning constructor + Ecxeption(Ecxeption o) { + this(); + code = o.code; + } + } diff --git a/src/desktop/vue/Instruction.java b/src/desktop/vue/Instruction.java index f2e59ba..94f137b 100644 --- a/src/desktop/vue/Instruction.java +++ b/src/desktop/vue/Instruction.java @@ -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; + } + /////////////////////////////////////////////////////////////////////////// diff --git a/src/desktop/vue/JavaVue.java b/src/desktop/vue/JavaVue.java index 0ff3188..5b9d322 100644 --- a/src/desktop/vue/JavaVue.java +++ b/src/desktop/vue/JavaVue.java @@ -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 @@ -29,9 +31,10 @@ class JavaVue extends Vue { // Default constructor JavaVue() { - cpu = new CPU (this); - pak = new GamePak(this); - wram = new byte[0x10000]; + 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; + } + } diff --git a/src/desktop/vue/NativeVue.c b/src/desktop/vue/NativeVue.c index a402403..b2a01bb 100644 --- a/src/desktop/vue/NativeVue.c +++ b/src/desktop/vue/NativeVue.c @@ -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); -} diff --git a/src/desktop/vue/NativeVue.java b/src/desktop/vue/NativeVue.java index cc1f61e..e6cb79f 100644 --- a/src/desktop/vue/NativeVue.java +++ b/src/desktop/vue/NativeVue.java @@ -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); - } diff --git a/src/desktop/vue/Vue.java b/src/desktop/vue/Vue.java index c81f54b..d599212 100644 --- a/src/desktop/vue/Vue.java +++ b/src/desktop/vue/Vue.java @@ -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) { }