pvbemu/src/desktop/vue/Breakpoint.java

1675 lines
60 KiB
Java

package vue;
// Java imports
import java.util.*;
// Breakpoint definition
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
///////////////////////////////////////////////////////////////////////////
// Constants //
///////////////////////////////////////////////////////////////////////////
// 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;
// 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;
// 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;
// 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<String, Integer> LITDEFS;
private static final HashMap<String, OpDef > OPDEFS;
private static final HashMap<String, Integer> SYMDEFS;
// Functional symbol IDs
//private static final int ADDRESS = 0; // Same as error type
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<String, Integer>();
OPDEFS = new HashMap<String, OpDef >();
SYMDEFS = new HashMap<String, Integer>();
// 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 ));
// 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", 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);
};
///////////////////////////////////////////////////////////////////////////
// Classes //
///////////////////////////////////////////////////////////////////////////
// Operator definition
private static class OpDef {
int id; // Identifier
int precedence; // Operator precedence
int type; // Operator category
// Constructor
OpDef(int precedence, int type, int id) {
this.id = id;
this.precedence = precedence;
this.type = type;
}
}
// 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
// Constructor
Token(int type, int start, String text) {
this.start = start;
this.text = text;
this.type = type;
}
// Retrieve the applicable serialized "value"
int flatten() {
return type == FLOAT || type == WORD ? value : id;
}
}
///////////////////////////////////////////////////////////////////////////
// Constructors //
///////////////////////////////////////////////////////////////////////////
// Default 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;
}
///////////////////////////////////////////////////////////////////////////
// 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
public boolean evaluate() {
return vue == null ? false : vue.evaluate(this);
}
// Retrieve the most recent input addresses
public String getAddresses() {
return addresses;
}
// Retrieve the most recent input condition
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 error character position
public int getErrorPosition(int type) {
return type < 0 || type > 1 ? BADTYPE : errPosition[type];
}
// 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
public boolean getException() {
return (hooks & EXCEPTION) != 0;
}
// Retrieve whether the breakpoint hooks executions
public boolean getExecute() {
return (hooks & EXECUTE) != 0;
}
// Retrieve whether the breakpoint hooks reads
public boolean getRead() {
return (hooks & READ) != 0;
}
// Retrieve whether the breakpoint hooks writes
public boolean getWrite() {
return (hooks & WRITE) != 0;
}
// Retrieve the display name
public String getName() {
return name;
}
// Determine whether the breakpoint is enabled
public boolean isEnabled() {
return isEnabled;
}
// Specify and parse a list of address ranges
public boolean setAddresses(String addresses) {
Integer first = null; // Value of first address
int mode = 0; // Processing state
var ranges = new ArrayList<int[]>(); // Output
int start = 0; // Position of address literal
int x = 0; // Input position
// Configure instance fields
this.addresses = addresses == null ? addresses = "" : addresses;
// Parse the input
var chars = (addresses + " ").toCharArray();
for (x = 0; x < chars.length; x++) {
char c = chars[x];
boolean white = c == ' ' || c == '\t';
boolean digit =
c >= '0' && c <= '9' ||
c >= 'A' && c <= 'F' ||
c >= 'a' && c <= 'f'
;
// Before
if (mode == 0) {
// Ignore whitespace
if (white)
continue;
// Begin an address
if (digit) {
start = x;
mode = 1; // During
continue;
}
}
// During
else if (mode == 1) {
// Ignore digits
if (digit)
continue;
// The end of the address has been found
String text = new String(chars, start, x - start);
int addr = 0;
try { addr = (int) Long.parseLong(text, 16); }
// Could not parse the address
catch (Exception e) {
errCode [ADDRESS] = BADLITERAL;
errPosition[ADDRESS] = start + 1;
errText [ADDRESS] = text;
if (vue != null)
vue.updateRanges(this);
return false;
}
// Processed the first address
if (first == null)
first = addr;
// Processed the second address
else {
ranges.add(new int[] { first, addr });
first = null;
}
// Begin searching for a delimiter
mode = 2; // After
x--;
continue;
}
// After
else if (mode == 2) {
// Ignore whitespace
if (white)
continue;
// Begin searching for the second address
if (c == '-' && first != null) {
mode = 0; // Before
continue;
}
// All addresses in the range have been processed
if (c == ',') {
if (first != null) {
ranges.add(new int[] { first, first });
first = null;
}
mode = 0; // Before
continue;
}
}
// Invalid character
errCode [ADDRESS] = UNEXPECTED;
errPosition[ADDRESS] = x + 1;
errText [ADDRESS] = Character.toString(c);
if (vue != null)
vue.updateRanges(this);
return false;
} // x
// Unexpected end of input
if (mode == 0 && ranges.size() > 0) {
errCode [ADDRESS] = EARLYEOF;
errPosition[ADDRESS] = x + 1;
errText [ADDRESS] = "";
if (vue != null)
vue.updateRanges(this);
return false;
}
// A one-address range was processed
if (first != null)
ranges.add(new int[] { first, first });
// Parsing was successful
this.ranges = ranges.toArray(new int[ranges.size()][]);
errCode [ADDRESS] = NONE;
errPosition[ADDRESS] = 0;
errText [ADDRESS] = "";
if (vue != null)
vue.updateRanges(this);
return true;
}
// Specify and parse a condition
public boolean setCondition(String condition) {
// Configure instance fields
this.condition = condition == null ? condition = "" : condition;
errCode [CONDITION] = NONE;
errPosition[CONDITION] = 0;
errText [CONDITION] = "";
tokens = new Token[0];
// Process the expression
var tokens = parse();
if (tokens == null || !validate(tokens)) {
if (vue != null)
vue.updateTokens(this);
return false;
}
tree(tokens);
// The expression is empty
if (tokens.size() == 0) {
if (vue != null)
vue.updateTokens(this);
return true;
}
// Produce an RPN-ordered list of tokens
var tok = tokens.remove(0);
while (tok != null) {
// Traverse to left child node
if (tok.left != null) {
tok = tok.left;
tok.parent.left = null;
continue;
}
// Traverse to right child node
if (tok.right != null) {
tok = tok.right;
tok.parent.right = null;
continue;
}
// No children: add node to output
tokens.add(tok);
tok = tok.parent;
}
this.tokens = tokens.toArray(new Token[tokens.size()]);
// The expression was successfully parsed
if (vue != null)
vue.updateTokens(this);
return true;
}
// Specify whether the breakpoint is enabled
public void setEnabled(boolean enabled) {
isEnabled = enabled;
if (vue != null)
vue.updateState(this);
}
// Specify whether the breakpoint hooks exceptions
public void setException(boolean hook) {
hooks = hook ? hooks | EXCEPTION : hooks & ~EXCEPTION;
if (vue != null)
vue.updateState(this);
}
// Specify whether the breakpoint hooks executions
public void setExecute(boolean hook) {
hooks = hook ? hooks | EXECUTE : hooks & ~EXECUTE;
if (vue != null)
vue.updateState(this);
}
// Specify the display name
public void setName(String name) {
this.name = name == null ? "" : name;
}
// Specify whether the breakpoint hooks reads
public void setRead(boolean hook) {
hooks = hook ? hooks | READ : hooks & ~READ;
if (vue != null)
vue.updateState(this);
}
// Specify whether the breakpoint hooks reads
public void setWrite(boolean hook) {
hooks = hook ? hooks | WRITE : hooks & ~WRITE;
if (vue != null)
vue.updateState(this);
}
///////////////////////////////////////////////////////////////////////////
// Package Methods //
///////////////////////////////////////////////////////////////////////////
// Evaluate the condition for a Java emulation context
boolean evaluate(int[] stack) {
// The condition is empty
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 (stack[1] & (stack[0] == WORD ? 0xFFFFFFFF : 0x7FFFFFFF)) != 0;
}
// Determine the required stack size to evaluate the expression
int depth() {
// Error checking
if (errCode[CONDITION] != 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 FLOAT : // Fallthrough
case SYMBOL: // Fallthrough
case WORD : max = Math.max(max, ++size);
}
return max;
}
// 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++) {
var range = ranges[x];
ret[x / 2 ] = range[0];
ret[x / 2 + 1] = range[1];
}
return ret;
}
// 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++) {
var token = tokens[x];
ret[x / 2 ] = token.type;
ret[x / 2 + 1] = token.flatten();
}
return ret;
}
// Retrieve the bit mask for enabled hooks
int getHooks() {
return hooks;
}
// Retrieve the list of address ranges
int[][] getRanges() {
return ranges;
}
// Retrieve the list of condition tokens
Token[] getTokens() {
return tokens;
}
// The breakpoint is being removed from its emulation context
void remove() {
vue = null;
}
///////////////////////////////////////////////////////////////////////////
// Private 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;
}
// Parse a condition into tokens
private ArrayList<Token> parse() {
var tokens = new ArrayList<Token>();
// Parse the expression
var chars = (condition + " ").toCharArray();
for (int x = 0; x < chars.length; x++) {
char c = chars[x];
// Ignore whitespace
if (c == ' ' || c == '\t')
continue;
// Produce a token based on the first character
Token tok =
c >= '0' && c <= '9' || c == '.' ?
parseLiteral(chars, x) :
c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' ?
parseSymbol (chars, x) :
parseOperator (chars, x)
;
// There was an error processing the token
if (tok == null)
return null;
// Advance to the next token
tokens.add(tok);
x += tok.text.length() - 1;
} // x
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
// 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') {
errCode [CONDITION] = UNEXPECTED;
errPosition[CONDITION] = x + 1;
errText [CONDITION] = Character.toString(c);
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);
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(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;
}
// Could not parse the value
catch (Exception e) {
errCode [CONDITION] = BADLITERAL;
errPosition[CONDITION] = x + 1;
errText [CONDITION] = ret.text;
return null;
}
} // x
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)
continue;
// A matching operator was found
ret.id = def.id;
ret.precedence = def.precedence;
ret.text = text;
ret.type = def.type;
return ret;
}
// 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;
}
// 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
}
// Build an expression tree from a list of tokens
private void tree(ArrayList<Token> tokens) {
// Process all operators
while (tokens.size() > 1) {
int end = tokens.size() - 1;
int start = 0;
// Locate the bounds of the innermost nested group
for (int x = 0; x < end; x++) {
var tok = tokens.get(x);
if (tok.type == OPEN)
start = x + 1;
if (tok.type != CLOSE)
continue;
end = x - 1;
break;
}
// Apply unary operators
for (int x = end; x >= start; x--) {
var tok = tokens.get(x);
if (tok.right != null || tok.type != UNARY)
continue;
tok.right = tokens.remove(x + 1);
tok.right.parent = tok;
end--;
}
// Apply binary operators
while (start != end) {
int index = -1;
Token tok = null;
// Locate the left-most operator with the highest precedence
for (int x = start; x < end; x++) {
var tik = tokens.get(x);
if (tik.right != null || tik.type != BINARY ||
tok != null && tik.precedence >= tok.precedence)
continue;
index = x;
tok = tik;
}
// Apply the operator
tok.right = tokens.remove(index + 1);
tok.left = tokens.remove(index - 1);
tok.left.parent = tok.right.parent = tok;
end -= 2;
}
// There are no group operators
if (tokens.size() == 1)
break;
// 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;
tok.right = tokens.remove(start - 1);
tok.right.parent = tok;
tokens.add(start - 1, tok);
}
} // size
}
// Ensure a sequence of tokens is valid
private boolean validate(ArrayList<Token> tokens) {
int mode = 0;
var stack = new Stack<Token>();
// Validate all tokens
for (var tok : tokens) {
// Expected token mode mismatch
if ((MODES_BEFORE >> tok.type & 1) != mode) {
// The token is invalid
if (tok.id != NEGATE) {
errCode [CONDITION] = INVALID;
errPosition[CONDITION] = tok.start;
errText [CONDITION] = tok.text;
return false;
}
// Convert negate to subtract
tok.id = SUBTRACT;
tok.precedence = 3;
tok.type = BINARY;
}
// Nesting error
if (tok.type == CLOSE &&
(stack.empty() || stack.pop().id != tok.id)) {
errCode [CONDITION] = NESTING;
errPosition[CONDITION] = tok.start;
errText [CONDITION] = tok.text;
return false;
}
// The token opens a group
if (tok.type == OPEN)
stack.push(tok);
// The token is valid
mode = MODES_AFTER >> tok.type & 1;
continue;
}
// A group was not closed
if (!stack.empty()) {
errCode [CONDITION] = EARLYEOF;
errPosition[CONDITION] = condition.length();
errText [CONDITION] = stack.pop().text;
}
// Successfully parsed the condition
return true;
}
///////////////////////////////////////////////////////////////////////////
// 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
private void evalUnary(int id, int[] stack, int size) {
int type = stack[size - 2];
int value = stack[size - 1];
boolean 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);
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;
}
///////////////////////////////////////////////////////////////////////////
// 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;
}
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;
}
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;
}
}