576 lines
20 KiB
C
576 lines
20 KiB
C
// This file is included through NativeVue.c and cannot be built directly. */
|
|
#ifdef NATIVEVUE
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Constants //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Hook flags
|
|
#define BRK_EXCEPTION 0x00000001
|
|
#define BRK_EXECUTE 0x00000002
|
|
#define BRK_FRAME 0x00000004
|
|
#define BRK_READ 0x00000008
|
|
#define BRK_WRITE 0x00000010
|
|
|
|
// Token types
|
|
#define BRK_BOOL 0 /* Value types */
|
|
#define BRK_SIGNED 1
|
|
#define BRK_UNSIGNED 2
|
|
#define BRK_FLOAT 3
|
|
#define BRK_SYMBOL 4 /* Symbol types */
|
|
#define BRK_PROREG 5
|
|
#define BRK_SYSREG 6
|
|
#define BRK_UNARY 7 /* Operator types */
|
|
#define BRK_BINARY 8
|
|
|
|
|
|
// Functional symbol IDs
|
|
#define BRK_ADDRESS 0
|
|
#define BRK_BREAK 1
|
|
#define BRK_CODE 2
|
|
#define BRK_COND 3
|
|
#define BRK_DISP 4
|
|
#define BRK_FETCH 5
|
|
#define BRK_FORMAT 6
|
|
#define BRK_ID 7
|
|
#define BRK_IMM 8
|
|
#define BRK_OPCODE 9
|
|
#define BRK_REG1 10
|
|
#define BRK_REG2 11
|
|
#define BRK_REGID 12
|
|
#define BRK_SIZE 13
|
|
#define BRK_SUBOPCODE 14
|
|
#define BRK_TYPE 15
|
|
#define BRK_VALUE 16
|
|
#define BRK_VECTOR 17
|
|
|
|
// Evaluation operator IDs
|
|
#define BRK_XS32 1 /* xs32, xword */
|
|
#define BRK_XU32 2 /* xu32, xuword */
|
|
#define BRK_XFLOAT 3 /* xfloat */
|
|
#define BRK_READ8 4 /* [] */
|
|
#define BRK_READ16 5 /* [] */
|
|
#define BRK_READ32 6 /* [] */
|
|
#define BRK_BOOL_ - 2 /* bool */
|
|
#define BRK_S32 - 3 /* s32, word */
|
|
#define BRK_U32 - 4 /* u32, uword */
|
|
#define BRK_FLOAT_ - 5 /* float */
|
|
#define BRK_ADD - 6 /* + */
|
|
#define BRK_AND_B - 7 /* & */
|
|
#define BRK_AND_L - 8 /* && */
|
|
#define BRK_CEIL - 9 /* ceil */
|
|
#define BRK_DIVIDE -10 /* / */
|
|
#define BRK_EQUAL -11 /* == */
|
|
#define BRK_FLOOR -12 /* floor */
|
|
#define BRK_GREATER -13 /* > */
|
|
#define BRK_GREQUAL -14 /* >= */
|
|
#define BRK_LEFT_L -15 /* << */
|
|
#define BRK_LEQUAL -16 /* <= */
|
|
#define BRK_LESS -17 /* < */
|
|
#define BRK_MULTIPLY -18 /* * */
|
|
#define BRK_NEQUAL -19 /* != */
|
|
#define BRK_NOT_B -20 /* ~ */
|
|
#define BRK_NOT_L -21 /* ! */
|
|
#define BRK_NEGATE -22 /* - */
|
|
#define BRK_OR_B -23 /* | */
|
|
#define BRK_OR_L -24 /* || */
|
|
#define BRK_REMAINDER -25 /* % */
|
|
#define BRK_RIGHT_A -26 /* >> */
|
|
#define BRK_RIGHT_L -27 /* >>> */
|
|
#define BRK_ROUND -28 /* round */
|
|
#define BRK_S8 -29 /* s8, byte */
|
|
#define BRK_S16 -30 /* s16, halfword */
|
|
#define BRK_SUBTRACT -31 /* - */
|
|
#define BRK_TRUNC -32 /* trunc */
|
|
#define BRK_U8 -33 /* u8, ubyte */
|
|
#define BRK_U16 -34 /* u16, uhalfword */
|
|
#define BRK_XOR_B -36 /* ^ */
|
|
#define BRK_XOR_L -37 /* ^^ */
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Internal Functions //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Adjust a float value as needed
|
|
static int brkAdjust(float value) {
|
|
int32_t bits = *(int32_t *)&value;
|
|
int exp = bits & 0x7F800000;
|
|
return
|
|
(bits & 0x7FFFFFFF) == 0 || // Zero
|
|
exp == 0x7F800000 || // Indefinite
|
|
exp == 0 // Denormal
|
|
? 0 : bits;
|
|
}
|
|
|
|
// Evaluate a binary operator
|
|
static int32_t brkEvalBinary(int32_t id, int32_t left, int32_t right) {
|
|
|
|
// Processing by ID
|
|
switch (id) {
|
|
|
|
// Add
|
|
case -BRK_ADD * 4 + BRK_BOOL:
|
|
case -BRK_ADD * 4 + BRK_SIGNED:
|
|
case -BRK_ADD * 4 + BRK_UNSIGNED:
|
|
return left + right;
|
|
case -BRK_ADD * 4 + BRK_FLOAT:
|
|
return brkAdjust(*(float *)&left + *(float *)&right);
|
|
|
|
// And Bitwise
|
|
case -BRK_AND_B * 4 + BRK_BOOL:
|
|
case -BRK_AND_B * 4 + BRK_FLOAT: // Prevented by parser
|
|
case -BRK_AND_B * 4 + BRK_SIGNED:
|
|
case -BRK_AND_B * 4 + BRK_UNSIGNED:
|
|
return left & right;
|
|
|
|
// And Logical
|
|
case -BRK_AND_L * 4 + BRK_BOOL:
|
|
case -BRK_AND_L * 4 + BRK_FLOAT:
|
|
case -BRK_AND_L * 4 + BRK_SIGNED:
|
|
case -BRK_AND_L * 4 + BRK_UNSIGNED:
|
|
return left == 0 ? left : right;
|
|
|
|
// Divide
|
|
case -BRK_DIVIDE * 4 + BRK_BOOL:
|
|
case -BRK_DIVIDE * 4 + BRK_SIGNED:
|
|
return right == 0 ? 0 : left / right;
|
|
case -BRK_DIVIDE * 4 + BRK_UNSIGNED:
|
|
return right == 0 ? 0 : (uint32_t) left / right;
|
|
case -BRK_DIVIDE * 4 + BRK_FLOAT:
|
|
return right == 0 ? 0 :
|
|
brkAdjust(*(float *)&left / *(float *)&right);
|
|
|
|
// Equal
|
|
case -BRK_EQUAL * 4 + BRK_BOOL:
|
|
case -BRK_EQUAL * 4 + BRK_FLOAT:
|
|
case -BRK_EQUAL * 4 + BRK_SIGNED:
|
|
case -BRK_EQUAL * 4 + BRK_UNSIGNED:
|
|
return left == right ? 1 : 0;
|
|
|
|
// Greater
|
|
case -BRK_GREATER * 4 + BRK_BOOL:
|
|
case -BRK_GREATER * 4 + BRK_SIGNED:
|
|
return left > right ? 1 : 0;
|
|
case -BRK_GREATER * 4 + BRK_UNSIGNED:
|
|
return (uint32_t) left > right ? 1 : 0;
|
|
case -BRK_GREATER * 4 + BRK_FLOAT:
|
|
return *(float *)&left > *(float *)&right ? 1 : 0;
|
|
|
|
// Greater or Equal
|
|
case -BRK_GREQUAL * 4 + BRK_BOOL:
|
|
case -BRK_GREQUAL * 4 + BRK_SIGNED:
|
|
return left >= right ? 1 : 0;
|
|
case -BRK_GREQUAL * 4 + BRK_UNSIGNED:
|
|
return (uint32_t) left >= right ? 1 : 0;
|
|
case -BRK_GREQUAL * 4 + BRK_FLOAT:
|
|
return *(float *)&left >= *(float *)&right ? 1 : 0;
|
|
|
|
// Shift Left
|
|
case -BRK_LEFT_L * 4 + BRK_BOOL:
|
|
case -BRK_LEFT_L * 4 + BRK_FLOAT: // Prevented by parser
|
|
case -BRK_LEFT_L * 4 + BRK_SIGNED:
|
|
case -BRK_LEFT_L * 4 + BRK_UNSIGNED:
|
|
return left << (right & 31);
|
|
|
|
// Less or Equal
|
|
case -BRK_LEQUAL * 4 + BRK_BOOL:
|
|
case -BRK_LEQUAL * 4 + BRK_SIGNED:
|
|
return left <= right ? 1 : 0;
|
|
case -BRK_LEQUAL * 4 + BRK_UNSIGNED:
|
|
return (uint32_t) left <= right ? 1 : 0;
|
|
case -BRK_LEQUAL * 4 + BRK_FLOAT:
|
|
return *(float *)&left <= *(float *)&right ? 1 : 0;
|
|
|
|
// Less
|
|
case -BRK_LESS * 4 + BRK_BOOL:
|
|
case -BRK_LESS * 4 + BRK_SIGNED:
|
|
return left < right ? 1 : 0;
|
|
case -BRK_LESS * 4 + BRK_UNSIGNED:
|
|
return (uint32_t) left < right ? 1 : 0;
|
|
case -BRK_LESS * 4 + BRK_FLOAT:
|
|
return *(float *)&left < *(float *)&right ? 1 : 0;
|
|
|
|
// Multiply
|
|
case -BRK_MULTIPLY * 4 + BRK_BOOL:
|
|
case -BRK_MULTIPLY * 4 + BRK_SIGNED:
|
|
return left * right;
|
|
case -BRK_MULTIPLY * 4 + BRK_UNSIGNED:
|
|
return (uint32_t) left * right;
|
|
case -BRK_MULTIPLY * 4 + BRK_FLOAT:
|
|
return brkAdjust(*(float *)&left * *(float *)&right);
|
|
|
|
// Not Equal
|
|
case -BRK_NEQUAL * 4 + BRK_BOOL:
|
|
case -BRK_NEQUAL * 4 + BRK_FLOAT:
|
|
case -BRK_NEQUAL * 4 + BRK_SIGNED:
|
|
case -BRK_NEQUAL * 4 + BRK_UNSIGNED:
|
|
return left != right ? 1 : 0;
|
|
|
|
// Or Bitwise
|
|
case -BRK_OR_B * 4 + BRK_BOOL:
|
|
case -BRK_OR_B * 4 + BRK_FLOAT: // Prevented by parser
|
|
case -BRK_OR_B * 4 + BRK_SIGNED:
|
|
case -BRK_OR_B * 4 + BRK_UNSIGNED:
|
|
return left | right;
|
|
|
|
// Or Logical
|
|
case -BRK_OR_L * 4 + BRK_BOOL:
|
|
case -BRK_OR_L * 4 + BRK_FLOAT:
|
|
case -BRK_OR_L * 4 + BRK_SIGNED:
|
|
case -BRK_OR_L * 4 + BRK_UNSIGNED:
|
|
return left != 0 ? left : right;
|
|
|
|
// Remainder
|
|
case -BRK_REMAINDER * 4 + BRK_BOOL:
|
|
case -BRK_REMAINDER * 4 + BRK_SIGNED:
|
|
return right == 0 ? 0 : left % right;
|
|
case -BRK_REMAINDER * 4 + BRK_UNSIGNED:
|
|
return right == 0 ? 0 : (uint32_t) left % right;
|
|
case -BRK_REMAINDER * 4 + BRK_FLOAT:
|
|
return right == 0 ? 0 :
|
|
brkAdjust(fmodf(*(float *)&left, *(float *)&right));
|
|
|
|
// Shift Right Arithmetic
|
|
case -BRK_RIGHT_A * 4 + BRK_BOOL:
|
|
case -BRK_RIGHT_A * 4 + BRK_FLOAT: // Prevented by parser
|
|
case -BRK_RIGHT_A * 4 + BRK_SIGNED:
|
|
case -BRK_RIGHT_A * 4 + BRK_UNSIGNED:
|
|
return SIGN_EXTEND(left >> (right & 31), 32 - (right & 31));
|
|
|
|
// Shift Right Logical
|
|
case -BRK_RIGHT_L * 4 + BRK_BOOL:
|
|
case -BRK_RIGHT_L * 4 + BRK_FLOAT: // Prevented by parser
|
|
case -BRK_RIGHT_L * 4 + BRK_SIGNED:
|
|
case -BRK_RIGHT_L * 4 + BRK_UNSIGNED:
|
|
return left >> (right & 31) & ((int32_t) -1 << (right & 31));
|
|
|
|
// Subtract
|
|
case -BRK_SUBTRACT * 4 + BRK_BOOL:
|
|
case -BRK_SUBTRACT * 4 + BRK_SIGNED:
|
|
case -BRK_SUBTRACT * 4 + BRK_UNSIGNED:
|
|
return left - right;
|
|
case -BRK_SUBTRACT * 4 + BRK_FLOAT:
|
|
return brkAdjust(*(float *)&left - *(float *)&right);
|
|
|
|
// Exclusive Or Bitwise
|
|
case -BRK_XOR_B * 4 + BRK_BOOL:
|
|
case -BRK_XOR_B * 4 + BRK_FLOAT: // Prevented by parser
|
|
case -BRK_XOR_B * 4 + BRK_SIGNED:
|
|
case -BRK_XOR_B * 4 + BRK_UNSIGNED:
|
|
return left ^ right;
|
|
|
|
// Exclusive Or Logical
|
|
case -BRK_XOR_L * 4 + BRK_BOOL:
|
|
case -BRK_XOR_L * 4 + BRK_FLOAT:
|
|
case -BRK_XOR_L * 4 + BRK_SIGNED:
|
|
case -BRK_XOR_L * 4 + BRK_UNSIGNED:
|
|
return left != 0 && right != 0 ? 0 : left != 0 ? left : right;
|
|
|
|
}
|
|
|
|
// Unreachable
|
|
return 0;
|
|
}
|
|
|
|
// Evaluate a unary operator
|
|
static int32_t brkEvalUnary(Vue *vue, int32_t id, int32_t operand) {
|
|
float val; // Working variable
|
|
|
|
// Processing by ID
|
|
switch (id) {
|
|
|
|
// Cast to Boolean
|
|
case -BRK_BOOL_ * 4 + BRK_BOOL: // Removed by parser
|
|
case -BRK_BOOL_ * 4 + BRK_FLOAT:
|
|
case -BRK_BOOL_ * 4 + BRK_SIGNED:
|
|
case -BRK_BOOL_ * 4 + BRK_UNSIGNED:
|
|
return operand == 0 ? 0 : 1;
|
|
|
|
// Round up
|
|
case -BRK_CEIL * 4 + BRK_BOOL: // Removed by parser
|
|
case -BRK_CEIL * 4 + BRK_FLOAT:
|
|
case -BRK_CEIL * 4 + BRK_SIGNED: // Removed by parser
|
|
case -BRK_CEIL * 4 + BRK_UNSIGNED: // Removed by parser
|
|
return brkAdjust(ceilf(*(float *)&operand));
|
|
|
|
// Cast to Float
|
|
case -BRK_FLOAT_ * 4 + BRK_BOOL:
|
|
case -BRK_FLOAT_ * 4 + BRK_FLOAT: // Removed by parser
|
|
case -BRK_FLOAT_ * 4 + BRK_SIGNED:
|
|
return brkAdjust(operand);
|
|
case -BRK_FLOAT_ * 4 + BRK_UNSIGNED:
|
|
return brkAdjust((uint32_t) operand);
|
|
|
|
// Round down
|
|
case -BRK_FLOOR * 4 + BRK_BOOL: // Removed by parser
|
|
case -BRK_FLOOR * 4 + BRK_FLOAT:
|
|
case -BRK_FLOOR * 4 + BRK_SIGNED: // Removed by parser
|
|
case -BRK_FLOOR * 4 + BRK_UNSIGNED: // Removed by parser
|
|
return brkAdjust(floorf(*(float *)&operand));
|
|
|
|
// Bitwise Not
|
|
case -BRK_NOT_B * 4 + BRK_BOOL:
|
|
case -BRK_NOT_B * 4 + BRK_FLOAT: // Prevented by parser
|
|
case -BRK_NOT_B * 4 + BRK_SIGNED:
|
|
case -BRK_NOT_B * 4 + BRK_UNSIGNED:
|
|
return ~operand;
|
|
|
|
// Logical Not
|
|
case -BRK_NOT_L * 4 + BRK_BOOL:
|
|
case -BRK_NOT_L * 4 + BRK_FLOAT:
|
|
case -BRK_NOT_L * 4 + BRK_SIGNED:
|
|
case -BRK_NOT_L * 4 + BRK_UNSIGNED:
|
|
return operand == 0 ? 1 : 0;
|
|
|
|
// Negate
|
|
case -BRK_NEGATE * 4 + BRK_BOOL:
|
|
case -BRK_NEGATE * 4 + BRK_SIGNED:
|
|
case -BRK_NEGATE * 4 + BRK_UNSIGNED: // Removed by parser
|
|
return -operand;
|
|
case -BRK_NEGATE * 4 + BRK_FLOAT:
|
|
return brkAdjust(-*(float *)&operand);
|
|
|
|
// Read Byte
|
|
case BRK_READ8:
|
|
return vueRead(vue, operand, VUE_S8);
|
|
|
|
// Read Halfword
|
|
case BRK_READ16:
|
|
return vueRead(vue, operand, VUE_S16);
|
|
|
|
// Read Word
|
|
case BRK_READ32:
|
|
return vueRead(vue, operand, VUE_S32);
|
|
|
|
// Round to Nearest
|
|
case -BRK_ROUND * 4 + BRK_BOOL: // Removed by parser
|
|
case -BRK_ROUND * 4 + BRK_FLOAT:
|
|
case -BRK_ROUND * 4 + BRK_SIGNED: // Removed by parser
|
|
case -BRK_ROUND * 4 + BRK_UNSIGNED: // Removed by parser
|
|
return brkAdjust(roundf(*(float *)&operand));
|
|
|
|
// Cast to Signed Byte
|
|
case -BRK_S8 * 4 + BRK_FLOAT:
|
|
operand = brkEvalUnary(vue, -BRK_S32 * 4 + BRK_FLOAT, operand);
|
|
// Fallthrough
|
|
case -BRK_S8 * 4 + BRK_BOOL:
|
|
case -BRK_S8 * 4 + BRK_SIGNED:
|
|
case -BRK_S8 * 4 + BRK_UNSIGNED:
|
|
return SIGN_EXTEND(operand, 8);
|
|
|
|
// Cast to Signed Halfword
|
|
case -BRK_S16 * 4 + BRK_FLOAT:
|
|
operand = brkEvalUnary(vue, -BRK_S32 * 4 + BRK_FLOAT, operand);
|
|
// Fallthrough
|
|
case -BRK_S16 * 4 + BRK_BOOL:
|
|
case -BRK_S16 * 4 + BRK_SIGNED:
|
|
case -BRK_S16 * 4 + BRK_UNSIGNED:
|
|
return SIGN_EXTEND(operand, 16);
|
|
|
|
// Cast to Signed Word
|
|
case -BRK_S32 * 4 + BRK_BOOL:
|
|
case -BRK_S32 * 4 + BRK_SIGNED: // Removed by parser
|
|
case -BRK_S32 * 4 + BRK_UNSIGNED:
|
|
return operand;
|
|
case -BRK_S32 * 4 + BRK_FLOAT:
|
|
val = *(float *)&operand;
|
|
return val >= -MAX_WORD && val < MAX_WORD ? (int32_t) val : 0;
|
|
|
|
// Truncate
|
|
case -BRK_TRUNC * 4 + BRK_BOOL: // Removed by parser
|
|
case -BRK_TRUNC * 4 + BRK_FLOAT:
|
|
case -BRK_TRUNC * 4 + BRK_SIGNED: // Removed by parser
|
|
case -BRK_TRUNC * 4 + BRK_UNSIGNED: // Removed by parser
|
|
return brkAdjust(truncf(*(float *)&operand));
|
|
|
|
// Cast to Unsigned Byte
|
|
case -BRK_U8 * 4 + BRK_FLOAT:
|
|
operand = brkEvalUnary(vue, -BRK_S32 * 4 + BRK_FLOAT, operand);
|
|
case -BRK_U8 * 4 + BRK_BOOL:
|
|
case -BRK_U8 * 4 + BRK_SIGNED:
|
|
case -BRK_U8 * 4 + BRK_UNSIGNED:
|
|
return operand & 0xFF;
|
|
|
|
// Cast to Unsigned Halfword
|
|
case -BRK_U16 * 4 + BRK_FLOAT:
|
|
operand = brkEvalUnary(vue, -BRK_S32 * 4 + BRK_FLOAT, operand);
|
|
case -BRK_U16 * 4 + BRK_BOOL:
|
|
case -BRK_U16 * 4 + BRK_SIGNED:
|
|
case -BRK_U16 * 4 + BRK_UNSIGNED:
|
|
return operand & 0xFFFF;
|
|
|
|
// Cast to Unsigned Word
|
|
case -BRK_U32 * 4 + BRK_BOOL:
|
|
case -BRK_U32 * 4 + BRK_SIGNED:
|
|
case -BRK_U32 * 4 + BRK_UNSIGNED: // Removed by parser
|
|
return operand;
|
|
case -BRK_U32 * 4 + BRK_FLOAT:
|
|
val = *(float *)&operand;
|
|
return val >= 0 && val < MAX_UWORD ? (uint32_t) val : 0;
|
|
|
|
// Reinterpret as Float
|
|
case BRK_XFLOAT:
|
|
return brkAdjust(*(float *)&operand);
|
|
|
|
// Reinterpret as Signed Word, Reinterpret as Unsigned Word
|
|
//case BRK_XS32: // Removed by parser
|
|
//case BRK_XU32: // Removed by parser
|
|
}
|
|
|
|
// Unreachable
|
|
return 0;
|
|
}
|
|
|
|
// Evaluate the condition, returning only the computed value
|
|
static int32_t brkEvaluate(Core *core, Breakpoint *brk) {
|
|
int32_t *stack = core->stack;
|
|
Vue *vue = &core->vue;
|
|
|
|
// Process all tokens
|
|
int size = 0;
|
|
Token *tok;
|
|
int32_t x, sym; // Working variables
|
|
for (tok = &brk->tokens[x=0]; x < brk->numTokens; tok = &brk->tokens[++x])
|
|
switch (tok->type) {
|
|
|
|
// Binary operator
|
|
case BRK_BINARY:
|
|
stack[size - 2] =
|
|
brkEvalBinary(tok->id, stack[size - 2], stack[size - 1]);
|
|
size--;
|
|
break;
|
|
|
|
// Literal
|
|
case BRK_BOOL:
|
|
case BRK_FLOAT:
|
|
case BRK_SIGNED:
|
|
case BRK_UNSIGNED:
|
|
stack[size++] = tok->id;
|
|
break;
|
|
|
|
// CPU register
|
|
case BRK_PROREG:
|
|
case BRK_SYSREG:
|
|
stack[size++] = vueGetRegister(vue,tok->id,tok->type==BRK_SYSREG);
|
|
break;
|
|
|
|
// Unary operator
|
|
case BRK_UNARY:
|
|
stack[size - 1] = brkEvalUnary(vue, tok->id, stack[size - 1]);
|
|
break;
|
|
|
|
// Symbol
|
|
case BRK_SYMBOL:
|
|
sym = vue->cpu.inst.imm; // IMM, REGID, VECTOR
|
|
switch (tok->id) {
|
|
case BRK_ADDRESS : sym = vue->cpu.access.address; break;
|
|
case BRK_BREAK : sym = core->breakType ; break;
|
|
case BRK_CODE : sym = vue->cpu.exception ; break;
|
|
case BRK_COND : sym = vue->cpu.inst.cond ; break;
|
|
case BRK_DISP : sym = vue->cpu.inst.disp ; break;
|
|
case BRK_FETCH : sym = vue->cpu.fetch ; break;
|
|
case BRK_FORMAT : sym = vue->cpu.inst.format ; break;
|
|
case BRK_ID : sym = vue->cpu.inst.id ; break;
|
|
case BRK_OPCODE : sym = vue->cpu.inst.opcode ; break;
|
|
case BRK_REG1 : sym = vue->cpu.inst.reg1 ; break;
|
|
case BRK_REG2 : sym = vue->cpu.inst.reg2 ; break;
|
|
case BRK_SIZE : sym = vue->cpu.inst.size ; break;
|
|
case BRK_SUBOPCODE: sym = vue->cpu.inst.subopcode; break;
|
|
case BRK_TYPE : sym = vue->cpu.access.type ; break;
|
|
case BRK_VALUE : sym = vue->cpu.access.value ; break;
|
|
}
|
|
stack[size++] = sym;
|
|
break;
|
|
|
|
}
|
|
|
|
// Return the remaining stack value
|
|
return stack[0];
|
|
}
|
|
|
|
// Determine whether the breakpoint applies to a given address range
|
|
static vbool brkInRange(Breakpoint *brk, uint32_t start, uint32_t end) {
|
|
|
|
// Implicit inclusion
|
|
if (brk->numRanges == 0)
|
|
return VUE_TRUE;
|
|
|
|
// Check all ranges
|
|
for (int x = 0; x < brk->numRanges; x++) {
|
|
uint32_t *range = &brk->ranges[x * 2];
|
|
if (
|
|
start - range[0] <= range[1] - range[0] ||
|
|
range[0] - start <= end - start
|
|
) return VUE_TRUE;
|
|
}
|
|
return VUE_FALSE;
|
|
}
|
|
|
|
// Check for breakpoints
|
|
static int32_t brkOnBreakpoint(Vue *vue, int32_t breakType) {
|
|
Core *core = (Core *) vue->tag;
|
|
uint32_t end = 0;
|
|
vbool ranged = VUE_FALSE;
|
|
uint32_t start = 0;
|
|
core->breakType = breakType;
|
|
|
|
// Processing for Execute
|
|
if (breakType == BRK_EXECUTE) {
|
|
ranged = VUE_TRUE;
|
|
start = vue->cpu.pc;
|
|
end = start + vue->cpu.inst.size - 1;
|
|
}
|
|
|
|
// Processing for Read and Write
|
|
else if (breakType == BRK_READ || breakType == BRK_WRITE) {
|
|
ranged = VUE_TRUE;
|
|
start = vue->cpu.access.address;
|
|
end = start + TYPE_SIZES[vue->cpu.access.type] - 1;
|
|
}
|
|
|
|
// Check all breakpoints
|
|
for (int x = 0; x < core->numBreakpoints; x++) {
|
|
Breakpoint *brk = &core->breakpoints[x];
|
|
if (
|
|
brk->enabled &&
|
|
(breakType == 0 || (breakType & brk->hooks) != 0) &&
|
|
(!ranged || brkInRange(brk, start, end)) &&
|
|
(brk->numTokens == 0 || brkEvaluate(core, brk) != 0)
|
|
) return x + 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Check for exception breakpoints
|
|
static int32_t brkOnException(Vue *vue, uint16_t code) {
|
|
return brkOnBreakpoint(vue, BRK_EXCEPTION);
|
|
}
|
|
|
|
// Check for execute breakpoints
|
|
static int32_t brkOnExecute(Vue *vue, VueInstruction *inst) {
|
|
return brkOnBreakpoint(vue, BRK_EXECUTE);
|
|
}
|
|
|
|
// Check for frame breakpoints
|
|
static int32_t brkOnFrame(Vue *vue) {
|
|
return brkOnBreakpoint(vue, BRK_FRAME);
|
|
}
|
|
|
|
// Check for read breakpoints
|
|
static int32_t brkOnRead(Vue *vue, VueAccess *acc) {
|
|
return brkOnBreakpoint(vue, BRK_READ);
|
|
}
|
|
|
|
// Check for write breakpoints
|
|
static int32_t brkOnWrite(Vue *vue, VueAccess *acc) {
|
|
return brkOnBreakpoint(vue, BRK_WRITE);
|
|
}
|
|
|
|
|
|
|
|
#endif // NATIVEVUE
|