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
- 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.

View File

@ -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);

View File

@ -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 {

View File

@ -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))

View File

@ -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"

View File

@ -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.

View File

@ -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 }
};

View File

@ -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);
}

View File

@ -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) {

View File

@ -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)) {