mirror of
https://github.com/Decompollaborate/rabbitizer.git
synced 2025-02-05 18:40:12 +00:00
commit
2231c7dde0
31
.gitattributes
vendored
31
.gitattributes
vendored
@ -1,2 +1,33 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
src/instructions/RabbitizerInstruction/instrOpercandCallbacks_array.table.h linguist-generated=true
|
||||
|
||||
src/instructions/InstrCategory_Names_array.table.h linguist-generated=true
|
||||
src/instructions/InstrDescriptor_Descriptors_array.table.h linguist-generated=true
|
||||
src/instructions/InstrId_Names_array.table.h linguist-generated=true
|
||||
src/instructions/RegisterDescriptor_Descriptors_arrays.table.h linguist-generated=true
|
||||
src/instructions/Registers_Names_arrays.table.h linguist-generated=true
|
||||
|
||||
include/common/Abi_enum.table.h linguist-generated=true
|
||||
|
||||
include/instructions/AccessType_enum.table.h linguist-generated=true
|
||||
include/instructions/InstrCategory_enum.table.h linguist-generated=true
|
||||
include/instructions/InstrId_enum.table.h linguist-generated=true
|
||||
include/instructions/InstrSuffix_enum.table.h linguist-generated=true
|
||||
include/instructions/OperandType_enum.table.h linguist-generated=true
|
||||
include/instructions/OperandType_function_declarations.table.h linguist-generated=true
|
||||
include/instructions/Registers_enums.table.h linguist-generated=true
|
||||
|
||||
cplusplus/include/instructions/AccessType_enum_class.table.h linguist-generated=true
|
||||
cplusplus/include/instructions/OperandType_enum_class.table.h linguist-generated=true
|
||||
cplusplus/include/instructions/Registers_enum_classes.table.h linguist-generated=true
|
||||
cplusplus/include/instructions/UniqueId_enum_class.table.h linguist-generated=true
|
||||
|
||||
rust/src/abi_enum.rs linguist-generated=true
|
||||
rust/src/access_type_enum.rs linguist-generated=true
|
||||
rust/src/instr_category_enum.rs linguist-generated=true
|
||||
rust/src/instr_id_enum.rs linguist-generated=true
|
||||
rust/src/instr_suffix_enum.rs linguist-generated=true
|
||||
rust/src/operand_type_enum.rs linguist-generated=true
|
||||
rust/src/registers_enum.rs linguist-generated=true
|
||||
|
@ -4,7 +4,7 @@
|
||||
[package]
|
||||
name = "rabbitizer"
|
||||
# Version should be synced with include/common/RabbitizerVersion.h
|
||||
version = "1.5.11"
|
||||
version = "1.6.0"
|
||||
edition = "2021"
|
||||
authors = ["Anghelo Carvajal <angheloalf95@gmail.com>"]
|
||||
description = "MIPS instruction decoder"
|
||||
|
@ -537,7 +537,6 @@ r5900_madda_s,
|
||||
r5900_msuba_s,
|
||||
r5900_max_s,
|
||||
r5900_min_s,
|
||||
r5900_trunc_w_s,
|
||||
r5900_c_lt_s,
|
||||
r5900_c_le_s,
|
||||
r5900_qmfc2,
|
||||
|
@ -49,6 +49,11 @@ typedef struct RabbitizerConfig_ToolchainTweaks {
|
||||
* So we replace break instrutions for SN64 with the exact word that the assembler generates when expanding div
|
||||
*/
|
||||
bool sn64DivFix;
|
||||
/**
|
||||
* Enables various tweaks to allow building matching with GNU as which
|
||||
* break original compiler behavior and what's specified in the manuals.
|
||||
*/
|
||||
bool gnuMode;
|
||||
} RabbitizerConfig_ToolchainTweaks;
|
||||
|
||||
typedef struct RabbitizerConfig_Misc {
|
||||
|
@ -13,8 +13,8 @@ extern "C" {
|
||||
|
||||
// Header version
|
||||
#define RAB_VERSION_MAJOR 1
|
||||
#define RAB_VERSION_MINOR 5
|
||||
#define RAB_VERSION_PATCH 11
|
||||
#define RAB_VERSION_MINOR 6
|
||||
#define RAB_VERSION_PATCH 0
|
||||
|
||||
#define RAB_VERSION_STR RAB_STRINGIFY(RAB_VERSION_MAJOR) "." RAB_STRINGIFY(RAB_VERSION_MINOR) "." RAB_STRINGIFY(RAB_VERSION_PATCH)
|
||||
|
||||
|
1
include/instructions/InstrId_enum.table.h
generated
1
include/instructions/InstrId_enum.table.h
generated
@ -537,7 +537,6 @@ RABBITIZER_INSTR_ID_r5900_madda_s,
|
||||
RABBITIZER_INSTR_ID_r5900_msuba_s,
|
||||
RABBITIZER_INSTR_ID_r5900_max_s,
|
||||
RABBITIZER_INSTR_ID_r5900_min_s,
|
||||
RABBITIZER_INSTR_ID_r5900_trunc_w_s,
|
||||
RABBITIZER_INSTR_ID_r5900_c_lt_s,
|
||||
RABBITIZER_INSTR_ID_r5900_c_le_s,
|
||||
RABBITIZER_INSTR_ID_r5900_qmfc2,
|
||||
|
@ -103,19 +103,6 @@ RABBITIZER_DEF_INSTR_ID_ALTNAME(
|
||||
.readsFt=true
|
||||
) // floating point MINimum
|
||||
|
||||
// Due to the R5900's FPU being non properly complaint the instruction cvt.w.s always behaves as trunc.w.s because is because EE can only do round-to-zero.
|
||||
// Assemblers like GAS workaround this issue by decoding cvt.w.s as trunc.w.s, so we mimic that behaviour to allow assembling with GAS.
|
||||
// Here's some reading about the binutils rationale:
|
||||
// https://sourceware.org/legacy-ml/binutils/2012-11/msg00360.html
|
||||
// https://sourceware.org/pipermail/binutils/2013-January/079863.html
|
||||
RABBITIZER_DEF_INSTR_ID_ALTNAME(
|
||||
r5900, 0x24, trunc_w_s, trunc.w.s,
|
||||
.operands={RAB_OPERAND_cpu_fd, RAB_OPERAND_cpu_fs},
|
||||
.isFloat=true,
|
||||
.modifiesFd=true,
|
||||
.readsFs=true
|
||||
) // Floating-Point Truncate to Word Fixed-Point
|
||||
|
||||
RABBITIZER_DEF_INSTR_ID_ALTNAME(
|
||||
r5900, 0x34, c_lt_s, c.lt.s,
|
||||
.operands={RAB_OPERAND_cpu_fs, RAB_OPERAND_cpu_ft},
|
||||
|
@ -4,7 +4,7 @@
|
||||
[project]
|
||||
name = "rabbitizer"
|
||||
# Version should be synced with include/common/RabbitizerVersion.h
|
||||
version = "1.5.11"
|
||||
version = "1.6.0"
|
||||
description = "MIPS instruction decoder"
|
||||
# license = "MIT"
|
||||
readme = "README.md"
|
||||
|
@ -35,8 +35,9 @@ class _RabbitizerConfig:
|
||||
pseudos_pseudoNegu: bool = True
|
||||
pseudos_pseudoBal: bool = True
|
||||
|
||||
toolchainTweaks_sn64DivFix: bool = False
|
||||
toolchainTweaks_treatJAsUnconditionalBranch: bool = False
|
||||
toolchainTweaks_sn64DivFix: bool = False
|
||||
toolchainTweaks_gnuMode: bool = True
|
||||
|
||||
misc_opcodeLJust: int = 11
|
||||
misc_unknownInstrComment: bool = True
|
||||
|
@ -118,6 +118,7 @@ DEF_MEMBER_GET_SET_BOOL(pseudos, pseudoBal)
|
||||
|
||||
DEF_MEMBER_GET_SET_BOOL(toolchainTweaks, treatJAsUnconditionalBranch)
|
||||
DEF_MEMBER_GET_SET_BOOL(toolchainTweaks, sn64DivFix)
|
||||
DEF_MEMBER_GET_SET_BOOL(toolchainTweaks, gnuMode)
|
||||
|
||||
DEF_MEMBER_GET_SET_INT(misc, opcodeLJust, false, 0, 0)
|
||||
DEF_MEMBER_GET_SET_BOOL(misc, unknownInstrComment)
|
||||
@ -144,6 +145,7 @@ static PyGetSetDef rabbitizer_global_config_GetSets[] = {
|
||||
|
||||
MEMBER_GET_SET(toolchainTweaks, treatJAsUnconditionalBranch, "", NULL),
|
||||
MEMBER_GET_SET(toolchainTweaks, sn64DivFix, "", NULL),
|
||||
MEMBER_GET_SET(toolchainTweaks, gnuMode, "", NULL),
|
||||
|
||||
MEMBER_GET_SET(misc, opcodeLJust, "", NULL),
|
||||
MEMBER_GET_SET(misc, unknownInstrComment, "", NULL),
|
||||
|
@ -35,6 +35,7 @@ pub struct PseudoInstr {
|
||||
pub struct ToolchainTweaks {
|
||||
pub treat_j_as_unconditional_branch: bool,
|
||||
pub sn64_div_fix: bool,
|
||||
pub gnu_mode: bool,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
1
rust/src/instr_id_enum.rs
generated
1
rust/src/instr_id_enum.rs
generated
@ -537,7 +537,6 @@ r5900_madda_s,
|
||||
r5900_msuba_s,
|
||||
r5900_max_s,
|
||||
r5900_min_s,
|
||||
r5900_trunc_w_s,
|
||||
r5900_c_lt_s,
|
||||
r5900_c_le_s,
|
||||
r5900_qmfc2,
|
||||
|
@ -40,6 +40,7 @@ RabbitizerConfig RabbitizerConfig_Cfg = {
|
||||
.toolchainTweaks = {
|
||||
.treatJAsUnconditionalBranch = true,
|
||||
.sn64DivFix = false,
|
||||
.gnuMode = true,
|
||||
},
|
||||
.misc = {
|
||||
.opcodeLJust = 7+4,
|
||||
|
@ -537,7 +537,6 @@ const RabbitizerInstrDescriptor RabbitizerInstrDescriptor_Descriptors[] = {
|
||||
[RABBITIZER_INSTR_ID_r5900_msuba_s] = { .operands={RAB_OPERAND_cpu_fs, RAB_OPERAND_cpu_ft}, .isFloat=true, .readsFs=true, .readsFt=true },
|
||||
[RABBITIZER_INSTR_ID_r5900_max_s] = { .operands={RAB_OPERAND_cpu_fd, RAB_OPERAND_cpu_fs, RAB_OPERAND_cpu_ft}, .isFloat=true, .modifiesFd=true, .readsFs=true, .readsFt=true },
|
||||
[RABBITIZER_INSTR_ID_r5900_min_s] = { .operands={RAB_OPERAND_cpu_fd, RAB_OPERAND_cpu_fs, RAB_OPERAND_cpu_ft}, .isFloat=true, .modifiesFd=true, .readsFs=true, .readsFt=true },
|
||||
[RABBITIZER_INSTR_ID_r5900_trunc_w_s] = { .operands={RAB_OPERAND_cpu_fd, RAB_OPERAND_cpu_fs}, .isFloat=true, .modifiesFd=true, .readsFs=true },
|
||||
[RABBITIZER_INSTR_ID_r5900_c_lt_s] = { .operands={RAB_OPERAND_cpu_fs, RAB_OPERAND_cpu_ft}, .isFloat=true, .readsFs=true, .readsFt=true },
|
||||
[RABBITIZER_INSTR_ID_r5900_c_le_s] = { .operands={RAB_OPERAND_cpu_fs, RAB_OPERAND_cpu_ft}, .isFloat=true, .readsFs=true, .readsFt=true },
|
||||
[RABBITIZER_INSTR_ID_r5900_qmfc2] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_r5900_vfs}, .modifiesRt=true },
|
||||
|
1
src/instructions/InstrId_Names_array.table.h
generated
1
src/instructions/InstrId_Names_array.table.h
generated
@ -537,7 +537,6 @@ const char *RabbitizerInstrId_Names[] = {
|
||||
[RABBITIZER_INSTR_ID_r5900_msuba_s] = "msuba.s",
|
||||
[RABBITIZER_INSTR_ID_r5900_max_s] = "max.s",
|
||||
[RABBITIZER_INSTR_ID_r5900_min_s] = "min.s",
|
||||
[RABBITIZER_INSTR_ID_r5900_trunc_w_s] = "trunc.w.s",
|
||||
[RABBITIZER_INSTR_ID_r5900_c_lt_s] = "c.lt.s",
|
||||
[RABBITIZER_INSTR_ID_r5900_c_le_s] = "c.le.s",
|
||||
[RABBITIZER_INSTR_ID_r5900_qmfc2] = "qmfc2",
|
||||
|
@ -95,6 +95,38 @@ bool RabbitizerInstruction_mustDisasmAsData(const RabbitizerInstruction *self) {
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* Here's some reading about the binutils rationale:
|
||||
* - https://sourceware.org/legacy-ml/binutils/2012-11/msg00360.html
|
||||
* - https://sourceware.org/pipermail/binutils/2013-January/079863.html
|
||||
*
|
||||
* Because of this, building with GAS with the -march=r5900 flag produces:
|
||||
* - 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
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!RabbitizerInstruction_isValid(self)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -101,13 +101,15 @@ void RabbitizerInstruction_processUniqueId_Special(RabbitizerInstruction *self)
|
||||
|
||||
switch (self->uniqueId) {
|
||||
case RABBITIZER_INSTR_ID_cpu_div:
|
||||
if (RabbitizerConfig_Cfg.toolchainTweaks.sn64DivFix && !self->inHandwrittenFunction) {
|
||||
if ((!RabbitizerConfig_Cfg.toolchainTweaks.gnuMode) ||
|
||||
(RabbitizerConfig_Cfg.toolchainTweaks.sn64DivFix && !self->inHandwrittenFunction)) {
|
||||
self->descriptor = &RabbitizerInstrDescriptor_Descriptors[RABBITIZER_INSTR_ID_cpu_sn64_div];
|
||||
}
|
||||
break;
|
||||
|
||||
case RABBITIZER_INSTR_ID_cpu_divu:
|
||||
if (RabbitizerConfig_Cfg.toolchainTweaks.sn64DivFix && !self->inHandwrittenFunction) {
|
||||
if ((!RabbitizerConfig_Cfg.toolchainTweaks.gnuMode) ||
|
||||
(RabbitizerConfig_Cfg.toolchainTweaks.sn64DivFix && !self->inHandwrittenFunction)) {
|
||||
self->descriptor = &RabbitizerInstrDescriptor_Descriptors[RABBITIZER_INSTR_ID_cpu_sn64_divu];
|
||||
}
|
||||
break;
|
||||
|
@ -15,7 +15,7 @@ size_t RabbitizerOperandType_process_r5900_I(UNUSED const RabbitizerInstruction
|
||||
UNUSED const char *immOverride, UNUSED size_t immOverrideLength) {
|
||||
size_t totalSize = 0;
|
||||
|
||||
RABUTILS_BUFFER_CPY(dst, totalSize, "$I");
|
||||
RABUTILS_BUFFER_CPY(dst, totalSize, "I");
|
||||
|
||||
return totalSize;
|
||||
}
|
||||
@ -24,7 +24,7 @@ size_t RabbitizerOperandType_process_r5900_Q(UNUSED const RabbitizerInstruction
|
||||
UNUSED const char *immOverride, UNUSED size_t immOverrideLength) {
|
||||
size_t totalSize = 0;
|
||||
|
||||
RABUTILS_BUFFER_CPY(dst, totalSize, "$Q");
|
||||
RABUTILS_BUFFER_CPY(dst, totalSize, "Q");
|
||||
|
||||
return totalSize;
|
||||
}
|
||||
@ -33,7 +33,7 @@ size_t RabbitizerOperandType_process_r5900_R(UNUSED const RabbitizerInstruction
|
||||
UNUSED const char *immOverride, UNUSED size_t immOverrideLength) {
|
||||
size_t totalSize = 0;
|
||||
|
||||
RABUTILS_BUFFER_CPY(dst, totalSize, "$R");
|
||||
RABUTILS_BUFFER_CPY(dst, totalSize, "R");
|
||||
|
||||
return totalSize;
|
||||
}
|
||||
@ -42,7 +42,7 @@ size_t RabbitizerOperandType_process_r5900_ACC(UNUSED const RabbitizerInstructio
|
||||
UNUSED const char *immOverride, UNUSED size_t immOverrideLength) {
|
||||
size_t totalSize = 0;
|
||||
|
||||
RABUTILS_BUFFER_CPY(dst, totalSize, "$ACC");
|
||||
RABUTILS_BUFFER_CPY(dst, totalSize, "ACC");
|
||||
|
||||
return totalSize;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include "instructions/RabbitizerInstructionR5900.h"
|
||||
#include "common/RabbitizerConfig.h"
|
||||
|
||||
#define RABBITIZER_DEF_INSTR_ID(prefix, caseBits, name, ...) \
|
||||
case (caseBits): \
|
||||
|
15
tests/asm/r5900/trunc_w_c.s
Normal file
15
tests/asm/r5900/trunc_w_c.s
Normal file
@ -0,0 +1,15 @@
|
||||
.set noreorder
|
||||
|
||||
.section .text
|
||||
|
||||
.global test
|
||||
trunc.w.s $f0, $f12
|
||||
jr $31
|
||||
nop
|
||||
|
||||
.global test2
|
||||
cvt.w.s $f0, $f12
|
||||
jr $31
|
||||
nop
|
||||
|
||||
|
58
tests/c/instruction_checks/r5900_trunc_cvt.c
Normal file
58
tests/c/instruction_checks/r5900_trunc_cvt.c
Normal file
@ -0,0 +1,58 @@
|
||||
/* SPDX-FileCopyrightText: © 2023 Decompollaborate */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include "rabbitizer.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
typedef struct TestEntry {
|
||||
uint32_t word;
|
||||
bool gnuMode;
|
||||
const char *expectedStr;
|
||||
} TestEntry;
|
||||
|
||||
|
||||
const TestEntry entries[] = {
|
||||
{ 0x4600600D, true, ".word 0x4600600D # trunc.w.s $f0, $f12 # 00000000" },
|
||||
{ 0x46006024, true, ".word 0x46006024 # cvt.w.s $f0, $f12 # 00000000" },
|
||||
{ 0x4600600D, false, "trunc.w.s $f0, $f12" },
|
||||
{ 0x46006024, false, "cvt.w.s $f0, $f12" },
|
||||
};
|
||||
|
||||
int main() {
|
||||
int errorCount = 0;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ARRAY_COUNT(entries); i++) {
|
||||
const TestEntry *entry = &entries[i];
|
||||
RabbitizerConfig_Cfg.toolchainTweaks.gnuMode = entry->gnuMode;
|
||||
RabbitizerInstruction instr;
|
||||
char *buffer;
|
||||
size_t bufferSize;
|
||||
|
||||
RabbitizerInstructionR5900_init(&instr, entry->word, 0x80000000);
|
||||
RabbitizerInstructionR5900_processUniqueId(&instr);
|
||||
|
||||
bufferSize = RabbitizerInstruction_getSizeForBuffer(&instr, 0, 0);
|
||||
buffer = malloc(bufferSize + 1);
|
||||
assert(buffer != NULL);
|
||||
|
||||
RabbitizerInstruction_disassemble(&instr, buffer, NULL, 0, 0);
|
||||
|
||||
if (entry->expectedStr == NULL) {
|
||||
printf("Word '0x%08X' gnuMode '%s' doesn't have a expected str, got '%s'\n", entry->word, entry->gnuMode ? "true" : "false", buffer);
|
||||
errorCount++;
|
||||
} else if (strcmp(buffer, entry->expectedStr) != 0) {
|
||||
fprintf(stderr, "Error on word '0x%08X' gnuMode '%s'. Expected '%s', got '%s'\n", entry->word, entry->gnuMode ? "true" : "false", entry->expectedStr, buffer);
|
||||
errorCount++;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
RabbitizerInstructionR5900_destroy(&instr);
|
||||
}
|
||||
|
||||
return errorCount;
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
# SPDX-FileCopyrightText: © 2022 Decompollaborate
|
||||
# SPDX-FileCopyrightText: © 2022-2023 Decompollaborate
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
set -e
|
||||
|
||||
./build/tests/c/instruction_checks/jalr.elf
|
||||
./build/tests/c/instruction_checks/plain_disassembly.elf
|
||||
./build/tests/c/instruction_checks/r5900_trunc_cvt.elf
|
||||
|
Loading…
x
Reference in New Issue
Block a user