diff --git a/cplusplus/include/instructions/InstructionBase.hpp b/cplusplus/include/instructions/InstructionBase.hpp index 3462383..1cae5e0 100644 --- a/cplusplus/include/instructions/InstructionBase.hpp +++ b/cplusplus/include/instructions/InstructionBase.hpp @@ -155,7 +155,10 @@ namespace rabbitizer { uint32_t getInstrIndexAsVram() const; int32_t getBranchOffset() const; + //! @deprecated int32_t getGenericBranchOffset(uint32_t currentVram) const; + int32_t getBranchOffsetGeneric() const; + int32_t getBranchVramGeneric() const; std::string getOpcodeName() const; diff --git a/cplusplus/src/instructions/InstructionBase.cpp b/cplusplus/src/instructions/InstructionBase.cpp index 5ad6c4d..7454f83 100644 --- a/cplusplus/src/instructions/InstructionBase.cpp +++ b/cplusplus/src/instructions/InstructionBase.cpp @@ -703,6 +703,26 @@ int32_t InstructionBase::getGenericBranchOffset(uint32_t currentVram) const { return RabbitizerInstruction_getGenericBranchOffset(&this->instr, currentVram); } +int32_t InstructionBase::getBranchOffsetGeneric() const { +#ifdef RAB_SANITY_CHECKS + if (!hasOperandAlias(OperandType::cpu_branch_target_label) && !hasOperandAlias(OperandType::cpu_label)) { + // TODO: make a rabbitizer exception class + throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have either 'branch_target_label' or 'label' operands."); + } +#endif + + return RabbitizerInstruction_getBranchOffsetGeneric(&this->instr); +} +int32_t InstructionBase::getBranchVramGeneric() const { +#ifdef RAB_SANITY_CHECKS + if (!hasOperandAlias(OperandType::cpu_branch_target_label) && !hasOperandAlias(OperandType::cpu_label)) { + // TODO: make a rabbitizer exception class + throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have either 'branch_target_label' or 'label' operands."); + } +#endif + + return RabbitizerInstruction_getBranchVramGeneric(&this->instr); +} std::string InstructionBase::getOpcodeName() const { return InstrId::getOpcodeName(getUniqueId()); diff --git a/include/instructions/RabbitizerInstruction.h b/include/instructions/RabbitizerInstruction.h index 78cd6c8..e109fae 100644 --- a/include/instructions/RabbitizerInstruction.h +++ b/include/instructions/RabbitizerInstruction.h @@ -179,6 +179,10 @@ NODISCARD NON_NULL(1) PURE int32_t RabbitizerInstruction_getBranchOffset(const RabbitizerInstruction *self); NODISCARD NON_NULL(1) PURE int32_t RabbitizerInstruction_getGenericBranchOffset(const RabbitizerInstruction *self, uint32_t currentVram); +NODISCARD NON_NULL(1) PURE +int32_t RabbitizerInstruction_getBranchOffsetGeneric(const RabbitizerInstruction *self); +NODISCARD NON_NULL(1) PURE +int32_t RabbitizerInstruction_getBranchVramGeneric(const RabbitizerInstruction *self); /* General getters */ diff --git a/rabbitizer/rabbitizer.pyi b/rabbitizer/rabbitizer.pyi index 06b4a7f..1f09f20 100644 --- a/rabbitizer/rabbitizer.pyi +++ b/rabbitizer/rabbitizer.pyi @@ -44,12 +44,13 @@ class Instruction: def __init__(self, word: int, vram: int=0, category: Enum=InstrCategory.CPU) -> None: ... def getRaw(self) -> int: ... - #! deprecated - def getImmediate(self) -> int: ... + def getImmediate(self) -> int: ... #! deprecated def getProcessedImmediate(self) -> int: ... def getInstrIndexAsVram(self) -> int: ... def getBranchOffset(self) -> int: ... - def getGenericBranchOffset(self, currentVram: int) -> int: ... + def getGenericBranchOffset(self, currentVram: int) -> int: ... #! deprecated + def getBranchOffsetGeneric(self) -> int: ... + def getBranchVramGeneric(self) -> int: ... def getOpcodeName(self) -> str: ... def blankOut(self) -> None: ... diff --git a/rabbitizer/rabbitizer_type_Instruction.c b/rabbitizer/rabbitizer_type_Instruction.c index e40be2d..dae1083 100644 --- a/rabbitizer/rabbitizer_type_Instruction.c +++ b/rabbitizer/rabbitizer_type_Instruction.c @@ -170,6 +170,9 @@ static PyObject *rabbitizer_type_Instruction_getGenericBranchOffset(PyRabbitizer return PyLong_FromLong(RabbitizerInstruction_getGenericBranchOffset(&self->instr, currentVram)); } +DEF_METHOD_GET_INT(getBranchOffsetGeneric) +DEF_METHOD_GET_INT(getBranchVramGeneric) + static PyObject *rabbitizer_type_Instruction_blankOut(PyRabbitizerInstruction *self, UNUSED PyObject *closure) { RabbitizerInstruction_blankOut(&self->instr); Py_RETURN_NONE; @@ -388,6 +391,8 @@ static PyMethodDef rabbitizer_type_Instruction_methods[] = { METHOD_NO_ARGS(getInstrIndexAsVram, ""), METHOD_NO_ARGS(getBranchOffset, ""), METHOD_ARGS(getGenericBranchOffset, ""), + METHOD_NO_ARGS(getBranchOffsetGeneric, ""), + METHOD_NO_ARGS(getBranchVramGeneric, ""), METHOD_NO_ARGS(getOpcodeName, ""), METHOD_NO_ARGS(blankOut, ""), diff --git a/src/instructions/RabbitizerInstruction/RabbitizerInstruction.c b/src/instructions/RabbitizerInstruction/RabbitizerInstruction.c index 2757702..b4846a0 100644 --- a/src/instructions/RabbitizerInstruction/RabbitizerInstruction.c +++ b/src/instructions/RabbitizerInstruction/RabbitizerInstruction.c @@ -64,6 +64,20 @@ int32_t RabbitizerInstruction_getGenericBranchOffset(const RabbitizerInstruction return RabbitizerInstruction_getBranchOffset(self); } +int32_t RabbitizerInstruction_getBranchOffsetGeneric(const RabbitizerInstruction *self) { + if (RabbitizerInstruction_hasOperandAlias(self, RAB_OPERAND_cpu_label)) { + return RabbitizerInstruction_getInstrIndexAsVram(self) - self->vram; + } + return RabbitizerInstruction_getBranchOffset(self); +} + +int32_t RabbitizerInstruction_getBranchVramGeneric(const RabbitizerInstruction *self) { + if (RabbitizerInstruction_hasOperandAlias(self, RAB_OPERAND_cpu_label)) { + return RabbitizerInstruction_getInstrIndexAsVram(self); + } + return RabbitizerInstruction_getBranchOffset(self) + self->vram; +} + /* General getters */ void RabbitizerInstruction_blankOut(RabbitizerInstruction *self) { diff --git a/src/instructions/RabbitizerInstruction/RabbitizerInstruction_Examination.c b/src/instructions/RabbitizerInstruction/RabbitizerInstruction_Examination.c index 136e4aa..854884f 100644 --- a/src/instructions/RabbitizerInstruction/RabbitizerInstruction_Examination.c +++ b/src/instructions/RabbitizerInstruction/RabbitizerInstruction_Examination.c @@ -48,32 +48,47 @@ bool RabbitizerInstruction_isNop(const RabbitizerInstruction *self) { } bool RabbitizerInstruction_isUnconditionalBranch(const RabbitizerInstruction *self) { - if (self->uniqueId == RABBITIZER_INSTR_ID_cpu_b) { - return true; + switch (self->uniqueId) { + case RABBITIZER_INSTR_ID_cpu_b: + case RABBITIZER_INSTR_ID_rsp_b: + return true; + + case RABBITIZER_INSTR_ID_cpu_beq: + case RABBITIZER_INSTR_ID_rsp_beq: + // in case the b pseudoinstruction is disabled + return RAB_INSTR_GET_rt(self) == 0 && RAB_INSTR_GET_rs(self) == 0; + + case RABBITIZER_INSTR_ID_cpu_j: + case RABBITIZER_INSTR_ID_rsp_j: + return RabbitizerConfig_Cfg.toolchainTweaks.treatJAsUnconditionalBranch; + + default: + return false; } - if (self->uniqueId == RABBITIZER_INSTR_ID_cpu_beq && RAB_INSTR_GET_rt(self) == 0 && RAB_INSTR_GET_rs(self) == 0) { - return true; - } - if (RabbitizerConfig_Cfg.toolchainTweaks.treatJAsUnconditionalBranch && self->uniqueId == RABBITIZER_INSTR_ID_cpu_j) { - return true; - } - return false; } bool RabbitizerInstruction_isJrRa(const RabbitizerInstruction *self) { - if (self->uniqueId == RABBITIZER_INSTR_ID_cpu_jr) { - // TODO: abi stuffs - return RAB_INSTR_GET_rs(self) == RABBITIZER_REG_GPR_O32_ra; + switch (self->uniqueId) { + case RABBITIZER_INSTR_ID_cpu_jr: + case RABBITIZER_INSTR_ID_rsp_jr: + // TODO: abi stuffs + return RAB_INSTR_GET_rs(self) == RABBITIZER_REG_GPR_O32_ra; + + default: + return false; } - return false; } bool RabbitizerInstruction_isJrNotRa(const RabbitizerInstruction *self) { - if (self->uniqueId == RABBITIZER_INSTR_ID_cpu_jr) { - // TODO: abi stuffs - return RAB_INSTR_GET_rs(self) != RABBITIZER_REG_GPR_O32_ra; + switch (self->uniqueId) { + case RABBITIZER_INSTR_ID_cpu_jr: + case RABBITIZER_INSTR_ID_rsp_jr: + // TODO: abi stuffs + return RAB_INSTR_GET_rs(self) != RABBITIZER_REG_GPR_O32_ra; + + default: + return false; } - return false; } bool RabbitizerInstruction_hasDelaySlot(const RabbitizerInstruction *self) {