diff --git a/src/xenia/cpu/cpu_flags.cc b/src/xenia/cpu/cpu_flags.cc index 6c37e7edc..27de03e08 100644 --- a/src/xenia/cpu/cpu_flags.cc +++ b/src/xenia/cpu/cpu_flags.cc @@ -40,6 +40,7 @@ DEFINE_uint64(break_on_instruction, 0, "int3 before the given guest address is executed."); DEFINE_int32(break_condition_gpr, -1, "GPR compared to"); DEFINE_uint64(break_condition_value, 0, "value compared against"); +DEFINE_string(break_condition_op, "eq", "comparison operator"); DEFINE_bool(break_condition_truncate, true, "truncate value to 32-bits"); DEFINE_bool(break_on_debugbreak, true, "int3 on JITed __debugbreak requests."); diff --git a/src/xenia/cpu/cpu_flags.h b/src/xenia/cpu/cpu_flags.h index 17b88ff08..33b71150e 100644 --- a/src/xenia/cpu/cpu_flags.h +++ b/src/xenia/cpu/cpu_flags.h @@ -30,6 +30,7 @@ DECLARE_bool(validate_hir); DECLARE_uint64(break_on_instruction); DECLARE_int32(break_condition_gpr); DECLARE_uint64(break_condition_value); +DECLARE_string(break_condition_op); DECLARE_bool(break_condition_truncate); DECLARE_bool(break_on_debugbreak); diff --git a/src/xenia/cpu/ppc/ppc_hir_builder.cc b/src/xenia/cpu/ppc/ppc_hir_builder.cc index e18118d7b..3187983bb 100644 --- a/src/xenia/cpu/ppc/ppc_hir_builder.cc +++ b/src/xenia/cpu/ppc/ppc_hir_builder.cc @@ -157,21 +157,7 @@ bool PPCHIRBuilder::Emit(GuestFunction* function, uint32_t flags) { ContextBarrier(); } - if (address == FLAGS_break_on_instruction) { - Comment("--break-on-instruction target"); - - if (FLAGS_break_condition_gpr < 0) { - DebugBreak(); - } else { - auto left = LoadGPR(FLAGS_break_condition_gpr); - auto right = LoadConstantUint64(FLAGS_break_condition_value); - if (FLAGS_break_condition_truncate) { - left = Truncate(left, INT32_TYPE); - right = Truncate(right, INT32_TYPE); - } - TrapTrue(CompareEQ(left, right)); - } - } + MaybeBreakOnInstruction(address); InstrData i; i.address = address; @@ -194,6 +180,52 @@ bool PPCHIRBuilder::Emit(GuestFunction* function, uint32_t flags) { return Finalize(); } +void PPCHIRBuilder::MaybeBreakOnInstruction(uint32_t address) { + if (address != FLAGS_break_on_instruction) { + return; + } + + Comment("--break-on-instruction target"); + + if (FLAGS_break_condition_gpr < 0) { + DebugBreak(); + return; + } + + auto left = LoadGPR(FLAGS_break_condition_gpr); + auto right = LoadConstantUint64(FLAGS_break_condition_value); + if (FLAGS_break_condition_truncate) { + left = Truncate(left, INT32_TYPE); + right = Truncate(right, INT32_TYPE); + } + + auto op = FLAGS_break_condition_op.c_str(); + // TODO(rick): table? + if (strcasecmp(op, "eq") == 0) { + TrapTrue(CompareEQ(left, right)); + } else if (strcasecmp(op, "ne") == 0) { + TrapTrue(CompareNE(left, right)); + } else if (strcasecmp(op, "slt") == 0) { + TrapTrue(CompareSLT(left, right)); + } else if (strcasecmp(op, "sle") == 0) { + TrapTrue(CompareSLE(left, right)); + } else if (strcasecmp(op, "sgt") == 0) { + TrapTrue(CompareSGT(left, right)); + } else if (strcasecmp(op, "sge") == 0) { + TrapTrue(CompareSGE(left, right)); + } else if (strcasecmp(op, "ult") == 0) { + TrapTrue(CompareULT(left, right)); + } else if (strcasecmp(op, "ule") == 0) { + TrapTrue(CompareULE(left, right)); + } else if (strcasecmp(op, "ugt") == 0) { + TrapTrue(CompareUGT(left, right)); + } else if (strcasecmp(op, "uge") == 0) { + TrapTrue(CompareUGE(left, right)); + } else { + assert_always(); + } +} + void PPCHIRBuilder::AnnotateLabel(uint32_t address, Label* label) { char name_buffer[13]; snprintf(name_buffer, xe::countof(name_buffer), "loc_%.8X", address); diff --git a/src/xenia/cpu/ppc/ppc_hir_builder.h b/src/xenia/cpu/ppc/ppc_hir_builder.h index 8b88ae35d..a7eb6fc4a 100644 --- a/src/xenia/cpu/ppc/ppc_hir_builder.h +++ b/src/xenia/cpu/ppc/ppc_hir_builder.h @@ -82,6 +82,7 @@ class PPCHIRBuilder : public hir::HIRBuilder { Value* LoadReserved(); private: + void MaybeBreakOnInstruction(uint32_t address); void AnnotateLabel(uint32_t address, Label* label); PPCFrontend* frontend_;