From 2df99895fa1e5327fe146d4d29015d01ac055441 Mon Sep 17 00:00:00 2001 From: Guy Perfect Date: Fri, 14 Aug 2020 10:06:00 -0500 Subject: [PATCH] Implementing breakpoint condition evaluator --- src/desktop/Main.java | 10 + src/desktop/vue/Breakpoint.java | 993 ++++++++++++++++++++++++++------ src/desktop/vue/CPU.java | 2 +- src/desktop/vue/JavaVUE.java | 6 + src/desktop/vue/NativeVUE.java | 3 + src/desktop/vue/VUE.java | 3 + 6 files changed, 851 insertions(+), 166 deletions(-) diff --git a/src/desktop/Main.java b/src/desktop/Main.java index bdc90e4..71bac7f 100644 --- a/src/desktop/Main.java +++ b/src/desktop/Main.java @@ -50,6 +50,16 @@ public class Main { // Begin application operations new App(useNative); + +/* + var brk = new Breakpoint(); + String exp = "([sp - 8] & 3) << 6 != 12.0 + r6 * ecr && [0x0500008C + r8] == 0"; + System.out.println(exp); + if (brk.setCondition(exp)) + System.out.println(brk.debug()); + else System.out.println(brk.getErrorCode() + "\t" + + brk.getErrorPosition() + ":" + brk.getErrorText()); +*/ } } diff --git a/src/desktop/vue/Breakpoint.java b/src/desktop/vue/Breakpoint.java index 784fedd..152aabb 100644 --- a/src/desktop/vue/Breakpoint.java +++ b/src/desktop/vue/Breakpoint.java @@ -7,14 +7,243 @@ import java.util.*; public class Breakpoint { // Instance fields - private int errCode; // Error type - private int errPosition; // Character of input error - private String errText; // Offending token text - private String expression; // Un-processed input - private boolean isEnabled; // Breakpoint is active - private boolean isValid; // Expression is valid and processed - private String name; // Display name - private Token[] tokens; // Evaluation tokens + private int[][] addresses; // Applicable address ranges + private String condition; // Un-processed condition + private int errCode; // Condition error code + private int errPosition; // Character of condition error + private String errText; // Offending condition text + private boolean isEnabled; // Breakpoint is active + private String name; // Display name + private Token[] tokens; // Evaluation tokens + + + + /////////////////////////////////////////////////////////////////////////// + // Constants // + /////////////////////////////////////////////////////////////////////////// + + // Error codes + 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; + + // Token types + private static final int BINARY = 1; + private static final int CLOSE = 2; + private static final int FLOAT = 3; + private static final int OPEN = 4; + private static final int SYMBOL = 5; + private static final int UNARY = 6; + private static final int WORD = 0; + + // 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 = 0b0101101; + private static final int MODES_BEFORE = 0b0000110; + + // Operator IDs + private static final int ADD = 0; + private static final int BITWISE_AND = 1; + private static final int BITWISE_NOT = 2; + private static final int BITWISE_OR = 3; + private static final int BITWISE_XOR = 4; + private static final int CEIL = 5; + private static final int DIVIDE = 6; + private static final int EQUAL = 7; + private static final int FLOATOP = 8; + private static final int FLOOR = 9; + private static final int GREATER_EQUAL_SIGNED = 10; + private static final int GREATER_EQUAL_UNSIGNED = 11; + private static final int GREATER_SIGNED = 12; + private static final int GREATER_UNSIGNED = 13; + private static final int GROUP = 14; + private static final int LESS_EQUAL_SIGNED = 15; + private static final int LESS_EQUAL_UNSIGNED = 16; + private static final int LESS_SIGNED = 17; + private static final int LESS_UNSIGNED = 18; + private static final int LOGICAL_AND = 19; + private static final int LOGICAL_NOT = 20; + private static final int LOGICAL_OR = 21; + private static final int LOGICAL_XOR = 22; + private static final int MULTIPLY = 23; + private static final int NEGATE = 24; + private static final int NOT_EQUAL = 25; + private static final int READ_WORD = 26; + private static final int REMAINDER = 27; + private static final int ROUND = 28; + private static final int SHIFT_LEFT = 29; + private static final int SHIFT_RIGHT = 30; + private static final int SHIFT_RIGHT_ARITHMETIC = 31; + private static final int SUBTRACT = 32; + private static final int TRUNC = 33; + private static final int WORDOP = 34; + 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; + + // Functional symbol IDs + private static final int ADDRESS = 0; + private static final int CODE = 1; + private static final int COND = 2; + private static final int DISP = 3; + private static final int FORMAT = 4; + private static final int ID = 5; + private static final int IMM = 6; + private static final int OPCODE = 7; + private static final int REG1 = 8; + private static final int REG2 = 9; + private static final int REGID = 10; + private static final int SIZE = 11; + private static final int SUBOPCODE = 12; + private static final int VALUE = 13; + private static final int VECTOR = 14; + + // Static initializer + static { + LITDEFS = 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 , FLOATOP )); + 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 , WORDOP )); + 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 )); + + // 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); + + // 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 ); + + // 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); + + // System register symbol definitions + SYMDEFS.put("adtre", 225); SYMDEFS.put("fepsw", 203); + SYMDEFS.put("chcw" , 224); SYMDEFS.put("pc" , 199); + SYMDEFS.put("ecr" , 204); SYMDEFS.put("psw" , 205); + SYMDEFS.put("eipc" , 200); SYMDEFS.put("sr29" , 229); + SYMDEFS.put("eipsw", 201); SYMDEFS.put("sr31" , 231); + SYMDEFS.put("fepc" , 202); + LITDEFS.put("pir" , 0x00005346); + LITDEFS.put("tkcw" , 0x000000E0); + LITDEFS.put("sr30" , 0x00000004); + + }; @@ -47,7 +276,7 @@ public class Breakpoint { int start; // Character position in expression String text; // Display text int type; // Token category - Object value; // Literal value + int value; // Literal value // Constructor Token(int type, int start, String text) { @@ -60,126 +289,19 @@ public class Breakpoint { - /////////////////////////////////////////////////////////////////////////// - // Constants // - /////////////////////////////////////////////////////////////////////////// - - // Error codes - public static final int NONE = 0; - public static final int BADTOKEN = 1; - public static final int EARLYEOF = 2; - public static final int EMPTY = 3; - public static final int INVALID = 4; - public static final int NESTING = 5; - public static final int UNEXPECTED = 6; - - // Token types - private static final int BINARY = 0; - private static final int CLOSE = 1; - private static final int LITERAL = 2; - private static final int OPEN = 3; - private static final int SYMBOL = 4; - private static final int UNARY = 5; - - // Expected token modes adjacent to any given token - private static final int MODES_AFTER = 0b010110; - private static final int MODES_BEFORE = 0b000011; - - // Token IDs - private static final int ADD = 0; - private static final int BITWISE_AND = 1; - private static final int BITWISE_NOT = 2; - private static final int BITWISE_OR = 3; - private static final int BITWISE_XOR = 4; - private static final int CEIL = 5; - private static final int DIVIDE = 6; - private static final int EQUAL = 7; - private static final int FLOAT = 8; - private static final int FLOOR = 9; - private static final int GREATER_EQUAL_SIGNED = 10; - private static final int GREATER_EQUAL_UNSIGNED = 11; - private static final int GREATER_SIGNED = 12; - private static final int GREATER_UNSIGNED = 13; - private static final int GROUP = 14; - private static final int LESS_EQUAL_SIGNED = 15; - private static final int LESS_EQUAL_UNSIGNED = 16; - private static final int LESS_SIGNED = 17; - private static final int LESS_UNSIGNED = 18; - private static final int LOGICAL_AND = 19; - private static final int LOGICAL_NOT = 20; - private static final int LOGICAL_OR = 21; - private static final int LOGICAL_XOR = 22; - private static final int MULTIPLY = 23; - private static final int NEGATE = 24; - private static final int NOT_EQUAL = 25; - private static final int READ = 26; - private static final int REMAINDER = 27; - private static final int ROUND = 28; - private static final int SHIFT_LEFT = 29; - private static final int SHIFT_RIGHT = 30; - private static final int SHIFT_RIGHT_ARITHMETIC = 31; - private static final int SUBTRACT = 32; - private static final int TRUNC = 33; - private static final int WORD = 34; - private static final int XFLOAT = 35; - private static final int XWORD = 36; - - // Token definitions - private static final HashMap OPDEFS; - - // Static initializer - static { - OPDEFS = new HashMap(); - OPDEFS.put("(" , new OpDef( 0, OPEN , GROUP )); - OPDEFS.put(")" , new OpDef( 0, CLOSE , GROUP )); - OPDEFS.put("[" , new OpDef( 0, OPEN , READ )); - OPDEFS.put("]" , new OpDef( 0, CLOSE , READ )); - 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 )); - }; - - - /////////////////////////////////////////////////////////////////////////// // Constructors // /////////////////////////////////////////////////////////////////////////// // Default constructor public Breakpoint() { - setExpression(null); - name = ""; + addresses = new int[0][]; + condition = ""; + errCode = NONE; + errPosition = 0; + errText = ""; + name = ""; + tokens = new Token[0]; } @@ -188,6 +310,63 @@ 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(); + } + + // Retrieve the most recent input condition + public String getCondition() { + return condition; + } + // Retrieve the most recent error code public int getErrorCode() { return errCode; @@ -203,11 +382,6 @@ public class Breakpoint { return errText; } - // Retrieve the most recent input expression - public String getExpression() { - return expression; - } - // Retrieve the display name public String getName() { return name; @@ -218,26 +392,48 @@ public class Breakpoint { return isEnabled; } - // Determine whether the breakpoint is valid - public boolean isValid() { - return isValid; + // Specify and parse a list of address ranges + public boolean setAddresses(int[][] addresses) { + + // Error checking + if (addresses == null) + return false; + for (var range : addresses) + if (range == null || range.length > 2) + return false; + + // Accept the new address ranges + this.addresses = new int[addresses.length][2]; + for (int x = 0; x < addresses.length; x++) { + var range = addresses[x]; + this.addresses[x] = new int[] { + range[0], + range[range.length - 1] + }; + } + return true; } - // Specify and parse an expression - public boolean setExpression(String expression) { + // Specify and parse a condition + public boolean setCondition(String condition) { // Configure instance fields - errCode = NONE; - errPosition = 0; - errText = ""; - this.expression = expression == null ? expression = "" : expression; + this.condition = condition == null ? condition = "" : condition; + errCode = NONE; + errPosition = 0; + errText = ""; + tokens = new Token[0]; // Process the expression var tokens = parse(); if (tokens == null || !validate(tokens)) - return isValid = false; + return false; tree(tokens); + // The expression is empty + if (tokens.size() == 0) + return true; + // Produce an RPN-ordered list of tokens var tok = tokens.remove(0); while (tok != null) { @@ -257,14 +453,13 @@ public class Breakpoint { } // No children: add node to output - System.out.println(tok.text); tokens.add(tok); tok = tok.parent; } this.tokens = tokens.toArray(new Token[tokens.size()]); // The expression was successfully parsed - return isValid = true; + return true; } // Specify the display name @@ -282,7 +477,7 @@ public class Breakpoint { int depth() { // Error checking - if (!isValid) + if (errCode != NONE) return 0; // Count the maximum size of the stack @@ -290,8 +485,9 @@ public class Breakpoint { int size = 0; for (var tok : tokens) switch (tok.type) { case BINARY : size--; break; - case LITERAL: // Fallthrough - case SYMBOL : max = Math.max(max, ++size); + case FLOAT : // Fallthrough + case SYMBOL : // Fallthrough + case WORD : max = Math.max(max, ++size); } return max; } @@ -314,12 +510,12 @@ public class Breakpoint { ? 0 : value; } - // Parse an expression into tokens + // Parse a condition into tokens private ArrayList parse() { var tokens = new ArrayList(); // Parse the expression - var chars = (expression + " ").toCharArray(); + var chars = (condition + " ").toCharArray(); for (int x = 0; x < chars.length; x++) { char c = chars[x]; @@ -345,14 +541,6 @@ public class Breakpoint { x += tok.text.length() - 1; } // x - // The expression contains no tokens - if (tokens.size() == 0) { - errCode = EMPTY; - errPosition = 1; - errText = ""; - return null; - } - return tokens; } @@ -404,23 +592,24 @@ public class Breakpoint { ) continue; // Produce a new token - var ret = new Token(LITERAL, start, + 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.value = - fixFloat(Float.parseFloat(ret.text)); - else ret.value = - Integer.parseInt(ret.text); + else if (isFloat) { + ret.type = FLOAT; + ret.value = Float.floatToRawIntBits( + fixFloat(Float.parseFloat(ret.text))); + } else ret.value = Integer.parseInt(ret.text); return ret; } // Could not parse the value catch (Exception e) { - errCode = UNEXPECTED; + errCode = BADLITERAL; errPosition = x + 1; errText = ret.text; return null; @@ -492,11 +681,12 @@ public class Breakpoint { ) continue; // Produce a new token - var ret = new Token(SYMBOL, start, + 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(ret.text.toLowerCase()); + var def = OPDEFS.get(text); if (def != null) { ret.id = def.id; ret.precedence = def.precedence; @@ -504,8 +694,27 @@ public class Breakpoint { return ret; } + // 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 - return ret; + value = SYMDEFS.get(text); + if (value != null) { + ret.id = value; + ret.type = SYMBOL; + return ret; + } + + // The token is not recognized + errCode = BADTOKEN; + errPosition = x + 1; + errText = ret.text; + return null; } // x return null; // Unreachable @@ -568,8 +777,9 @@ public class Breakpoint { // Apply the group operators tokens.remove(end + 1); - if (tokens.remove(start - 1).id == READ) { + if (tokens.remove(start - 1).id == READ_WORD) { var tok = new Token(UNARY, 0, "{Read Word}"); + tok.id = READ_WORD; tok.right = tokens.remove(start - 1); tok.right.parent = tok; tokens.add(start - 1, tok); @@ -625,12 +835,465 @@ public class Breakpoint { // A group was not closed if (!stack.empty()) { errCode = EARLYEOF; - errPosition = expression.length(); + errPosition = condition.length(); errText = stack.pop().text; } - // Successfully parsed the expression + // Successfully parsed the condition return true; } + + + /////////////////////////////////////////////////////////////////////////// + // Evaluation Methods // + /////////////////////////////////////////////////////////////////////////// + + // Evaluate the condition for an emulation context + boolean evaluate(JavaVUE vue, int[] stack) { + + // The condition is empty + if (tokens.length == 0) + return isEnabled && errCode == NONE; + + // Process tokens + int size = 0; + for (var tok : tokens) { + switch (tok.type) { + //case BINARY: size = + // evalBinary(vue, tok.id, stack, size); continue; + case SYMBOL: size = + evalSymbol(vue, tok.id, stack, size); continue; + case UNARY : size = + evalUnary (vue, tok.id, stack, size); continue; + } + stack[size++] = tok.type; + stack[size++] = tok.value; + } + return (stack[1] & (stack[0] == FLOAT ? 0x7FFFFFFF : 0xFFFFFFFF)) != 0; + } + + // Evaluate a binary operator + private int evalBinary(JavaVUE vue, int id, int[] stack, int size) { + int lw = stack[size - 3]; + float lf = Float.intBitsToFloat(lw); + int ret = 0; + int rw = stack[size - 1]; + float rf = Float.intBitsToFloat(rw); + int type = stack[size - 2] | stack[size - 4]; + switch (id) { + case ADD : + ret = evalAdd (type, lw, lf, rw, rf); break; + case BITWISE_AND : + ret = evalBitwiseAnd (type, lw, lf, rw, rf); break; + case BITWISE_XOR : + ret = evalBitwiseXOr (type, lw, lf, rw, rf); break; + case BITWISE_OR : + ret = evalBitwiseOr (type, lw, lf, rw, rf); break; + case DIVIDE : + ret = evalDivide (type, lw, lf, rw, rf); break; + case EQUAL : + ret = evalEqual (type, lw, lf, rw, rf); + type = WORD; break; + case GREATER_EQUAL_SIGNED : + ret = evalGreaterEqualSigned (type, lw, lf, rw, rf); + type = WORD; break; + case GREATER_EQUAL_UNSIGNED: + ret = evalGreaterEqualUnsigned(type, lw, lf, rw, rf); + type = WORD; break; + case GREATER_SIGNED : + ret = evalGreaterSigned (type, lw, lf, rw, rf); + type = WORD; break; + case GREATER_UNSIGNED : + ret = evalGreaterUnsigned (type, lw, lf, rw, rf); + type = WORD; break; + case LESS_EQUAL_SIGNED : + ret = evalLessEqualSigned (type, lw, lf, rw, rf); + type = WORD; break; + case LESS_EQUAL_UNSIGNED : + ret = evalLessEqualUnsigned (type, lw, lf, rw, rf); + type = WORD; break; + case LESS_SIGNED : + ret = evalLessSigned (type, lw, lf, rw, rf); + type = WORD; break; + case LESS_UNSIGNED : + ret = evalLessUnsigned (type, lw, lf, rw, rf); + type = WORD; break; + case LOGICAL_AND : + ret = evalLogicalAnd (type, lw, lf, rw, rf); + type = WORD; break; + case LOGICAL_OR : + ret = evalLogicalOr (type, lw, lf, rw, rf); + type = WORD; break; + case LOGICAL_XOR : + ret = evalLogicalXOr (type, lw, lf, rw, rf); + type = WORD; break; + case MULTIPLY : + ret = evalMultiply (type, lw, lf, rw, rf); break; + case NOT_EQUAL : + ret = evalNotEqual (type, lw, lf, rw, rf); + type = WORD; break; + case REMAINDER : + ret = evalRemainder (type, lw, lf, rw, rf); break; + case SHIFT_LEFT : + ret = evalShiftLeft (type, lw, lf, rw, rf); break; + case SHIFT_RIGHT : + ret = evalShiftRight (type, lw, lf, rw, rf); break; + case SHIFT_RIGHT_ARITHMETIC: + ret = evalShiftRightArithmetic(type, lw, lf, rw, rf); break; + case SUBTRACT : + ret = evalSubtract (type, lw, lf, rw, rf); break; + } + stack[size - 4] = type; + stack[size - 3] = ret; + return size - 2; + } + + // Evaluate + + private int evalAdd(int type, int lw, float lf, int rw, float rf) { + return type == WORD ? lw + rw : Float.floatToRawIntBits(lf + rf); + } + + // Evaluate & + private int evalBitwiseAnd(int type, int lw, float lf, int rw, float rf) { + return type == WORD ? lw & rw : Float.floatToRawIntBits( + fixFloat(Float.intBitsToFloat(lw & rw))); + } + + // Evaluate | + private int evalBitwiseOr(int type, int lw, float lf, int rw, float rf) { + return type == WORD ? lw | rw : Float.floatToRawIntBits( + fixFloat(Float.intBitsToFloat(lw | rw))); + } + + // Evaluate ^ + private int evalBitwiseXOr(int type, int lw, float lf, int rw, float rf) { + return type == WORD ? lw ^ rw : Float.floatToRawIntBits( + fixFloat(Float.intBitsToFloat(lw ^ rw))); + } + + // Evaluate / + private int evalDivide(int type, int lw, float lf, int rw, float rf) { + return type == WORD ? rw == 0 ? 0 : lw / rw : rf == 0 ? 0 : + Float.floatToRawIntBits(lf / rf); + } + + // Evaluate == + private int evalEqual(int type, int lw, float lf, int rw, float rf) { + return (type == WORD ? lw == rw : lf == rf) ? 1 : 0; + } + + // Evaluate >= + private int evalGreaterEqualSigned(int type, + int lw, float lf, int rw, float rf) { + return (type == WORD ? lw >= rw : (lf >= rf)) ? 1 : 0; + } + + // Evaluate >=_ + private int evalGreaterEqualUnsigned(int type, + int lw, float lf, int rw, float rf) { + return (type == WORD ? Integer.compareUnsigned(lw, rw) >= 0 : + (lf >= rf)) ? 1 : 0; + } + + // Evaluate > + private int evalGreaterSigned(int type,int lw,float lf,int rw,float rf) { + return (type == WORD ? lw > rw : (lf > rf)) ? 1 : 0; + } + + // Evaluate >_ + private int evalGreaterUnsigned(int type,int lw,float lf,int rw,float rf) { + return (type == WORD ? Integer.compareUnsigned(lw, rw) > 0 : + (lf > rf)) ? 1 : 0; + } + + // Evaluate <= + private int evalLessEqualSigned(int type, + int lw, float lf, int rw, float rf) { + return (type == WORD ? lw <= rw : (lf <= rf)) ? 1 : 0; + } + + // Evaluate <=_ + private int evalLessEqualUnsigned(int type, + int lw, float lf, int rw, float rf) { + return (type == WORD ? Integer.compareUnsigned(lw, rw) <= 0 : + (lf <= rf)) ? 1 : 0; + } + + // Evaluate < + private int evalLessSigned(int type, int lw, float lf, int rw, float rf) { + return (type == WORD ? lw < rw : (lf < rf)) ? 1 : 0; + } + + // Evaluate <_ + private int evalLessUnsigned(int type, int lw, float lf, int rw, float rf){ + return (type == WORD ? Integer.compareUnsigned(lw, rw) < 0 : + (lf < rf)) ? 1 : 0; + } + + // Evaluate && + private int evalLogicalAnd(int type, int lw, float lf, int rw, float rf) { + return type == WORD ? lw != 0 ? rw : 0 : + Float.floatToRawIntBits(lf != 0 ? rf : 0); + } + + // Evaluate || + private int evalLogicalOr(int type, int lw, float lf, int rw, float rf) { + return type == WORD ? lw != 0 ? lw : rw : + Float.floatToRawIntBits(lf != 0 ? lf : rf); + } + + // Evaluate ^^ + private int evalLogicalXOr(int type, int lw, float lf, int rw, float rf) { + return type == WORD ? lw!=0 ? rw!=0 ? 0 : lw : rw!=0 ? rw : 0 : + Float.floatToRawIntBits(lf!=0 ? rf!=0 ? 0 : lf : rf!=0 ? rf : 0); + } + + // Evaluate * + private int evalMultiply(int type, int lw, float lf, int rw, float rf) { + return type == WORD ? lw * rw : Float.floatToRawIntBits(lf * rf); + } + + // Evaluate != + private int evalNotEqual(int type, int lw, float lf, int rw, float rf) { + return (type == WORD ? lw != rw : lf != rf) ? 1 : 0; + } + + // Evaluate % + private int evalRemainder(int type, int lw, float lf, int rw, float rf) { + return type == WORD ? rw == 0 ? 0 : lw % rw : rf == 0 ? 0 : + Float.floatToRawIntBits(lf % rf); + } + + // Evaluate << + private int evalShiftLeft(int type, int lw, float lf, int rw, float rf) { + return type == WORD ? lw << (rw & 31) : Float.floatToRawIntBits( + fixFloat(Float.intBitsToFloat(lw << ((int) rf & 31)))); + } + + // Evaluate >>> + private int evalShiftRight(int type, int lw, float lf, int rw, float rf) { + return type == WORD ? lw >>> (rw & 31) : Float.floatToRawIntBits( + fixFloat(Float.intBitsToFloat(lw >>> ((int) rf & 31)))); + } + + // Evaluate >> + private int evalShiftRightArithmetic(int type, + int lw, float lf, int rw, float rf) { + return type == WORD ? lw >> (rw & 31) : Float.floatToRawIntBits( + fixFloat(Float.intBitsToFloat(lw >> ((int) rf & 31)))); + } + + // Evaluate - + private int evalSubtract(int type, int lw, float lf, int rw, float rf) { + return type == WORD ? lw - rw : Float.floatToRawIntBits(lf - rf); + } + + // Evaluate a functional symbol + private int evalSymbol(JavaVUE vue, int id, int[] stack, int size) { + int ret = 0; + if (vue.cpu.stage == CPU.EXCEPTION) switch (id) { + case CODE: ret = vue.cpu.exception.code; break; + } + else 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 address + private int evalAddress(JavaVUE 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; + } + return 0; + } + + // Evaluate cond + private int evalCond(JavaVUE 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 + private int evalDisp(JavaVUE vue) { + switch (vue.cpu.inst.format) { + case 3: case 4: case 6: return vue.cpu.inst.disp; + } + return 0; + } + + // Evaluate imm + private int evalImm(JavaVUE vue) { + switch (vue.cpu.inst.format) { + case 2: case 5: return vue.cpu.inst.imm; + } + return 0; + } + + // Evaluate reg1 + private int evalReg1(JavaVUE 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(JavaVUE 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(JavaVUE vue) { + switch (vue.cpu.inst.id) { + case VUE.LDSR: case VUE.STSR: return vue.cpu.inst.imm; + } + return 0; + } + + // Evaluate subopcode + private int evalSubopcode(JavaVUE 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(JavaVUE vue) { + return vue.cpu.inst.format == 6 ? vue.cpu.access.value : 0; + } + + // Evaluate vector + private int evalVector(JavaVUE vue) { + return vue.cpu.inst.id == VUE.TRAP ? vue.cpu.inst.imm : 0; + } + + // Evaluate a unary operator + private int evalUnary(JavaVUE vue, int id, int[] stack, int size) { + int ret = 0; + int type = stack[size - 2]; + int w = stack[size - 1]; + float f = Float.intBitsToFloat(w); + switch (id) { + case BITWISE_NOT: ret = evalBitwiseNot(type, w, f); break; + case LOGICAL_NOT: ret = evalLogicalNot(type, w, f); + type = WORD ; break; + case NEGATE : ret = evalNegate (type, w, f); break; + case CEIL : ret = evalCeil (type, w, f); break; + case FLOATOP : ret = evalFloat (type, w, f); + type = FLOAT; break; + case FLOOR : ret = evalFloor (type, w, f); break; + case READ_WORD : ret = evalReadWord (type, w, f, vue); + type = WORD ; break; + case ROUND : ret = evalRound (type, w, f); break; + case TRUNC : ret = evalTrunc (type, w, f); break; + case WORDOP : ret = evalWord (type, w, f); + type = WORD ; break; + case XFLOAT : ret = evalXFloat (type, w, f); + type = FLOAT; break; + case XWORD : ret = w; type = WORD; break; + } + stack[size - 2] = type; + stack[size - 1] = ret; + return size; + } + + // Evaluate ~ + private int evalBitwiseNot(int type, int w, float f) { + return type == WORD ? ~w : + Float.floatToRawIntBits(fixFloat(Float.intBitsToFloat(~w))); + } + + // Evaluate ! + private int evalLogicalNot(int type, int w, float f) { + return (type == WORD ? w == 0 : f == 0) ? 1 : 0; + } + + // Evaluate - + private int evalNegate(int type, int w, float f) { + return type == WORD ? -w : Float.floatToRawIntBits(-f); + } + + // Evaluate ceil + private int evalCeil(int type, int w, float f) { + return type == WORD ? w : + Float.floatToRawIntBits((float) Math.ceil(f)); + } + + // Evaluate float + private int evalFloat(int type, int w, float f) { + return Float.floatToRawIntBits(type == FLOAT ? f : (float) w); + } + + // Evaluate floor + private int evalFloor(int type, int w, float f) { + return type == WORD ? w : + Float.floatToRawIntBits((float) Math.floor(f)); + } + + // Evaluate [] + private int evalReadWord(int type, int w, float f, JavaVUE vue) { + if (type == FLOAT) { + if (f > 0x7FFFFFFF || f < 0x80000000) + return 0; + w = (int) f; + } + return vue.read(w, VUE.S32); + } + + // Evaluate round + private int evalRound(int type, int w, float f) { + return type == WORD ? w : + Float.floatToRawIntBits((float) Math.round(f)); + } + + // Evaluate trunc + private int evalTrunc(int type, int w, float f) { + return type == WORD ? w : Float.floatToRawIntBits((float) + (f < 0 ? Math.ceil(f) : Math.floor(f))); + } + + // Evaluate word + private int evalWord(int type, int w, float f) { + return type == WORD ? w : + f > 0x7FFFFFFF || f < 0x80000000 ? 0 : (int) f; + } + + // Evaluate xfloat + private int evalXFloat(int type, int w, float f) { + return Float.floatToRawIntBits(type == FLOAT ? f : + fixFloat(Float.intBitsToFloat(w))); + } + } diff --git a/src/desktop/vue/CPU.java b/src/desktop/vue/CPU.java index ed3e623..d856668 100644 --- a/src/desktop/vue/CPU.java +++ b/src/desktop/vue/CPU.java @@ -1114,7 +1114,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute // Trap private void TRAP() { - exception.code = 0xFFA0 | inst.imm & 15; + exception.code = 0xFFA0 | inst.imm & 31; pc += 2; } diff --git a/src/desktop/vue/JavaVUE.java b/src/desktop/vue/JavaVUE.java index 7f59c30..4bc5547 100644 --- a/src/desktop/vue/JavaVUE.java +++ b/src/desktop/vue/JavaVUE.java @@ -91,6 +91,12 @@ class JavaVUE extends VUE { return Math.max(0, maxCycles); } + // Evaluate the condition in a breakpoint + public boolean evaluate(Breakpoint brk) { + return brk != null ? false : + brk.evaluate(this, new int[brk.depth() * 2]); + } + // Retrieve the application break code public int getBreakCode() { return breakCode; diff --git a/src/desktop/vue/NativeVUE.java b/src/desktop/vue/NativeVUE.java index 61fea85..c5ab28d 100644 --- a/src/desktop/vue/NativeVUE.java +++ b/src/desktop/vue/NativeVUE.java @@ -29,6 +29,9 @@ class NativeVUE extends VUE { // Process the simulation public native int emulate(int maxCycles); + // Evaluate the condition in a breakpoint + public native boolean evaluate(Breakpoint brk); + // Retrieve the application break code public native int getBreakCode(); diff --git a/src/desktop/vue/VUE.java b/src/desktop/vue/VUE.java index 61be8df..cd290f9 100644 --- a/src/desktop/vue/VUE.java +++ b/src/desktop/vue/VUE.java @@ -173,6 +173,9 @@ public abstract class VUE { // Process the simulation public abstract int emulate(int maxCycles); + // Evaluate the condition in a breakpoint + public abstract boolean evaluate(Breakpoint brk); + // Retrieve the application break code public abstract int getBreakCode();