Change flag_disasmAsData to flag_r5900DisasmAsData and redo the logic completely

This commit is contained in:
angie 2023-11-12 10:33:23 -03:00
parent 8b9dddd3b4
commit 80aa0b6c20
10 changed files with 82 additions and 52 deletions

View File

@ -9,7 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### 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.TRUE` forces the instruction to be disassembled as data.
- `TrinaryValue.FALSE` bypasses the global checks for disassembling a word - `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. as data. A word will still be disassembled as data if it can't be decoded.

View File

@ -149,8 +149,8 @@ namespace rabbitizer {
/* flags */ /* flags */
TrinaryValue FlagGet_disasmAsData() const; TrinaryValue FlagGet_r5900DisasmAsData() const;
void FlagSet_disasmAsData(TrinaryValue value); void FlagSet_r5900DisasmAsData(TrinaryValue value);
TrinaryValue FlagGet_r5900UseDollar() const; TrinaryValue FlagGet_r5900UseDollar() const;
void FlagSet_r5900UseDollar(TrinaryValue value); void FlagSet_r5900UseDollar(TrinaryValue value);

View File

@ -648,11 +648,11 @@ void InstructionBase::Set_stype(uint8_t val) {
/* flags */ /* flags */
TrinaryValue InstructionBase::FlagGet_disasmAsData() const { TrinaryValue InstructionBase::FlagGet_r5900DisasmAsData() const {
return static_cast<TrinaryValue>(RAB_INSTR_FLAGS_GET_disasmAsData(&this->instr)); return static_cast<TrinaryValue>(RAB_INSTR_FLAGS_GET_r5900DisasmAsData(&this->instr));
} }
void InstructionBase::FlagSet_disasmAsData(TrinaryValue value) { void InstructionBase::FlagSet_r5900DisasmAsData(TrinaryValue value) {
RAB_INSTR_FLAGS_SET_disasmAsData(&this->instr, static_cast<RabTrinaryValue>(value)); RAB_INSTR_FLAGS_SET_r5900DisasmAsData(&this->instr, static_cast<RabTrinaryValue>(value));
} }
TrinaryValue InstructionBase::FlagGet_r5900UseDollar() const { TrinaryValue InstructionBase::FlagGet_r5900UseDollar() const {

View File

@ -38,7 +38,7 @@ typedef struct RabbitizerInstruction {
* Flags are bitpacked, refer to the `RAB_INSTR_FLAGS_` macros to access them. * Flags are bitpacked, refer to the `RAB_INSTR_FLAGS_` macros to access them.
* *
* Bit usage: * 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_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_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. * - `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_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_GET_r5900DisasmAsData(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_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_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)) #define RAB_INSTR_FLAGS_SET_r5900UseDollar(self, value) ((self)->flags = BITREPACK((self)->flags, (value), 2, 2))

View File

@ -4,7 +4,7 @@
[project] [project]
name = "rabbitizer" name = "rabbitizer"
# Version should be synced with include/common/RabbitizerVersion.h # Version should be synced with include/common/RabbitizerVersion.h
version = "1.8.0.dev0" version = "1.8.0"
description = "MIPS instruction decoder" description = "MIPS instruction decoder"
# license = "MIT" # license = "MIT"
readme = "README.md" readme = "README.md"

View File

@ -61,8 +61,11 @@ class Instruction:
inHandwrittenFunction: bool = False 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.""" """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_r5900DisasmAsData: Enum = TrinaryValue.NONE
"""Flag to override the disasmAsData global configuration. """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.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. - `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.

View File

@ -242,7 +242,7 @@ static PyObject *rabbitizer_type_Instruction_member_get_instrIdType(PyRabbitizer
return 0; \ return 0; \
} }
DEF_MEMBER_FLAG(disasmAsData) DEF_MEMBER_FLAG(r5900DisasmAsData)
DEF_MEMBER_FLAG(r5900UseDollar) 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_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_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[] = { static PyGetSetDef rabbitizer_type_Instruction_getsetters[] = {
MEMBER_GET(rs, "", NULL), MEMBER_GET(rs, "", NULL),
MEMBER_GET(rt, "", NULL), MEMBER_GET(rt, "", NULL),
@ -261,8 +263,8 @@ static PyGetSetDef rabbitizer_type_Instruction_getsetters[] = {
MEMBER_GET(uniqueId, "", NULL), MEMBER_GET(uniqueId, "", NULL),
MEMBER_GET(instrIdType, "", NULL), MEMBER_GET(instrIdType, "", NULL),
MEMBER_GET_SET(flag_disasmAsData, "", NULL), MEMBER_FLAG_GET_SET(r5900DisasmAsData, "", NULL),
MEMBER_GET_SET(flag_r5900UseDollar, "", NULL), MEMBER_FLAG_GET_SET(r5900UseDollar, "", NULL),
{ 0 } { 0 }
}; };

View File

@ -454,10 +454,10 @@ impl Instruction {
self.get_cop2t().try_into().unwrap() 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() 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); self.flags = utils::bitrepack(self.flags, value.try_into().unwrap(), 0, 2);
} }

View File

@ -25,7 +25,7 @@ void RabbitizerInstruction_init(RabbitizerInstruction *self, uint32_t word, uint
self->category = RABBITIZER_INSTRCAT_CPU; self->category = RABBITIZER_INSTRCAT_CPU;
self->flags = 0; 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) { void RabbitizerInstruction_destroy(UNUSED RabbitizerInstruction *self) {

View File

@ -94,31 +94,29 @@ size_t RabbitizerInstruction_disassembleAsData(const RabbitizerInstruction *self
} }
bool RabbitizerInstruction_mustDisasmAsData(const RabbitizerInstruction *self) { bool RabbitizerInstruction_mustDisasmAsData(const RabbitizerInstruction *self) {
switch (RAB_INSTR_FLAGS_GET_disasmAsData(self)) { switch (self->uniqueId) {
case RAB_TRINARY_VAL_TRUE: case RABBITIZER_INSTR_ID_cpu_break:
return true; if (RabbitizerConfig_Cfg.toolchainTweaks.sn64DivFix) {
return true;
case RAB_TRINARY_VAL_FALSE: }
break; break;
case RAB_TRINARY_VAL_NONE: case RABBITIZER_INSTR_ID_cpu_trunc_w_s:
if (RabbitizerConfig_Cfg.toolchainTweaks.sn64DivFix) { case RABBITIZER_INSTR_ID_cpu_cvt_w_s:
if (self->uniqueId == RABBITIZER_INSTR_ID_cpu_break) { if (self->category == RABBITIZER_INSTRCAT_R5900) {
return true; switch (RAB_INSTR_FLAGS_GET_r5900DisasmAsData(self)) {
} case RAB_TRINARY_VAL_TRUE:
} return true;
if (RabbitizerConfig_Cfg.toolchainTweaks.gnuMode) { case RAB_TRINARY_VAL_FALSE:
switch (self->uniqueId) { break;
case RABBITIZER_INSTR_ID_cpu_trunc_w_s:
case RABBITIZER_INSTR_ID_cpu_cvt_w_s: case RAB_TRINARY_VAL_NONE:
if (self->category == RABBITIZER_INSTRCAT_R5900) { if (RabbitizerConfig_Cfg.toolchainTweaks.gnuMode) {
/** /**
* Due to the R5900's FPU being non properly complaint, the instruction cvt.w.s always * 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.
* 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 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 just use trunc.w.s and cvt.w.s as-is.
* *
* Here's some reading about the binutils rationale: * Here's some reading about the binutils rationale:
* - https://sourceware.org/legacy-ml/binutils/2012-11/msg00360.html * - 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. * - trunc.w.s is built as the cvt.w.s instruction.
* - cvt.w.s errors complaining as not being supported by the processor. * - 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 * To ensure the produced disassembly will still match when built with GAS, we decode this two instructions as .word
* two instructions as .word
*/ */
return true; return true;
} }
break; 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; 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)) { if (!RabbitizerInstruction_isValid(self)) {