mirror of
https://github.com/Decompollaborate/rabbitizer.git
synced 2024-12-26 18:14:51 +00:00
Change flag_disasmAsData to flag_r5900DisasmAsData and redo the logic completely
This commit is contained in:
parent
8b9dddd3b4
commit
80aa0b6c20
@ -9,7 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Added
|
||||
|
||||
- Add `flag_disasmAsData` member to the `Instruction` class.
|
||||
- Add `flag_r5900DisasmAsData` member to the `Instruction` class.
|
||||
- This flag allows to fine-tune R5900 instruction set that are affected by
|
||||
the global `gnuMode` option.
|
||||
- Currently these instructions are: `trunc.w.s`, `cvt.w.s`, `vclipw` and
|
||||
`vsqrt`.
|
||||
- `TrinaryValue.TRUE` forces the instruction to be disassembled as data.
|
||||
- `TrinaryValue.FALSE` bypasses the global checks for disassembling a word
|
||||
as data. A word will still be disassembled as data if it can't be decoded.
|
||||
|
@ -149,8 +149,8 @@ namespace rabbitizer {
|
||||
|
||||
/* flags */
|
||||
|
||||
TrinaryValue FlagGet_disasmAsData() const;
|
||||
void FlagSet_disasmAsData(TrinaryValue value);
|
||||
TrinaryValue FlagGet_r5900DisasmAsData() const;
|
||||
void FlagSet_r5900DisasmAsData(TrinaryValue value);
|
||||
|
||||
TrinaryValue FlagGet_r5900UseDollar() const;
|
||||
void FlagSet_r5900UseDollar(TrinaryValue value);
|
||||
|
@ -648,11 +648,11 @@ void InstructionBase::Set_stype(uint8_t val) {
|
||||
|
||||
/* flags */
|
||||
|
||||
TrinaryValue InstructionBase::FlagGet_disasmAsData() const {
|
||||
return static_cast<TrinaryValue>(RAB_INSTR_FLAGS_GET_disasmAsData(&this->instr));
|
||||
TrinaryValue InstructionBase::FlagGet_r5900DisasmAsData() const {
|
||||
return static_cast<TrinaryValue>(RAB_INSTR_FLAGS_GET_r5900DisasmAsData(&this->instr));
|
||||
}
|
||||
void InstructionBase::FlagSet_disasmAsData(TrinaryValue value) {
|
||||
RAB_INSTR_FLAGS_SET_disasmAsData(&this->instr, static_cast<RabTrinaryValue>(value));
|
||||
void InstructionBase::FlagSet_r5900DisasmAsData(TrinaryValue value) {
|
||||
RAB_INSTR_FLAGS_SET_r5900DisasmAsData(&this->instr, static_cast<RabTrinaryValue>(value));
|
||||
}
|
||||
|
||||
TrinaryValue InstructionBase::FlagGet_r5900UseDollar() const {
|
||||
|
@ -38,7 +38,7 @@ typedef struct RabbitizerInstruction {
|
||||
* Flags are bitpacked, refer to the `RAB_INSTR_FLAGS_` macros to access them.
|
||||
*
|
||||
* Bit usage:
|
||||
* - Bits 0 ~ 1: `disasmAsData`. Value of the `RabTrinaryValue` enum.
|
||||
* - Bits 0 ~ 1: `r5900DisasmAsData`. Value of the `RabTrinaryValue` enum.
|
||||
* - `RAB_TRINARY_VAL_TRUE` forces the instruction to be disassembled as data.
|
||||
* - `RAB_TRINARY_VAL_FALSE` bypasses the global checks for disassembling a word as data. A word will still be disassembled as data if it can't be decoded.
|
||||
* - `RAB_TRINARY_VAL_NONE` leaves this decision to the global settings.
|
||||
@ -145,8 +145,8 @@ typedef struct RabbitizerInstruction {
|
||||
#define RAB_INSTR_PACK_stype(word, value) (BITREPACK((word), (value), 6, 5))
|
||||
|
||||
|
||||
#define RAB_INSTR_FLAGS_GET_disasmAsData(self) (RabTrinaryValue)(SHIFTR((self)->flags, 0, 2))
|
||||
#define RAB_INSTR_FLAGS_SET_disasmAsData(self, value) ((self)->flags = BITREPACK((self)->flags, (value), 0, 2))
|
||||
#define RAB_INSTR_FLAGS_GET_r5900DisasmAsData(self) (RabTrinaryValue)(SHIFTR((self)->flags, 0, 2))
|
||||
#define RAB_INSTR_FLAGS_SET_r5900DisasmAsData(self, value) ((self)->flags = BITREPACK((self)->flags, (value), 0, 2))
|
||||
|
||||
#define RAB_INSTR_FLAGS_GET_r5900UseDollar(self) (RabTrinaryValue)(SHIFTR((self)->flags, 2, 2))
|
||||
#define RAB_INSTR_FLAGS_SET_r5900UseDollar(self, value) ((self)->flags = BITREPACK((self)->flags, (value), 2, 2))
|
||||
|
@ -4,7 +4,7 @@
|
||||
[project]
|
||||
name = "rabbitizer"
|
||||
# Version should be synced with include/common/RabbitizerVersion.h
|
||||
version = "1.8.0.dev0"
|
||||
version = "1.8.0"
|
||||
description = "MIPS instruction decoder"
|
||||
# license = "MIT"
|
||||
readme = "README.md"
|
||||
|
@ -61,8 +61,11 @@ class Instruction:
|
||||
inHandwrittenFunction: bool = False
|
||||
"""Boolean value indicating if the current instruction is used on a handwritten function. This is intended to be determined by the user."""
|
||||
|
||||
flag_disasmAsData: Enum = TrinaryValue.NONE
|
||||
"""Flag to override the disasmAsData global configuration.
|
||||
flag_r5900DisasmAsData: Enum = TrinaryValue.NONE
|
||||
"""Flag to override the r5900DisasmAsData global configuration.
|
||||
|
||||
- This flag allows to fine-tune R5900 instruction set that are affected by the global `gnuMode` option.
|
||||
- Currently these instructions are: `trunc.w.s` (r5900 mode), `cvt.w.s` (r5900 mode), `vclipw` and `vsqrt`.
|
||||
|
||||
- `TrinaryValue.TRUE` forces the instruction to be disassembled as data.
|
||||
- `TrinaryValue.FALSE` bypasses the global checks for disassembling a word as data. A word will still be disassembled as data if it can't be decoded.
|
||||
|
@ -242,7 +242,7 @@ static PyObject *rabbitizer_type_Instruction_member_get_instrIdType(PyRabbitizer
|
||||
return 0; \
|
||||
}
|
||||
|
||||
DEF_MEMBER_FLAG(disasmAsData)
|
||||
DEF_MEMBER_FLAG(r5900DisasmAsData)
|
||||
DEF_MEMBER_FLAG(r5900UseDollar)
|
||||
|
||||
|
||||
@ -250,6 +250,8 @@ DEF_MEMBER_FLAG(r5900UseDollar)
|
||||
#define MEMBER_SET(name, docs, closure) { #name, (getter) NULL, (setter) rabbitizer_type_Instruction_member_set_##name, PyDoc_STR(docs), closure }
|
||||
#define MEMBER_GET_SET(name, docs, closure) { #name, (getter) rabbitizer_type_Instruction_member_get_##name, (setter) rabbitizer_type_Instruction_member_set_##name, PyDoc_STR(docs), closure }
|
||||
|
||||
#define MEMBER_FLAG_GET_SET(name, docs, closure) { #name, (getter) rabbitizer_type_Instruction_member_get_flag_##name, (setter) rabbitizer_type_Instruction_member_set_flag_##name, PyDoc_STR(docs), closure }
|
||||
|
||||
static PyGetSetDef rabbitizer_type_Instruction_getsetters[] = {
|
||||
MEMBER_GET(rs, "", NULL),
|
||||
MEMBER_GET(rt, "", NULL),
|
||||
@ -261,8 +263,8 @@ static PyGetSetDef rabbitizer_type_Instruction_getsetters[] = {
|
||||
MEMBER_GET(uniqueId, "", NULL),
|
||||
MEMBER_GET(instrIdType, "", NULL),
|
||||
|
||||
MEMBER_GET_SET(flag_disasmAsData, "", NULL),
|
||||
MEMBER_GET_SET(flag_r5900UseDollar, "", NULL),
|
||||
MEMBER_FLAG_GET_SET(r5900DisasmAsData, "", NULL),
|
||||
MEMBER_FLAG_GET_SET(r5900UseDollar, "", NULL),
|
||||
|
||||
{ 0 }
|
||||
};
|
||||
|
@ -454,10 +454,10 @@ impl Instruction {
|
||||
self.get_cop2t().try_into().unwrap()
|
||||
}
|
||||
|
||||
pub fn flags_get_disasm_as_data(&self) -> utils::TrinaryValue {
|
||||
pub fn flags_get_r5900_disasm_as_data(&self) -> utils::TrinaryValue {
|
||||
utils::shiftr(self.flags, 0, 2).try_into().unwrap()
|
||||
}
|
||||
pub fn flags_set_disasm_as_data(&mut self, value: utils::TrinaryValue) {
|
||||
pub fn flags_set_r5900_disasm_as_data(&mut self, value: utils::TrinaryValue) {
|
||||
self.flags = utils::bitrepack(self.flags, value.try_into().unwrap(), 0, 2);
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ void RabbitizerInstruction_init(RabbitizerInstruction *self, uint32_t word, uint
|
||||
self->category = RABBITIZER_INSTRCAT_CPU;
|
||||
|
||||
self->flags = 0;
|
||||
RAB_INSTR_FLAGS_SET_disasmAsData(self, RAB_TRINARY_VAL_NONE);
|
||||
RAB_INSTR_FLAGS_SET_r5900DisasmAsData(self, RAB_TRINARY_VAL_NONE);
|
||||
}
|
||||
|
||||
void RabbitizerInstruction_destroy(UNUSED RabbitizerInstruction *self) {
|
||||
|
@ -94,31 +94,29 @@ size_t RabbitizerInstruction_disassembleAsData(const RabbitizerInstruction *self
|
||||
}
|
||||
|
||||
bool RabbitizerInstruction_mustDisasmAsData(const RabbitizerInstruction *self) {
|
||||
switch (RAB_INSTR_FLAGS_GET_disasmAsData(self)) {
|
||||
case RAB_TRINARY_VAL_TRUE:
|
||||
return true;
|
||||
|
||||
case RAB_TRINARY_VAL_FALSE:
|
||||
switch (self->uniqueId) {
|
||||
case RABBITIZER_INSTR_ID_cpu_break:
|
||||
if (RabbitizerConfig_Cfg.toolchainTweaks.sn64DivFix) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case RAB_TRINARY_VAL_NONE:
|
||||
if (RabbitizerConfig_Cfg.toolchainTweaks.sn64DivFix) {
|
||||
if (self->uniqueId == RABBITIZER_INSTR_ID_cpu_break) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
case RABBITIZER_INSTR_ID_cpu_trunc_w_s:
|
||||
case RABBITIZER_INSTR_ID_cpu_cvt_w_s:
|
||||
if (self->category == RABBITIZER_INSTRCAT_R5900) {
|
||||
switch (RAB_INSTR_FLAGS_GET_r5900DisasmAsData(self)) {
|
||||
case RAB_TRINARY_VAL_TRUE:
|
||||
return true;
|
||||
|
||||
if (RabbitizerConfig_Cfg.toolchainTweaks.gnuMode) {
|
||||
switch (self->uniqueId) {
|
||||
case RABBITIZER_INSTR_ID_cpu_trunc_w_s:
|
||||
case RABBITIZER_INSTR_ID_cpu_cvt_w_s:
|
||||
if (self->category == RABBITIZER_INSTRCAT_R5900) {
|
||||
case RAB_TRINARY_VAL_FALSE:
|
||||
break;
|
||||
|
||||
case RAB_TRINARY_VAL_NONE:
|
||||
if (RabbitizerConfig_Cfg.toolchainTweaks.gnuMode) {
|
||||
/**
|
||||
* Due to the R5900's FPU being non properly complaint, the instruction cvt.w.s always
|
||||
* behaves as trunc.w.s because EE can only do round-to-zero.
|
||||
* Due to the R5900's FPU being non properly complaint, the instruction cvt.w.s always behaves as trunc.w.s because EE can only do round-to-zero.
|
||||
*
|
||||
* Assemblers like GAS workaround this issue by decoding cvt.w.s as trunc.w.s, but other
|
||||
* assemblers just use trunc.w.s and cvt.w.s as-is.
|
||||
* Assemblers like GAS workaround this issue by decoding cvt.w.s as trunc.w.s, but other assemblers just use trunc.w.s and cvt.w.s as-is.
|
||||
*
|
||||
* Here's some reading about the binutils rationale:
|
||||
* - https://sourceware.org/legacy-ml/binutils/2012-11/msg00360.html
|
||||
@ -128,26 +126,49 @@ bool RabbitizerInstruction_mustDisasmAsData(const RabbitizerInstruction *self) {
|
||||
* - trunc.w.s is built as the cvt.w.s instruction.
|
||||
* - cvt.w.s errors complaining as not being supported by the processor.
|
||||
*
|
||||
* To ensure the produced disassembly will still match when built with GAS, we decode this
|
||||
* two instructions as .word
|
||||
* To ensure the produced disassembly will still match when built with GAS, we decode this two instructions as .word
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case RABBITIZER_INSTR_ID_r5900_vclipw:
|
||||
// The vclipw instruction has variants that are undocumented (vclipw.xy, vclipw.z) and don't
|
||||
// assemble in gnu as
|
||||
return true;
|
||||
case RABBITIZER_INSTR_ID_r5900_vsqrt:
|
||||
// The vclipw instruction seems to be representable in multiple ways, and we only disassemble
|
||||
// one of them
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RABBITIZER_INSTR_ID_r5900_vclipw:
|
||||
switch (RAB_INSTR_FLAGS_GET_r5900DisasmAsData(self)) {
|
||||
case RAB_TRINARY_VAL_TRUE:
|
||||
return true;
|
||||
|
||||
case RAB_TRINARY_VAL_FALSE:
|
||||
break;
|
||||
|
||||
case RAB_TRINARY_VAL_NONE:
|
||||
if (RabbitizerConfig_Cfg.toolchainTweaks.gnuMode) {
|
||||
// The vclipw instruction has variants that are undocumented (vclipw.xy, vclipw.z) and don't assemble in gnu as
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RABBITIZER_INSTR_ID_r5900_vsqrt:
|
||||
switch (RAB_INSTR_FLAGS_GET_r5900DisasmAsData(self)) {
|
||||
case RAB_TRINARY_VAL_TRUE:
|
||||
return true;
|
||||
|
||||
case RAB_TRINARY_VAL_FALSE:
|
||||
break;
|
||||
|
||||
case RAB_TRINARY_VAL_NONE:
|
||||
if (RabbitizerConfig_Cfg.toolchainTweaks.gnuMode) {
|
||||
// The vclipw instruction seems to be representable in multiple ways, and we only disassemble one of them
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!RabbitizerInstruction_isValid(self)) {
|
||||
|
Loading…
Reference in New Issue
Block a user