Merge pull request #23 from Decompollaborate/develop

1.5.9
This commit is contained in:
Anghelo Carvajal 2023-01-21 17:10:32 -03:00 committed by GitHub
commit f7ac917f80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 863 additions and 105 deletions

4
.markdownlint.json Normal file
View File

@ -0,0 +1,4 @@
{
"MD029": false,
"MD013": { "code_block_line_length": 120}
}

View File

@ -111,6 +111,7 @@ clean:
distclean: clean
$(RM) -rf dist *.egg-info .mypy_cache
$(RM) -rf $(TABLE_GENERATED)
$(RM) -rf target/
format:
clang-format-11 -i -style=file $(C_FILES)

View File

@ -7,9 +7,47 @@
![crate.io](https://img.shields.io/crates/dv/rabbitizer)
![GitHub contributors](https://img.shields.io/github/contributors/Decompollaborate/rabbitizer?logo=purple)
A MIPS instruction decoder API.
MIPS instruction decoder API.
Currently supports all the CPU instructions for MIPS I, II, III and IV.
## Features
- Should produce matching assembly.
- Fully written in C for fast decoding.
- The library is completely allocation-less, in other words `rabbitizer`
doesn't allocate in anything in the heap by itself.
- Other language bindings supported in this repo:
- Python bindings
- The minimal Python version is 3.7, older versions are not guaranteed to work.
- C++ bindings
- Rust bindings
- Simple per-word instruction decoding.
- The library doesn't try to be too smart by processing multiple instructions
at a time.
- Can perform validation checks for instructions.
- Provides many examination/grouping functions for instructions, allowing to
simplify checking characteristics of an instruction and minimizing the need to
check for specific instructions in a hardcoded way.
- Includes some minor tools to build your own pointer/symbol detection.
- Configurable, many features can be turned on and off.
- MIPS instructions features:
- Named registers for MIPS VR4300's coprocessors.
- Support for many pseudo-instructions.
- Properly handle move to/from coprocessor instructions.
- Support for numeric, o32, n32 and n64 ABI register names.
- Some workarounds for some specific compilers/assemblers:
- `SN64`:
- `div`/`divu` fix: tweaks a bit the produced `div`, `divu` and `break` instructions.
- Multiple MIPS architectures are supported:
- Main focus on MIPS I, II and III architectures. Partial support for MIPS IV too.
- N64 RSP instruction decoding support.
- RSP decoding has been tested to build back to matching assemblies with [armips](https://github.com/Kingcom/armips/).
- R5900 (PS2's Emotion Engine processor) decoding support.
## Non-features
In order to keep it simple and fast the following features will not be added:
- Pseudo-instructions which expands to more than one instruction.
## Installing
@ -21,13 +59,15 @@ The recommended way to install is using from the PyPi release, via `pip`:
pip install rabbitizer
```
In case you want to mess with the latest development version without wanting to clone the repository, then you could use the following command:
In case you want to mess with the latest development version without wanting to
clone the repository, then you could use the following command:
```bash
pip install git+https://github.com/Decompollaborate/rabbitizer.git@develop
```
NOTE: Installing the development version is not recommended. Proceed at your own risk.
NOTE: Installing the development version is not recommended. Proceed at your own
risk.
See this package at <https://pypi.org/project/rabbitizer/>.
@ -42,28 +82,6 @@ rabbitizer = "1.5.8"
See this crate at <https://crates.io/crates/rabbitizer>.
## Features
- Should produces matching assembly.
- Fully written in C for fast decoding.
- Python bindings.
- The minimal Python version is 3.7, older versions are not guaranteed to work.
- C++ bindings
- Rust bindings
- Includes some minor tools to build your own pointer/symbol detection.
- Configurable, many features can be turned on and off.
- MIPS instructions features:
- Named registers for MIPS VR4300's coprocessors.
- Support for many pseudoinstructions.
- Properly handle move to/from coprocessor instructions.
- Support for numeric, o32, n32 and n64 ABI register names.
- Some workarounds for some specific compilers/assemblers:
- `SN64`:
- `div`/`divu` fix: tweaks a bit the produced `div`, `divu` and `break` instructions.
- N64 RSP instruction decoding support.
- RSP decoding has been tested to build back to matching assemblies with [armips](https://github.com/Kingcom/armips/).
- R5900 (PS2's Emotion Engine processor) decoding support.
## References
- MIPS CPU:

View File

@ -249,8 +249,11 @@ namespace rabbitizer {
bool readsFt() const;
bool readsFd() const;
//! @deprecated
bool notEmitedByCompilers() const;
bool notEmittedByCompilers() const;
bool canBeHi() const;
bool canBeLo() const;
bool doesLink() const;

View File

@ -19,6 +19,7 @@ cpu_ft,
cpu_fd,
cpu_cop1cs,
cpu_cop2t,
cpu_cop2cd,
cpu_op,
cpu_code,
cpu_code_lower,

View File

@ -238,6 +238,10 @@ cpu_cvt_s_w,
cpu_cvt_d_w,
cpu_cvt_s_l,
cpu_cvt_d_l,
cpu_mfc2,
cpu_mtc2,
cpu_cfc2,
cpu_ctc2,
cpu_USERDEF_00,
cpu_USERDEF_01,
cpu_USERDEF_02,

View File

@ -909,7 +909,11 @@ bool InstructionBase::readsFd() const {
}
bool InstructionBase::notEmitedByCompilers() const {
return RabbitizerInstrDescriptor_notEmitedByCompilers(this->instr.descriptor);
return RabbitizerInstrDescriptor_notEmittedByCompilers(this->instr.descriptor);
}
bool InstructionBase::notEmittedByCompilers() const {
return RabbitizerInstrDescriptor_notEmittedByCompilers(this->instr.descriptor);
}
bool InstructionBase::canBeHi() const {

504
docs/usage_c_api.md Normal file
View File

@ -0,0 +1,504 @@
# Usage of the C API
- [Usage of the C API](#usage-of-the-c-api)
- [Simple example to disassemble a word](#simple-example-to-disassemble-a-word)
- [Overriding the immediate](#overriding-the-immediate)
- [Examinating an instruction](#examinating-an-instruction)
## Simple example to disassemble a word
```c
#include "rabbitizer.h"
#include <stdlib.h>
int main() {
RabbitizerInstruction instr;
uint32_t word = 0x8D4A7E18;
uint32_t vram = 0x80000000;
char *buffer;
size_t bufferSize;
RabbitizerInstruction_init(&instr, word, vram);
RabbitizerInstruction_processUniqueId(&instr);
bufferSize = RabbitizerInstruction_getSizeForBuffer(&instr, 0, 0);
buffer = malloc(bufferSize + 1);
RabbitizerInstruction_disassemble(&instr, buffer, NULL, 0, 0);
printf("%s\n", buffer);
free(buffer);
RabbitizerInstruction_destroy(&instr);
return 0;
}
```
Compiling and running the above C code prints the following:
```mips
lw $t2, 0x7E18($t2)
```
Please note many safe-guards were removed from this example for simplicity, like
checking if `malloc` returned a `NULL` pointer.
Let's break up the example and explain each part:
1. The stack
The `RabbitizerInstruction` type is the type `rabbitizer` uses to represent an
instruction. It is a simple struct which doesn't need dynamic memory
allocation of any kind, so it can be declared as an automatic variable and live
in the stack, without worrying about pointers and such.
The other stack variables should be self-explanatory. `word` is a 32-bit word
representing a raw MIPS instruction (spoiler, it is an `lw`). `rabbitizer`
needs to know the `vram` address of the instruction it is decoding, so we
initialize with a place-holder one. `buffer` and `bufferSize` will be used for
storing the disassembled string.
```c
int main() {
RabbitizerInstruction instr;
uint32_t word = 0x8D4A7E18;
uint32_t vram = 0x80000000;
char *buffer;
size_t bufferSize;
```
2. Initializing
To initialize our `instr` we need to call the pair `RabbitizerInstruction_init`
and `RabbitizerInstruction_processUniqueId`. `RabbitizerInstruction_init`
initialises all the members of the struct so it doesn't contain garbage data
anymore, while `RabbitizerInstruction_processUniqueId` does the heavy lifting of
identifying the actual instruction id out of the `word` we passed.
A `RabbitizerInstruction` variable is not considered fully initialized until it
has been passed to this pair of functions.
```c
RabbitizerInstruction_init(&instr, word, vram);
RabbitizerInstruction_processUniqueId(&instr);
```
3. Disassembling into a string
To disassemble the passed word as a string we can call
`RabbitizerInstruction_disassemble`. This function expects a `char` buffer to
fill, which should have enough space to hold the resulting string. To know how
big this buffer needs to be we should use the
`RabbitizerInstruction_getSizeForBuffer` function which calculates a size big
enough to hold the disassembled string for the passed instruction (without
taking into account the finalizing NUL character, similar to how `strlen`
behaves).
With this information we can just `malloc` our buffer and call
`RabbitizerInstruction_disassemble` to get our disassembled instruction.
(Ignore the extra `0` and `NULL` arguments for now, they will be discussed later)
```c
bufferSize = RabbitizerInstruction_getSizeForBuffer(&instr, 0, 0);
buffer = malloc(bufferSize + 1);
RabbitizerInstruction_disassemble(&instr, buffer, NULL, 0, 0);
```
4. Printing
Not much to say here, just print the disassembled instruction to `stdout`.
```c
printf("%s\n", buffer);
```
5. Clean-up
Finally since we know we won't be using the produced string or the instruction
we just `free` and `RabbitizerInstruction_destroy` them.
As a curiosity, `RabbitizerInstruction_destroy` currently does nothing, but
exists in case some destruction is needed in the future, so it recommended to
call this function as a future-proof method.
```c
free(buffer);
RabbitizerInstruction_destroy(&instr);
return 0;
}
```
## Overriding the immediate
When disassembling an instruction which has an immediate you'll probably don't
want raw immediate embedded in the disassembled string, but instead it reference
a symbol passed by the user.
For example, instead of having the raw immediate here
```mips
lw $t2, 0x7E18($t2)
bnez $t1, . + 4 + (-0x5 << 2)
```
You may want to reference symbols like this
```mips
lw $t2, %lo(some_symbol)($t2)
bnez $t1, some_branch_label
```
To do this you need to simply pass the string which will override the immediate
to the `immOverride` parameter of the `RabbitizerInstruction_disassemble`
function. For example:
```c
#include "rabbitizer.h"
#include <stdlib.h>
#include <string.h>
int main() {
RabbitizerInstruction instr;
uint32_t word = 0x8D4A7E18; // lw $t2, 0x7E18($t2)
uint32_t vram = 0x80000000;
char *buffer;
size_t bufferSize;
const char *immOverride = "%lo(some_symbol)";
size_t immOverrideLength;
immOverrideLength = strlen(immOverride);
RabbitizerInstruction_init(&instr, word, vram);
RabbitizerInstruction_processUniqueId(&instr);
bufferSize = RabbitizerInstruction_getSizeForBuffer(&instr, immOverrideLength, 0);
buffer = malloc(bufferSize + 1);
RabbitizerInstruction_disassemble(&instr, buffer, immOverride, immOverrideLength, 0);
printf("%s\n", buffer);
free(buffer);
RabbitizerInstruction_destroy(&instr);
return 0;
}
```
`RabbitizerInstruction_disassemble` will do the heavy lifting of using the
passed string as immediate so the user doesn't have to do string manipulations
to replace it.
In the case the user passed an `immOverride` to an instruction which does not
have an immediate then `rabbitizer` will simply ignore it.
Note both `RabbitizerInstruction_getSizeForBuffer` and
`RabbitizerInstruction_disassemble` require the length of the override string,
it can be easily computed with `strlen`.
Also note the passed `immOverride` includes the `%lo` reloc operand.
`rabbitizer` does not perform any kind of logic to add reloc operands, that kind
of logic is expected to be handled by the user, the library will use the
`immOverride` blindly.
Finally, `immOverride` and `immOverrideLength` must be both `NULL`/`0` or both
point to a valid NUL-terminated string and its size, using a combination of them
(as in non-`NULL` and `0` length or `NULL` and non-`zero` length) is UB.
For completeness sake, here's the code to produce the `bnez` from the above
example.
```c
#include "rabbitizer.h"
#include <stdlib.h>
#include <string.h>
int main() {
RabbitizerInstruction instr;
uint32_t word = 0x1520FFFB; // bnez $t1, . + 4 + (-0x5 << 2)
uint32_t vram = 0x80000000;
char *buffer;
size_t bufferSize;
const char *immOverride = "some_branch_label";
size_t immOverrideLength;
immOverrideLength = strlen(immOverride);
RabbitizerInstruction_init(&instr, word, vram);
RabbitizerInstruction_processUniqueId(&instr);
bufferSize = RabbitizerInstruction_getSizeForBuffer(&instr, immOverrideLength, 0);
buffer = malloc(bufferSize + 1);
RabbitizerInstruction_disassemble(&instr, buffer, immOverride, immOverrideLength, 0);
printf("%s\n", buffer);
free(buffer);
RabbitizerInstruction_destroy(&instr);
return 0;
}
```
## Examinating an instruction
As discussed before the library requires the user to already have included any
kind of extra stuff to the overriden immediate, does that mean the user will
need to hardcode conditionals for every MIPS instruction?
Nope, `rabbitizer` provides ways to examinate various characteristics of a given
instruction, which allow the user to request for this kind of information
without needing to worry to remember everything about every MIPS instruction
under the sun.
Let's write a program to actually check if the instruction has an immediate and
which kind of immediate it is.
First, to stop needing to change the word in the source code of the program
let's write a simple argument parser to get the word from the command line. It
goes straight to the point, it just expects the first argument to be a hex value
and there isn't any kind of validation.
```c
uint32_t getWordFromArgv(int argc, char *argv[]) {
uint32_t word;
if (argc < 2) {
fprintf(stderr, "Missing argument\n");
exit(1);
}
sscanf(argv[1], "%X", &word);
return word;
}
```
To simplify the main logic a bit, let's write a small function to print the
instruction to `stdout` too. This `printInstruction` basically does what we have
already discussed above so it should be pretty self-explanatory.
```c
void printInstruction(const RabbitizerInstruction *instr, const char *immOverride) {
char *buffer;
size_t bufferSize;
size_t immOverrideLength = 0;
if (immOverride != NULL) {
immOverrideLength = strlen(immOverride);
}
bufferSize = RabbitizerInstruction_getSizeForBuffer(instr, immOverrideLength, 0);
buffer = malloc(bufferSize + 1);
RabbitizerInstruction_disassemble(instr, buffer, immOverride, immOverrideLength, 0);
printf("%s\n", buffer);
free(buffer);
}
```
Something important we haven't discussed is validating the instruction before
examinating it. `rabbitizer` provides the `RabbitizerInstruction_isValid`
function to allow the user checking if the passed word corresponds to a valid
MIPS instruction, but it **expects the user to check for the validity of the
instruction**. This means if the user requests for any kind of examination on an
invalid instruction the library will return garbage.
The only case where `rabbitizer` actually will try to check if an instruction is
valid is when it produces a disassembly of said instruction with
`RabbitizerInstruction_disassemble`. If an invalid instruction is requested to
be disassembled then the library will produce a `.word` notation which should
correspond to the original passed word. We recommend the reader to check it out
by themselves.
```c
if (!RabbitizerInstruction_isValid(&instr)) {
printf("The word is not a valid instruction\n");
```
As we discussed before, passing an `immOverride` when disassembling an
instruction without an immediate is harmless, but the user may want to know if
the instruction actually has an immediate, to check that we can do it with
`RabbitizerInstruction_hasOperandAlias`. This function checks if the instruction
has the specific operand passed or any of the multiple aliases of said operand.
In this case we'll use it to print the instruction directly if it doesn't have
an immediate.
```c
} else if (!RabbitizerInstruction_hasOperandAlias(&instr, RAB_OPERAND_cpu_immediate)) {
printf("The word %08X corresponds to the instruction:\n", word);
printInstruction(&instr, NULL);
```
After having filtered the non-immediate instructions we can now focus on making
something for the ones that actually have an immediate. So it will look like
something like this:
```c
} else {
// For demostrative purposes we will use a big buffer on the stack and
// not perform sanity checks.
// Real world code should not do this and actually check nothing goes
// out of bounds
char immOverride[0x1000] = { 0 };
printf("The word %08X corresponds to the instruction (without immediate overriden):\n", word);
printInstruction(&instr, NULL);
printf("The word %08X corresponds to the instruction (with immediate overriden):\n", word);
// Fill the immOverride here
printInstruction(&instr, immOverride);
}
```
As we discussed before the user will want to prepare the `immOverride`
differently depending on the kind of instruction and how it interacts with said
immediate. For this we will consider 3 main instruction kinds, branch
instructions, %hi instructions and %lo instructions. For this we'll use the
instruction's descriptor.
The instruction's descriptor contains the metadata of an instruction. Stuff like
if the instruction is a branch, a jump, a float operation, which gpr/fpr
registers reads and modifies, which operands the instruction uses, etc, are
contained in the descriptor. To see the full list of stuff which is contained in
the descriptor see the [RabbitizerInstrDescriptor.h](../include/instructions/RabbitizerInstrDescriptor.h)
header.
Knowing this we can check for this 3 kinds of instruction easily with the
following code:
```c
if (RabbitizerInstrDescriptor_isBranch(instr.descriptor)) {
int32_t vramTarget = RabbitizerInstruction_getBranchVramGeneric(&instr);
sprintf(immOverride, ".L%08X", vramTarget);
} else if (RabbitizerInstrDescriptor_canBeHi(instr.descriptor)) {
int32_t processedImm = RabbitizerInstruction_getProcessedImmediate(&instr);
sprintf(immOverride, "%%hi(D_%08X)", processedImm << 16);
} else if (RabbitizerInstrDescriptor_canBeLo(instr.descriptor)) {
int32_t processedImm = RabbitizerInstruction_getProcessedImmediate(&instr);
sprintf(immOverride, "%%lo(D_%08X)", processedImm);
} else {
sprintf(immOverride, "other_sym");
}
```
`RabbitizerInstruction_getBranchVramGeneric` computes the vram address which
will be the destination of this branch instruction. It is relative to the `vram`
we passed to the instruction when we initialize it.
`RabbitizerInstruction_getProcessedImmediate` returns the immediate which this
instruction holds. In case this instruction uses the immediate as an unsigned
value then this function will return the immediate as-is, otherwise if the
instruction uses the immediate as a signed value then the function returns the
[two's complement](https://en.wikipedia.org/wiki/Two%27s_complement) of that
immediate.
Finally, here's the full program:
```c
#include "rabbitizer.h"
#include <stdlib.h>
#include <string.h>
uint32_t getWordFromArgv(int argc, char *argv[]) {
uint32_t word;
if (argc < 2) {
fprintf(stderr, "Missing argument\n");
exit(1);
}
sscanf(argv[1], "%X", &word);
return word;
}
void printInstruction(const RabbitizerInstruction *instr, const char *immOverride) {
char *buffer;
size_t bufferSize;
size_t immOverrideLength = 0;
if (immOverride != NULL) {
immOverrideLength = strlen(immOverride);
}
bufferSize = RabbitizerInstruction_getSizeForBuffer(instr, immOverrideLength, 0);
buffer = malloc(bufferSize + 1);
RabbitizerInstruction_disassemble(instr, buffer, immOverride, immOverrideLength, 0);
printf("%s\n", buffer);
free(buffer);
}
int main(int argc, char *argv[]) {
RabbitizerInstruction instr;
uint32_t word;
uint32_t vram = 0x80000000;
word = getWordFromArgv(argc, argv);
RabbitizerInstruction_init(&instr, word, vram);
RabbitizerInstruction_processUniqueId(&instr);
if (!RabbitizerInstruction_isValid(&instr)) {
printf("The word is not a valid instruction\n");
} else if (!RabbitizerInstruction_hasOperandAlias(&instr, RAB_OPERAND_cpu_immediate)) {
printf("The word %08X corresponds to the instruction:\n", word);
printInstruction(&instr, NULL);
} else {
// For demostrative purposes we will use a big buffer on the stack and
// not perform sanity checks.
// Real world code should not do this and actually check nothing goes
// out of bounds
char immOverride[0x1000] = { 0 };
printf("The word %08X corresponds to the instruction (without immediate overriden):\n", word);
printInstruction(&instr, NULL);
printf("The word %08X corresponds to the instruction (with immediate overriden):\n", word);
if (RabbitizerInstrDescriptor_isBranch(instr.descriptor)) {
int32_t vramTarget = RabbitizerInstruction_getBranchVramGeneric(&instr);
sprintf(immOverride, ".L%08X", vramTarget);
} else if (RabbitizerInstrDescriptor_canBeHi(instr.descriptor)) {
int32_t processedImm = RabbitizerInstruction_getProcessedImmediate(&instr);
sprintf(immOverride, "%%hi(D_%08X)", processedImm << 16);
} else if (RabbitizerInstrDescriptor_canBeLo(instr.descriptor)) {
int32_t processedImm = RabbitizerInstruction_getProcessedImmediate(&instr);
sprintf(immOverride, "%%lo(D_%08X)", processedImm);
} else {
sprintf(immOverride, "other_sym");
}
printInstruction(&instr, immOverride);
}
RabbitizerInstruction_destroy(&instr);
return 0;
}
```
Please note this example does not cover instructions with raw values embedded
into them which aren't immediates like `jal` or `j`. To check them the user can
use the `RabbitizerInstrDescriptor_isJumpWithAddress` function and retrieve the
target address as a vram address with
`RabbitizerInstruction_getInstrIndexAsVram`. Adding this functionality to the
above program is left as an exersice to the reader.

View File

@ -14,7 +14,7 @@ extern "C" {
// Header version
#define RAB_VERSION_MAJOR 1
#define RAB_VERSION_MINOR 5
#define RAB_VERSION_PATCH 8
#define RAB_VERSION_PATCH 9
#define RAB_VERSION_STR RAB_STRINGIFY(RAB_VERSION_MAJOR) "." RAB_STRINGIFY(RAB_VERSION_MINOR) "." RAB_STRINGIFY(RAB_VERSION_PATCH)

View File

@ -238,6 +238,10 @@ RABBITIZER_INSTR_ID_cpu_cvt_s_w,
RABBITIZER_INSTR_ID_cpu_cvt_d_w,
RABBITIZER_INSTR_ID_cpu_cvt_s_l,
RABBITIZER_INSTR_ID_cpu_cvt_d_l,
RABBITIZER_INSTR_ID_cpu_mfc2,
RABBITIZER_INSTR_ID_cpu_mtc2,
RABBITIZER_INSTR_ID_cpu_cfc2,
RABBITIZER_INSTR_ID_cpu_ctc2,
RABBITIZER_INSTR_ID_cpu_USERDEF_00,
RABBITIZER_INSTR_ID_cpu_USERDEF_01,
RABBITIZER_INSTR_ID_cpu_USERDEF_02,

View File

@ -19,6 +19,7 @@ RAB_OPERAND_cpu_ft,
RAB_OPERAND_cpu_fd,
RAB_OPERAND_cpu_cop1cs,
RAB_OPERAND_cpu_cop2t,
RAB_OPERAND_cpu_cop2cd,
RAB_OPERAND_cpu_op,
RAB_OPERAND_cpu_code,
RAB_OPERAND_cpu_code_lower,

View File

@ -17,6 +17,7 @@ size_t RabbitizerOperandType_process_cpu_ft (const struct RabbitizerInstruction
size_t RabbitizerOperandType_process_cpu_fd (const struct RabbitizerInstruction *self, char *dst, const char *immOverride, size_t immOverrideLength);
size_t RabbitizerOperandType_process_cpu_cop1cs (const struct RabbitizerInstruction *self, char *dst, const char *immOverride, size_t immOverrideLength);
size_t RabbitizerOperandType_process_cpu_cop2t (const struct RabbitizerInstruction *self, char *dst, const char *immOverride, size_t immOverrideLength);
size_t RabbitizerOperandType_process_cpu_cop2cd (const struct RabbitizerInstruction *self, char *dst, const char *immOverride, size_t immOverrideLength);
size_t RabbitizerOperandType_process_cpu_op (const struct RabbitizerInstruction *self, char *dst, const char *immOverride, size_t immOverrideLength);
size_t RabbitizerOperandType_process_cpu_code (const struct RabbitizerInstruction *self, char *dst, const char *immOverride, size_t immOverrideLength);
size_t RabbitizerOperandType_process_cpu_code_lower (const struct RabbitizerInstruction *self, char *dst, const char *immOverride, size_t immOverrideLength);

View File

@ -110,7 +110,7 @@ typedef struct RabbitizerInstrDescriptor {
/**
* This instruction is not emited by a C compiler
*/
bool notEmitedByCompilers;
bool notEmittedByCompilers;
/**
* The instruction can hold the "hi" value of a %hi/%lo pair
@ -232,7 +232,10 @@ NODISCARD NON_NULL(1) PURE
bool RabbitizerInstrDescriptor_readsFd(const RabbitizerInstrDescriptor *self);
NODISCARD NON_NULL(1) PURE
bool RabbitizerInstrDescriptor_notEmitedByCompilers(const RabbitizerInstrDescriptor *self);
bool RabbitizerInstrDescriptor_notEmittedByCompilers(const RabbitizerInstrDescriptor *self);
//! @deprecated
#define RabbitizerInstrDescriptor_notEmitedByCompilers RabbitizerInstrDescriptor_notEmittedByCompilers
NODISCARD NON_NULL(1) PURE
bool RabbitizerInstrDescriptor_canBeHi(const RabbitizerInstrDescriptor *self);

View File

@ -64,6 +64,7 @@ typedef struct RabbitizerInstruction {
#define RAB_INSTR_GET_cond(self) (SHIFTR((self)->word, 0, 4))
#define RAB_INSTR_GET_cop2t(self) (SHIFTR((self)->word, 16, 5))
#define RAB_INSTR_GET_cop2cd(self) (SHIFTR((self)->word, 11, 5))
#define RAB_INSTR_GET_tf(self) (SHIFTR((self)->word, 16, 1))
#define RAB_INSTR_GET_nd(self) (SHIFTR((self)->word, 17, 1))
@ -102,6 +103,7 @@ typedef struct RabbitizerInstruction {
#define RAB_INSTR_PACK_op(word, value) (BITREPACK((word), (value), 16, 5))
#define RAB_INSTR_PACK_cop2t(word, value) (BITREPACK((word), (value), 16, 5))
#define RAB_INSTR_PACK_cop2cd(word, value) (BITREPACK((word), value, 11, 5))
#define RAB_INSTR_PACK_tf(word, value) (BITREPACK((word), (value), 16, 1))
#define RAB_INSTR_PACK_nd(word, value) (BITREPACK((word), (value), 17, 1))

View File

@ -18,6 +18,7 @@ RABBITIZER_DEF_INSTR_ID(
#include "cpu/cpu_cop1_fpu_d.inc"
#include "cpu/cpu_cop1_fpu_w.inc"
#include "cpu/cpu_cop1_fpu_l.inc"
#include "cpu/cpu_cop2.inc"
RABBITIZER_DEF_INSTR_ID(
cpu, , USERDEF_00,

View File

@ -7,36 +7,40 @@ RABBITIZER_DEF_INSTR_ID(
.operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d},
.instrType=RABBITIZER_INSTR_TYPE_UNKNOWN,
.modifiesRt=true,
.notEmitedByCompilers=true
.notEmittedByCompilers=true
) // Move word From CP0
RABBITIZER_DEF_INSTR_ID(
cpu, 0x01, dmfc0,
.operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d},
.instrType=RABBITIZER_INSTR_TYPE_UNKNOWN,
.modifiesRt=true
.modifiesRt=true,
.notEmittedByCompilers=true
) // Doubleword Move From CP0
RABBITIZER_DEF_INSTR_ID(
cpu, 0x02, cfc0,
.operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d},
.instrType=RABBITIZER_INSTR_TYPE_UNKNOWN,
.modifiesRt=true
.modifiesRt=true,
.notEmittedByCompilers=true
) // Move control word From CP0
RABBITIZER_DEF_INSTR_ID(
cpu, 0x04, mtc0,
.operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d},
.instrType=RABBITIZER_INSTR_TYPE_UNKNOWN,
.readsRt=true,
.notEmitedByCompilers=true
.notEmittedByCompilers=true
) // Move word to CP0
RABBITIZER_DEF_INSTR_ID(
cpu, 0x05, dmtc0,
.operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d},
.instrType=RABBITIZER_INSTR_TYPE_UNKNOWN,
.readsRt=true
.readsRt=true,
.notEmittedByCompilers=true
) // Doubleword Move To CP0
RABBITIZER_DEF_INSTR_ID(
cpu, 0x06, ctc0,
.operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d},
.instrType=RABBITIZER_INSTR_TYPE_UNKNOWN,
.readsRt=true
.readsRt=true,
.notEmittedByCompilers=true
) // Move control word To CP0

View File

@ -6,13 +6,13 @@ RABBITIZER_DEF_INSTR_ID(
cpu, 0x01, tlbr,
.operands={0},
.instrType=RABBITIZER_INSTR_TYPE_UNKNOWN,
.notEmitedByCompilers=true
.notEmittedByCompilers=true
) // Read Indexed TLB Entry
RABBITIZER_DEF_INSTR_ID(
cpu, 0x02, tlbwi,
.operands={0},
.instrType=RABBITIZER_INSTR_TYPE_UNKNOWN,
.notEmitedByCompilers=true
.notEmittedByCompilers=true
) // Write Indexed TLB Entry
RABBITIZER_DEF_INSTR_ID(
@ -25,12 +25,12 @@ RABBITIZER_DEF_INSTR_ID(
cpu, 0x08, tlbp,
.operands={0},
.instrType=RABBITIZER_INSTR_TYPE_UNKNOWN,
.notEmitedByCompilers=true
.notEmittedByCompilers=true
) // Probe TLB for Matching Entry
RABBITIZER_DEF_INSTR_ID(
cpu, 0x18, eret,
.operands={0},
.instrType=RABBITIZER_INSTR_TYPE_UNKNOWN,
.notEmitedByCompilers=true
.notEmittedByCompilers=true
) // Return from Exception

View File

@ -0,0 +1,26 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
// OP rt, cop2cd
RABBITIZER_DEF_INSTR_ID(
cpu, 0x00, mfc2,
.operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop2cd},
.modifiesRt=true
)
RABBITIZER_DEF_INSTR_ID(
cpu, 0x04, mtc2,
.operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop2cd},
.readsRt=true
)
// OP rt, cop2cd
RABBITIZER_DEF_INSTR_ID(
cpu, 0x02, cfc2,
.operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop2cd},
.modifiesRt=true
)
RABBITIZER_DEF_INSTR_ID(
cpu, 0x06, ctc2,
.operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop2cd},
.readsRt=true
)

View File

@ -93,7 +93,7 @@ RABBITIZER_DEF_INSTR_ID(
.instrType=RABBITIZER_INSTR_TYPE_I,
.modifiesRt=true,
.readsRs=true,
.notEmitedByCompilers=true,
.notEmittedByCompilers=true,
.canBeLo=true
) // Add Immediate
RABBITIZER_DEF_INSTR_ID(
@ -359,6 +359,7 @@ RABBITIZER_DEF_INSTR_ID(
.instrType=RABBITIZER_INSTR_TYPE_I,
.modifiesRt=true,
.readsRs=true,
.notEmittedByCompilers=true,
.canBeLo=true,
.doesDereference=true,
.doesLoad=true
@ -376,6 +377,7 @@ RABBITIZER_DEF_INSTR_ID(
.instrType=RABBITIZER_INSTR_TYPE_I,
.modifiesRt=true,
.readsRs=true,
.notEmittedByCompilers=true,
.canBeLo=true,
.doesDereference=true,
.doesLoad=true
@ -397,6 +399,7 @@ RABBITIZER_DEF_INSTR_ID(
.instrType=RABBITIZER_INSTR_TYPE_I,
.readsRs=true,
.readsRt=true,
.notEmittedByCompilers=true,
.canBeLo=true,
.doesDereference=true,
.doesStore=true
@ -407,6 +410,7 @@ RABBITIZER_DEF_INSTR_ID(
.instrType=RABBITIZER_INSTR_TYPE_I,
.readsRs=true,
.readsRt=true,
.notEmittedByCompilers=true,
.canBeLo=true,
.doesDereference=true,
.doesStore=true
@ -429,7 +433,7 @@ RABBITIZER_DEF_INSTR_ID(
.operands={RAB_OPERAND_cpu_op, RAB_OPERAND_cpu_immediate_base},
.instrType=RABBITIZER_INSTR_TYPE_I,
.readsRs=true,
.notEmitedByCompilers=true
.notEmittedByCompilers=true
) // Cache
// OP ft, IMM(base)

View File

@ -38,42 +38,48 @@ RABBITIZER_DEF_INSTR_ID(
.operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate},
.instrType=RABBITIZER_INSTR_TYPE_REGIMM,
.isTrap=true,
.readsRs=true
.readsRs=true,
.notEmittedByCompilers=true
)
RABBITIZER_DEF_INSTR_ID(
cpu, 0x09, tgeiu,
.operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate},
.instrType=RABBITIZER_INSTR_TYPE_REGIMM,
.isTrap=true,
.readsRs=true
.readsRs=true,
.notEmittedByCompilers=true
)
RABBITIZER_DEF_INSTR_ID(
cpu, 0x0A, tlti,
.operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate},
.instrType=RABBITIZER_INSTR_TYPE_REGIMM,
.isTrap=true,
.readsRs=true
.readsRs=true,
.notEmittedByCompilers=true
)
RABBITIZER_DEF_INSTR_ID(
cpu, 0x0B, tltiu,
.operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate},
.instrType=RABBITIZER_INSTR_TYPE_REGIMM,
.isTrap=true,
.readsRs=true
.readsRs=true,
.notEmittedByCompilers=true
)
RABBITIZER_DEF_INSTR_ID(
cpu, 0x0C, teqi,
.operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate},
.instrType=RABBITIZER_INSTR_TYPE_REGIMM,
.isTrap=true,
.readsRs=true
.readsRs=true,
.notEmittedByCompilers=true
)
RABBITIZER_DEF_INSTR_ID(
cpu, 0x0E, tnei,
.operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate},
.instrType=RABBITIZER_INSTR_TYPE_REGIMM,
.isTrap=true,
.readsRs=true
.readsRs=true,
.notEmittedByCompilers=true
)
RABBITIZER_DEF_INSTR_ID(
@ -108,6 +114,7 @@ RABBITIZER_DEF_INSTR_ID(
.isBranch=true,
.isBranchLikely=true,
.readsRs=true,
.notEmittedByCompilers=true,
.doesLink=true
) // Branch on Greater Than or Equal to Zero and Link Likely
@ -119,6 +126,7 @@ RABBITIZER_DEF_INSTR_ID(
.operands={RAB_OPERAND_cpu_branch_target_label},
.instrType=RABBITIZER_INSTR_TYPE_REGIMM,
.isBranch=true,
.notEmittedByCompilers=true,
.doesLink=true,
.isPseudo=true
) // Branch and Link

View File

@ -272,7 +272,7 @@ RABBITIZER_DEF_INSTR_ID(
.modifiesRd=true,
.readsRs=true,
.readsRt=true,
.notEmitedByCompilers=true
.notEmittedByCompilers=true
) // ADD word
RABBITIZER_DEF_INSTR_ID(
cpu, 0x21, addu,
@ -288,6 +288,7 @@ RABBITIZER_DEF_INSTR_ID(
.operands={RAB_OPERAND_cpu_rd, RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt},
.instrType=RABBITIZER_INSTR_TYPE_R,
.modifiesRd=true,
.notEmittedByCompilers=true,
.readsRs=true,
.readsRt=true
) // Subtract word
@ -443,7 +444,8 @@ RABBITIZER_DEF_INSTR_ID(
.instrType=RABBITIZER_INSTR_TYPE_R,
.readsRs=true,
.readsRt=true,
.isTrap=true
.isTrap=true,
.notEmittedByCompilers=true
) // Trap if Greater or Equal
RABBITIZER_DEF_INSTR_ID(
cpu, 0x31, tgeu,
@ -451,7 +453,8 @@ RABBITIZER_DEF_INSTR_ID(
.instrType=RABBITIZER_INSTR_TYPE_R,
.readsRs=true,
.readsRt=true,
.isTrap=true
.isTrap=true,
.notEmittedByCompilers=true
) // Trap if Greater or Equal Unsigned
RABBITIZER_DEF_INSTR_ID(
cpu, 0x32, tlt,
@ -459,7 +462,8 @@ RABBITIZER_DEF_INSTR_ID(
.instrType=RABBITIZER_INSTR_TYPE_R,
.readsRs=true,
.readsRt=true,
.isTrap=true
.isTrap=true,
.notEmittedByCompilers=true
) // Trap if Less Than
RABBITIZER_DEF_INSTR_ID(
cpu, 0x33, tltu,
@ -467,7 +471,8 @@ RABBITIZER_DEF_INSTR_ID(
.instrType=RABBITIZER_INSTR_TYPE_R,
.readsRs=true,
.readsRt=true,
.isTrap=true
.isTrap=true,
.notEmittedByCompilers=true
) // Trap if Less Than Unsigned
RABBITIZER_DEF_INSTR_ID(
cpu, 0x34, teq,
@ -475,7 +480,8 @@ RABBITIZER_DEF_INSTR_ID(
.instrType=RABBITIZER_INSTR_TYPE_R,
.readsRs=true,
.readsRt=true,
.isTrap=true
.isTrap=true,
.notEmittedByCompilers=true
) // Trap if EQual
RABBITIZER_DEF_INSTR_ID(
cpu, 0x36, tne,
@ -483,7 +489,8 @@ RABBITIZER_DEF_INSTR_ID(
.instrType=RABBITIZER_INSTR_TYPE_R,
.readsRs=true,
.readsRt=true,
.isTrap=true
.isTrap=true,
.notEmittedByCompilers=true
) // Trap if Not Equal

View File

@ -7,12 +7,12 @@ RABBITIZER_DEF_INSTR_ID(
.operands={RAB_OPERAND_rsp_rt, RAB_OPERAND_rsp_cop0d},
.instrType=RABBITIZER_INSTR_TYPE_UNKNOWN,
.modifiesRt=true,
.notEmitedByCompilers=true
.notEmittedByCompilers=true
) // Move word From CP0
RABBITIZER_DEF_INSTR_ID(
rsp, 0x04, mtc0,
.operands={RAB_OPERAND_rsp_rt, RAB_OPERAND_rsp_cop0d},
.instrType=RABBITIZER_INSTR_TYPE_UNKNOWN,
.readsRt=true,
.notEmitedByCompilers=true
.notEmittedByCompilers=true
) // Move word to CP0

View File

@ -59,7 +59,7 @@ RABBITIZER_DEF_INSTR_ID(
.instrType=RABBITIZER_INSTR_TYPE_I,
.modifiesRt=true,
.readsRs=true,
.notEmitedByCompilers=true,
.notEmittedByCompilers=true,
.canBeLo=true
) // Add Immediate
RABBITIZER_DEF_INSTR_ID(

View File

@ -31,6 +31,7 @@ RABBITIZER_DEF_INSTR_ID(
.instrType=RABBITIZER_INSTR_TYPE_REGIMM,
.readsRs=true,
.isBranch=true,
.notEmittedByCompilers=true,
.doesLink=true
) // Branch on Greater Than or Equal to Zero and Link
@ -42,6 +43,7 @@ RABBITIZER_DEF_INSTR_ID(
.operands={RAB_OPERAND_cpu_branch_target_label},
.instrType=RABBITIZER_INSTR_TYPE_REGIMM,
.isBranch=true,
.notEmittedByCompilers=true,
.doesLink=true,
.isPseudo=true
) // Branch and Link

View File

@ -93,7 +93,7 @@ RABBITIZER_DEF_INSTR_ID(
.modifiesRd=true,
.readsRs=true,
.readsRt=true,
.notEmitedByCompilers=true
.notEmittedByCompilers=true
) // ADD word
RABBITIZER_DEF_INSTR_ID(
rsp, 0x21, addu,
@ -108,6 +108,7 @@ RABBITIZER_DEF_INSTR_ID(
.operands={RAB_OPERAND_rsp_rd, RAB_OPERAND_rsp_rs, RAB_OPERAND_rsp_rt},
.instrType=RABBITIZER_INSTR_TYPE_R,
.modifiesRd=true,
.notEmittedByCompilers=true,
.readsRs=true,
.readsRt=true
) // Subtract word

View File

@ -13,6 +13,7 @@ RAB_DEF_OPERAND(cpu, ft)
RAB_DEF_OPERAND(cpu, fd)
RAB_DEF_OPERAND(cpu, cop1cs) // Coprocessor 1 control fs
RAB_DEF_OPERAND(cpu, cop2t)
RAB_DEF_OPERAND(cpu, cop2cd) // Coprocessor 2 control rd
RAB_DEF_OPERAND(cpu, op)
RAB_DEF_OPERAND(cpu, code)
RAB_DEF_OPERAND(cpu, code_lower)

View File

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

View File

@ -228,6 +228,10 @@ class InstrId:
cpu_cvt_d_s: Enum
cpu_cvt_d_w: Enum
cpu_cvt_d_l: Enum
cpu_mfc2: Enum
cpu_mtc2: Enum
cpu_cfc2: Enum
cpu_ctc2: Enum
cpu_cvt_w_s: Enum
cpu_cvt_w_d: Enum
cpu_cvt_l_s: Enum

View File

@ -114,7 +114,8 @@ class Instruction:
def readsFs(self) -> bool: ...
def readsFt(self) -> bool: ...
def readsFd(self) -> bool: ...
def notEmitedByCompilers(self) -> bool: ...
def notEmitedByCompilers(self) -> bool: ... #! deprecated
def notEmittedByCompilers(self) -> bool: ...
def canBeHi(self) -> bool: ...
def canBeLo(self) -> bool: ...
def doesLink(self) -> bool: ...

View File

@ -374,6 +374,7 @@ DEF_DESCRIPTOR_METHOD_BOOL(readsFs)
DEF_DESCRIPTOR_METHOD_BOOL(readsFt)
DEF_DESCRIPTOR_METHOD_BOOL(readsFd)
DEF_DESCRIPTOR_METHOD_BOOL(notEmitedByCompilers)
DEF_DESCRIPTOR_METHOD_BOOL(notEmittedByCompilers)
DEF_DESCRIPTOR_METHOD_BOOL(canBeHi)
DEF_DESCRIPTOR_METHOD_BOOL(canBeLo)
DEF_DESCRIPTOR_METHOD_BOOL(doesLink)
@ -517,6 +518,7 @@ static PyMethodDef rabbitizer_type_Instruction_methods[] = {
METHOD_NO_ARGS(readsFt, ""),
METHOD_NO_ARGS(readsFd, ""),
METHOD_NO_ARGS(notEmitedByCompilers, ""),
METHOD_NO_ARGS(notEmittedByCompilers, ""),
METHOD_NO_ARGS(canBeHi, ""),
METHOD_NO_ARGS(canBeLo, ""),
METHOD_NO_ARGS(doesLink, ""),

View File

@ -238,6 +238,10 @@ cpu_cvt_s_w,
cpu_cvt_d_w,
cpu_cvt_s_l,
cpu_cvt_d_l,
cpu_mfc2,
cpu_mtc2,
cpu_cfc2,
cpu_ctc2,
cpu_USERDEF_00,
cpu_USERDEF_01,
cpu_USERDEF_02,

View File

@ -134,7 +134,7 @@ extern "C" {
fn RabbitizerInstrDescriptor_readsFt(self_: *const instr_descriptor::InstrDescriptor) -> bool;
fn RabbitizerInstrDescriptor_readsFd(self_: *const instr_descriptor::InstrDescriptor) -> bool;
fn RabbitizerInstrDescriptor_notEmitedByCompilers(
fn RabbitizerInstrDescriptor_notEmittedByCompilers(
self_: *const instr_descriptor::InstrDescriptor,
) -> bool;
fn RabbitizerInstrDescriptor_canBeHi(self_: *const instr_descriptor::InstrDescriptor) -> bool;
@ -673,9 +673,16 @@ impl Instruction {
RabbitizerInstrDescriptor_readsFd(self.descriptor)
}
}
// @deprecated
pub fn not_emited_by_compilers(&self) -> bool {
unsafe {
RabbitizerInstrDescriptor_notEmitedByCompilers(self.descriptor)
RabbitizerInstrDescriptor_notEmittedByCompilers(self.descriptor)
}
}
pub fn not_emitted_by_compilers(&self) -> bool {
unsafe {
RabbitizerInstrDescriptor_notEmittedByCompilers(self.descriptor)
}
}
pub fn can_be_hi(&self) -> bool {

View File

@ -19,6 +19,7 @@ cpu_ft,
cpu_fd,
cpu_cop1cs,
cpu_cop2t,
cpu_cop2cd,
cpu_op,
cpu_code,
cpu_code_lower,

View File

@ -18,7 +18,7 @@ const RabbitizerInstrDescriptor RabbitizerInstrDescriptor_Descriptors[] = {
[RABBITIZER_INSTR_ID_cpu_blezl] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_I, .isBranch=true, .isBranchLikely=true, .readsRs=true },
[RABBITIZER_INSTR_ID_cpu_bgtz] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_I, .isBranch=true, .readsRs=true },
[RABBITIZER_INSTR_ID_cpu_bgtzl] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_I, .isBranch=true, .isBranchLikely=true, .readsRs=true },
[RABBITIZER_INSTR_ID_cpu_addi] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_I, .modifiesRt=true, .readsRs=true, .notEmitedByCompilers=true, .canBeLo=true },
[RABBITIZER_INSTR_ID_cpu_addi] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_I, .modifiesRt=true, .readsRs=true, .notEmittedByCompilers=true, .canBeLo=true },
[RABBITIZER_INSTR_ID_cpu_addiu] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_I, .modifiesRt=true, .readsRs=true, .canBeLo=true },
[RABBITIZER_INSTR_ID_cpu_slti] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_I, .modifiesRt=true, .readsRs=true },
[RABBITIZER_INSTR_ID_cpu_sltiu] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_I, .modifiesRt=true, .readsRs=true },
@ -45,14 +45,14 @@ const RabbitizerInstrDescriptor RabbitizerInstrDescriptor_Descriptors[] = {
[RABBITIZER_INSTR_ID_cpu_sdl] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .readsRs=true, .readsRt=true, .canBeLo=true, .doesDereference=true, .doesStore=true },
[RABBITIZER_INSTR_ID_cpu_sdr] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .readsRs=true, .readsRt=true, .canBeLo=true, .doesDereference=true, .doesStore=true },
[RABBITIZER_INSTR_ID_cpu_swr] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .readsRs=true, .readsRt=true, .canBeLo=true, .doesDereference=true, .doesStore=true },
[RABBITIZER_INSTR_ID_cpu_ll] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .modifiesRt=true, .readsRs=true, .canBeLo=true, .doesDereference=true, .doesLoad=true },
[RABBITIZER_INSTR_ID_cpu_ll] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .modifiesRt=true, .readsRs=true, .notEmittedByCompilers=true, .canBeLo=true, .doesDereference=true, .doesLoad=true },
[RABBITIZER_INSTR_ID_cpu_pref] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .readsRs=true, .readsRt=true },
[RABBITIZER_INSTR_ID_cpu_lld] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .modifiesRt=true, .readsRs=true, .canBeLo=true, .doesDereference=true, .doesLoad=true },
[RABBITIZER_INSTR_ID_cpu_lld] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .modifiesRt=true, .readsRs=true, .notEmittedByCompilers=true, .canBeLo=true, .doesDereference=true, .doesLoad=true },
[RABBITIZER_INSTR_ID_cpu_ld] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .modifiesRt=true, .readsRs=true, .canBeLo=true, .doesDereference=true, .doesLoad=true, .accessType=RAB_ACCESSTYPE_DOUBLEWORD },
[RABBITIZER_INSTR_ID_cpu_sc] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .readsRs=true, .readsRt=true, .canBeLo=true, .doesDereference=true, .doesStore=true },
[RABBITIZER_INSTR_ID_cpu_scd] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .readsRs=true, .readsRt=true, .canBeLo=true, .doesDereference=true, .doesStore=true },
[RABBITIZER_INSTR_ID_cpu_sc] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .readsRs=true, .readsRt=true, .notEmittedByCompilers=true, .canBeLo=true, .doesDereference=true, .doesStore=true },
[RABBITIZER_INSTR_ID_cpu_scd] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .readsRs=true, .readsRt=true, .notEmittedByCompilers=true, .canBeLo=true, .doesDereference=true, .doesStore=true },
[RABBITIZER_INSTR_ID_cpu_sd] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .readsRs=true, .readsRt=true, .canBeLo=true, .doesDereference=true, .doesStore=true, .accessType=RAB_ACCESSTYPE_DOUBLEWORD },
[RABBITIZER_INSTR_ID_cpu_cache] = { .operands={RAB_OPERAND_cpu_op, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .readsRs=true, .notEmitedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_cache] = { .operands={RAB_OPERAND_cpu_op, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .readsRs=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_lwc1] = { .operands={RAB_OPERAND_cpu_ft, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .isFloat=true, .readsRs=true, .modifiesFt=true, .canBeLo=true, .doesDereference=true, .doesLoad=true, .accessType=RAB_ACCESSTYPE_FLOAT },
[RABBITIZER_INSTR_ID_cpu_ldc1] = { .operands={RAB_OPERAND_cpu_ft, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .isFloat=true, .isDouble=true, .readsRs=true, .modifiesFt=true, .canBeLo=true, .doesDereference=true, .doesLoad=true, .accessType=RAB_ACCESSTYPE_DOUBLEFLOAT },
[RABBITIZER_INSTR_ID_cpu_swc1] = { .operands={RAB_OPERAND_cpu_ft, RAB_OPERAND_cpu_immediate_base}, .instrType=RABBITIZER_INSTR_TYPE_I, .isFloat=true, .readsRs=true, .readsFt=true, .canBeLo=true, .doesDereference=true, .doesStore=true, .accessType=RAB_ACCESSTYPE_FLOAT },
@ -93,9 +93,9 @@ const RabbitizerInstrDescriptor RabbitizerInstrDescriptor_Descriptors[] = {
[RABBITIZER_INSTR_ID_cpu_sn64_divu] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .modifiesHI=true, .modifiesLO=true },
[RABBITIZER_INSTR_ID_cpu_ddiv] = { .operands={RAB_OPERAND_cpu_rd, RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .readsRd=true, .modifiesHI=true, .modifiesLO=true },
[RABBITIZER_INSTR_ID_cpu_ddivu] = { .operands={RAB_OPERAND_cpu_rd, RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .readsRd=true, .modifiesHI=true, .modifiesLO=true },
[RABBITIZER_INSTR_ID_cpu_add] = { .operands={RAB_OPERAND_cpu_rd, RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .readsRt=true, .notEmitedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_add] = { .operands={RAB_OPERAND_cpu_rd, RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .readsRt=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_addu] = { .operands={RAB_OPERAND_cpu_rd, RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .readsRt=true, .maybeIsMove=true },
[RABBITIZER_INSTR_ID_cpu_sub] = { .operands={RAB_OPERAND_cpu_rd, RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .readsRt=true },
[RABBITIZER_INSTR_ID_cpu_sub] = { .operands={RAB_OPERAND_cpu_rd, RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .notEmittedByCompilers=true, .readsRs=true, .readsRt=true },
[RABBITIZER_INSTR_ID_cpu_subu] = { .operands={RAB_OPERAND_cpu_rd, RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .readsRt=true },
[RABBITIZER_INSTR_ID_cpu_and] = { .operands={RAB_OPERAND_cpu_rd, RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .readsRt=true },
[RABBITIZER_INSTR_ID_cpu_or] = { .operands={RAB_OPERAND_cpu_rd, RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .maybeIsMove=true, .readsRs=true, .readsRt=true },
@ -114,12 +114,12 @@ const RabbitizerInstrDescriptor RabbitizerInstrDescriptor_Descriptors[] = {
[RABBITIZER_INSTR_ID_cpu_multu] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .modifiesHI=true, .modifiesLO=true },
[RABBITIZER_INSTR_ID_cpu_dmult] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .modifiesHI=true, .modifiesLO=true },
[RABBITIZER_INSTR_ID_cpu_dmultu] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .modifiesHI=true, .modifiesLO=true },
[RABBITIZER_INSTR_ID_cpu_tge] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_code_lower}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .isTrap=true },
[RABBITIZER_INSTR_ID_cpu_tgeu] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_code_lower}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .isTrap=true },
[RABBITIZER_INSTR_ID_cpu_tlt] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_code_lower}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .isTrap=true },
[RABBITIZER_INSTR_ID_cpu_tltu] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_code_lower}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .isTrap=true },
[RABBITIZER_INSTR_ID_cpu_teq] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_code_lower}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .isTrap=true },
[RABBITIZER_INSTR_ID_cpu_tne] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_code_lower}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .isTrap=true },
[RABBITIZER_INSTR_ID_cpu_tge] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_code_lower}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .isTrap=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_tgeu] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_code_lower}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .isTrap=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_tlt] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_code_lower}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .isTrap=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_tltu] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_code_lower}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .isTrap=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_teq] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_code_lower}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .isTrap=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_tne] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_code_lower}, .instrType=RABBITIZER_INSTR_TYPE_R, .readsRs=true, .readsRt=true, .isTrap=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_nop] = { .operands={0}, .instrType=RABBITIZER_INSTR_TYPE_R, .isPseudo=true },
[RABBITIZER_INSTR_ID_cpu_move] = { .operands={RAB_OPERAND_cpu_rd, RAB_OPERAND_cpu_rs}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .maybeIsMove=true, .isPseudo=true },
[RABBITIZER_INSTR_ID_cpu_not] = { .operands={RAB_OPERAND_cpu_rd, RAB_OPERAND_cpu_rs}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .isPseudo=true },
@ -128,32 +128,32 @@ const RabbitizerInstrDescriptor RabbitizerInstrDescriptor_Descriptors[] = {
[RABBITIZER_INSTR_ID_cpu_bgez] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isBranch=true, .readsRs=true },
[RABBITIZER_INSTR_ID_cpu_bltzl] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isBranch=true, .isBranchLikely=true, .readsRs=true },
[RABBITIZER_INSTR_ID_cpu_bgezl] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isBranch=true, .isBranchLikely=true, .readsRs=true },
[RABBITIZER_INSTR_ID_cpu_tgei] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isTrap=true, .readsRs=true },
[RABBITIZER_INSTR_ID_cpu_tgeiu] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isTrap=true, .readsRs=true },
[RABBITIZER_INSTR_ID_cpu_tlti] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isTrap=true, .readsRs=true },
[RABBITIZER_INSTR_ID_cpu_tltiu] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isTrap=true, .readsRs=true },
[RABBITIZER_INSTR_ID_cpu_teqi] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isTrap=true, .readsRs=true },
[RABBITIZER_INSTR_ID_cpu_tnei] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isTrap=true, .readsRs=true },
[RABBITIZER_INSTR_ID_cpu_tgei] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isTrap=true, .readsRs=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_tgeiu] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isTrap=true, .readsRs=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_tlti] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isTrap=true, .readsRs=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_tltiu] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isTrap=true, .readsRs=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_teqi] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isTrap=true, .readsRs=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_tnei] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isTrap=true, .readsRs=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_bltzal] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isBranch=true, .readsRs=true, .doesLink=true },
[RABBITIZER_INSTR_ID_cpu_bgezal] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isBranch=true, .readsRs=true, .doesLink=true },
[RABBITIZER_INSTR_ID_cpu_bltzall] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isBranch=true, .isBranchLikely=true, .readsRs=true, .doesLink=true },
[RABBITIZER_INSTR_ID_cpu_bgezall] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isBranch=true, .isBranchLikely=true, .readsRs=true, .doesLink=true },
[RABBITIZER_INSTR_ID_cpu_bal] = { .operands={RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isBranch=true, .doesLink=true, .isPseudo=true },
[RABBITIZER_INSTR_ID_cpu_mfc0] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .modifiesRt=true, .notEmitedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_dmfc0] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .modifiesRt=true },
[RABBITIZER_INSTR_ID_cpu_cfc0] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .modifiesRt=true },
[RABBITIZER_INSTR_ID_cpu_mtc0] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .readsRt=true, .notEmitedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_dmtc0] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .readsRt=true },
[RABBITIZER_INSTR_ID_cpu_ctc0] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .readsRt=true },
[RABBITIZER_INSTR_ID_cpu_bgezall] = { .operands={RAB_OPERAND_cpu_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isBranch=true, .isBranchLikely=true, .readsRs=true, .notEmittedByCompilers=true, .doesLink=true },
[RABBITIZER_INSTR_ID_cpu_bal] = { .operands={RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isBranch=true, .notEmittedByCompilers=true, .doesLink=true, .isPseudo=true },
[RABBITIZER_INSTR_ID_cpu_mfc0] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .modifiesRt=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_dmfc0] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .modifiesRt=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_cfc0] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .modifiesRt=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_mtc0] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .readsRt=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_dmtc0] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .readsRt=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_ctc0] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop0d}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .readsRt=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_bc0f] = { .operands={RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .isBranch=true },
[RABBITIZER_INSTR_ID_cpu_bc0t] = { .operands={RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .isBranch=true },
[RABBITIZER_INSTR_ID_cpu_bc0fl] = { .operands={RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .isBranch=true, .isBranchLikely=true },
[RABBITIZER_INSTR_ID_cpu_bc0tl] = { .operands={RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .isBranch=true, .isBranchLikely=true },
[RABBITIZER_INSTR_ID_cpu_tlbr] = { .operands={0}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .notEmitedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_tlbwi] = { .operands={0}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .notEmitedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_tlbr] = { .operands={0}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_tlbwi] = { .operands={0}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_tlbwr] = { .operands={0}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN },
[RABBITIZER_INSTR_ID_cpu_tlbp] = { .operands={0}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .notEmitedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_eret] = { .operands={0}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .notEmitedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_tlbp] = { .operands={0}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_eret] = { .operands={0}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_cpu_mfc1] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_fs}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .isFloat=true, .modifiesRt=true, .readsFs=true },
[RABBITIZER_INSTR_ID_cpu_dmfc1] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_fs}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .isFloat=true, .modifiesRt=true, .readsFs=true },
[RABBITIZER_INSTR_ID_cpu_mtc1] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_fs}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .isFloat=true, .readsRt=true, .modifiesFs=true },
@ -238,6 +238,10 @@ const RabbitizerInstrDescriptor RabbitizerInstrDescriptor_Descriptors[] = {
[RABBITIZER_INSTR_ID_cpu_cvt_d_w] = { .operands={RAB_OPERAND_cpu_fd, RAB_OPERAND_cpu_fs}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .isFloat=true, .isDouble=true, .modifiesFd=true, .readsFs=true },
[RABBITIZER_INSTR_ID_cpu_cvt_s_l] = { .operands={RAB_OPERAND_cpu_fd, RAB_OPERAND_cpu_fs}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .isFloat=true, .modifiesFd=true, .readsFs=true },
[RABBITIZER_INSTR_ID_cpu_cvt_d_l] = { .operands={RAB_OPERAND_cpu_fd, RAB_OPERAND_cpu_fs}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .isFloat=true, .isDouble=true, .modifiesFd=true, .readsFs=true },
[RABBITIZER_INSTR_ID_cpu_mfc2] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop2cd}, .modifiesRt=true },
[RABBITIZER_INSTR_ID_cpu_mtc2] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop2cd}, .readsRt=true },
[RABBITIZER_INSTR_ID_cpu_cfc2] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop2cd}, .modifiesRt=true },
[RABBITIZER_INSTR_ID_cpu_ctc2] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_cpu_cop2cd}, .readsRt=true },
[RABBITIZER_INSTR_ID_cpu_USERDEF_00] = { .operands={0} },
[RABBITIZER_INSTR_ID_cpu_USERDEF_01] = { .operands={0} },
[RABBITIZER_INSTR_ID_cpu_USERDEF_02] = { .operands={0} },
@ -337,7 +341,7 @@ const RabbitizerInstrDescriptor RabbitizerInstrDescriptor_Descriptors[] = {
[RABBITIZER_INSTR_ID_rsp_bne] = { .operands={RAB_OPERAND_rsp_rs, RAB_OPERAND_rsp_rt, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .readsRs=true, .readsRt=true, .isBranch=true },
[RABBITIZER_INSTR_ID_rsp_blez] = { .operands={RAB_OPERAND_rsp_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .readsRs=true, .isBranch=true },
[RABBITIZER_INSTR_ID_rsp_bgtz] = { .operands={RAB_OPERAND_rsp_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .readsRs=true, .isBranch=true },
[RABBITIZER_INSTR_ID_rsp_addi] = { .operands={RAB_OPERAND_rsp_rt, RAB_OPERAND_rsp_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_I, .modifiesRt=true, .readsRs=true, .notEmitedByCompilers=true, .canBeLo=true },
[RABBITIZER_INSTR_ID_rsp_addi] = { .operands={RAB_OPERAND_rsp_rt, RAB_OPERAND_rsp_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_I, .modifiesRt=true, .readsRs=true, .notEmittedByCompilers=true, .canBeLo=true },
[RABBITIZER_INSTR_ID_rsp_addiu] = { .operands={RAB_OPERAND_rsp_rt, RAB_OPERAND_rsp_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_I, .modifiesRt=true, .readsRs=true, .canBeLo=true },
[RABBITIZER_INSTR_ID_rsp_slti] = { .operands={RAB_OPERAND_rsp_rt, RAB_OPERAND_rsp_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_I, .modifiesRt=true, .readsRs=true },
[RABBITIZER_INSTR_ID_rsp_sltiu] = { .operands={RAB_OPERAND_rsp_rt, RAB_OPERAND_rsp_rs, RAB_OPERAND_cpu_immediate}, .instrType=RABBITIZER_INSTR_TYPE_I, .modifiesRt=true, .readsRs=true },
@ -367,9 +371,9 @@ const RabbitizerInstrDescriptor RabbitizerInstrDescriptor_Descriptors[] = {
[RABBITIZER_INSTR_ID_rsp_jalr] = { .operands={RAB_OPERAND_rsp_maybe_rd_rs}, .instrType=RABBITIZER_INSTR_TYPE_R, .isJump=true, .modifiesRd=true, .readsRs=true, .doesLink=true },
[RABBITIZER_INSTR_ID_rsp_movz] = { .operands={RAB_OPERAND_rsp_rd, RAB_OPERAND_rsp_rs, RAB_OPERAND_rsp_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .readsRt=true },
[RABBITIZER_INSTR_ID_rsp_movn] = { .operands={RAB_OPERAND_rsp_rd, RAB_OPERAND_rsp_rs, RAB_OPERAND_rsp_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .readsRt=true },
[RABBITIZER_INSTR_ID_rsp_add] = { .operands={RAB_OPERAND_rsp_rd, RAB_OPERAND_rsp_rs, RAB_OPERAND_rsp_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .readsRt=true, .notEmitedByCompilers=true },
[RABBITIZER_INSTR_ID_rsp_add] = { .operands={RAB_OPERAND_rsp_rd, RAB_OPERAND_rsp_rs, RAB_OPERAND_rsp_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .readsRt=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_rsp_addu] = { .operands={RAB_OPERAND_rsp_rd, RAB_OPERAND_rsp_rs, RAB_OPERAND_rsp_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .readsRt=true },
[RABBITIZER_INSTR_ID_rsp_sub] = { .operands={RAB_OPERAND_rsp_rd, RAB_OPERAND_rsp_rs, RAB_OPERAND_rsp_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .readsRt=true },
[RABBITIZER_INSTR_ID_rsp_sub] = { .operands={RAB_OPERAND_rsp_rd, RAB_OPERAND_rsp_rs, RAB_OPERAND_rsp_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .notEmittedByCompilers=true, .readsRs=true, .readsRt=true },
[RABBITIZER_INSTR_ID_rsp_subu] = { .operands={RAB_OPERAND_rsp_rd, RAB_OPERAND_rsp_rs, RAB_OPERAND_rsp_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .readsRt=true },
[RABBITIZER_INSTR_ID_rsp_and] = { .operands={RAB_OPERAND_rsp_rd, RAB_OPERAND_rsp_rs, RAB_OPERAND_rsp_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .readsRt=true },
[RABBITIZER_INSTR_ID_rsp_or] = { .operands={RAB_OPERAND_rsp_rd, RAB_OPERAND_rsp_rs, RAB_OPERAND_rsp_rt}, .instrType=RABBITIZER_INSTR_TYPE_R, .modifiesRd=true, .readsRs=true, .readsRt=true },
@ -385,10 +389,10 @@ const RabbitizerInstrDescriptor RabbitizerInstrDescriptor_Descriptors[] = {
[RABBITIZER_INSTR_ID_rsp_bltz] = { .operands={RAB_OPERAND_rsp_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .readsRs=true, .isBranch=true },
[RABBITIZER_INSTR_ID_rsp_bgez] = { .operands={RAB_OPERAND_rsp_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .readsRs=true, .isBranch=true },
[RABBITIZER_INSTR_ID_rsp_bltzal] = { .operands={RAB_OPERAND_rsp_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .readsRs=true, .isBranch=true, .doesLink=true },
[RABBITIZER_INSTR_ID_rsp_bgezal] = { .operands={RAB_OPERAND_rsp_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .readsRs=true, .isBranch=true, .doesLink=true },
[RABBITIZER_INSTR_ID_rsp_bal] = { .operands={RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isBranch=true, .doesLink=true, .isPseudo=true },
[RABBITIZER_INSTR_ID_rsp_mfc0] = { .operands={RAB_OPERAND_rsp_rt, RAB_OPERAND_rsp_cop0d}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .modifiesRt=true, .notEmitedByCompilers=true },
[RABBITIZER_INSTR_ID_rsp_mtc0] = { .operands={RAB_OPERAND_rsp_rt, RAB_OPERAND_rsp_cop0d}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .readsRt=true, .notEmitedByCompilers=true },
[RABBITIZER_INSTR_ID_rsp_bgezal] = { .operands={RAB_OPERAND_rsp_rs, RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .readsRs=true, .isBranch=true, .notEmittedByCompilers=true, .doesLink=true },
[RABBITIZER_INSTR_ID_rsp_bal] = { .operands={RAB_OPERAND_cpu_branch_target_label}, .instrType=RABBITIZER_INSTR_TYPE_REGIMM, .isBranch=true, .notEmittedByCompilers=true, .doesLink=true, .isPseudo=true },
[RABBITIZER_INSTR_ID_rsp_mfc0] = { .operands={RAB_OPERAND_rsp_rt, RAB_OPERAND_rsp_cop0d}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .modifiesRt=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_rsp_mtc0] = { .operands={RAB_OPERAND_rsp_rt, RAB_OPERAND_rsp_cop0d}, .instrType=RABBITIZER_INSTR_TYPE_UNKNOWN, .readsRt=true, .notEmittedByCompilers=true },
[RABBITIZER_INSTR_ID_rsp_USERDEF_00] = { .operands={0} },
[RABBITIZER_INSTR_ID_rsp_USERDEF_01] = { .operands={0} },
[RABBITIZER_INSTR_ID_rsp_USERDEF_02] = { .operands={0} },

View File

@ -238,6 +238,10 @@ const char *RabbitizerInstrId_Names[] = {
[RABBITIZER_INSTR_ID_cpu_cvt_d_w] = "cvt.d.w",
[RABBITIZER_INSTR_ID_cpu_cvt_s_l] = "cvt.s.l",
[RABBITIZER_INSTR_ID_cpu_cvt_d_l] = "cvt.d.l",
[RABBITIZER_INSTR_ID_cpu_mfc2] = "mfc2",
[RABBITIZER_INSTR_ID_cpu_mtc2] = "mtc2",
[RABBITIZER_INSTR_ID_cpu_cfc2] = "cfc2",
[RABBITIZER_INSTR_ID_cpu_ctc2] = "ctc2",
[RABBITIZER_INSTR_ID_cpu_USERDEF_00] = "USERDEF_00",
[RABBITIZER_INSTR_ID_cpu_USERDEF_01] = "USERDEF_01",
[RABBITIZER_INSTR_ID_cpu_USERDEF_02] = "USERDEF_02",

View File

@ -91,6 +91,7 @@ bool RabbitizerInstrDescriptor_hasOperandAlias(const RabbitizerInstrDescriptor *
case RAB_OPERAND_cpu_fd:
case RAB_OPERAND_cpu_cop1cs:
case RAB_OPERAND_cpu_cop2t:
case RAB_OPERAND_cpu_cop2cd:
case RAB_OPERAND_cpu_op:
break;
@ -579,8 +580,8 @@ bool RabbitizerInstrDescriptor_readsFd(const RabbitizerInstrDescriptor *self) {
return self->readsFd;
}
bool RabbitizerInstrDescriptor_notEmitedByCompilers(const RabbitizerInstrDescriptor *self) {
return self->notEmitedByCompilers;
bool RabbitizerInstrDescriptor_notEmittedByCompilers(const RabbitizerInstrDescriptor *self) {
return self->notEmittedByCompilers;
}
bool RabbitizerInstrDescriptor_canBeHi(const RabbitizerInstrDescriptor *self) {

View File

@ -151,6 +151,10 @@ void RabbitizerInstruction_blankOut(RabbitizerInstruction *self) {
self->word = RAB_INSTR_PACK_cop2t(self->word, 0);
break;
case RAB_OPERAND_cpu_cop2cd:
self->word = RAB_INSTR_PACK_cop2cd(self->word, 0);
break;
case RAB_OPERAND_cpu_op:
self->word = RAB_INSTR_PACK_op(self->word, 0);
break;

View File

@ -31,7 +31,7 @@ bool RabbitizerInstruction_isLikelyHandwritten(const RabbitizerInstruction *self
}
}
if (RabbitizerInstrDescriptor_notEmitedByCompilers(self->descriptor)) {
if (RabbitizerInstrDescriptor_notEmittedByCompilers(self->descriptor)) {
return true;
}
@ -201,6 +201,10 @@ uint32_t RabbitizerInstruction_getValidBits(const RabbitizerInstruction *self) {
validbits = RAB_INSTR_PACK_cop2t(validbits, ~0);
break;
case RAB_OPERAND_cpu_cop2cd:
validbits = RAB_INSTR_PACK_cop2cd(validbits, ~0);
break;
case RAB_OPERAND_cpu_op:
validbits = RAB_INSTR_PACK_op(validbits, ~0);
break;

View File

@ -268,8 +268,19 @@ void RabbitizerInstruction_processUniqueId_Coprocessor1(RabbitizerInstruction *s
}
void RabbitizerInstruction_processUniqueId_Coprocessor2(RabbitizerInstruction *self) {
uint32_t fmt = RAB_INSTR_GET_fmt(self);
self->_mandatorybits = RAB_INSTR_PACK_fmt(self->_mandatorybits, fmt);
self->_handwrittenCategory = true;
switch (fmt) {
#include "instructions/instr_id/cpu/cpu_cop2.inc"
default:
break;
}
self->descriptor = &RabbitizerInstrDescriptor_Descriptors[self->uniqueId];
}

View File

@ -18,6 +18,7 @@ const OperandCallback instrOpercandCallbacks[] = {
[RAB_OPERAND_cpu_fd] = RabbitizerOperandType_process_cpu_fd,
[RAB_OPERAND_cpu_cop1cs] = RabbitizerOperandType_process_cpu_cop1cs,
[RAB_OPERAND_cpu_cop2t] = RabbitizerOperandType_process_cpu_cop2t,
[RAB_OPERAND_cpu_cop2cd] = RabbitizerOperandType_process_cpu_cop2cd,
[RAB_OPERAND_cpu_op] = RabbitizerOperandType_process_cpu_op,
[RAB_OPERAND_cpu_code] = RabbitizerOperandType_process_cpu_code,
[RAB_OPERAND_cpu_code_lower] = RabbitizerOperandType_process_cpu_code_lower,

View File

@ -101,6 +101,15 @@ size_t RabbitizerOperandType_process_cpu_cop2t(const RabbitizerInstruction *self
return totalSize;
}
size_t RabbitizerOperandType_process_cpu_cop2cd(const RabbitizerInstruction *self, char *dst,
UNUSED const char *immOverride, UNUSED size_t immOverrideLength) {
size_t totalSize = 0;
const char *reg = RabbitizerRegister_getNameCop2(RAB_INSTR_GET_cop2cd(self));
RABUTILS_BUFFER_CPY(dst, totalSize, reg);
return totalSize;
}
size_t RabbitizerOperandType_process_cpu_sa(const RabbitizerInstruction *self, char *dst,
UNUSED const char *immOverride, UNUSED size_t immOverrideLength) {
size_t totalSize = 0;

View File

@ -0,0 +1,96 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#include "rabbitizer.h"
#include <string.h>
#include <stdlib.h>
#include <assert.h>
size_t strlen_null(const char *string) {
if (string == NULL) {
return 0;
}
return strlen(string);
}
typedef struct TestEntry {
uint32_t word;
const char *immOverride;
const char *expectedStr;
} TestEntry;
const TestEntry entries[] = {
{ 0x3C088001, NULL, "lui $t0, 0x8001" },
{ 0x25080E60, NULL, "addiu $t0, $t0, 0xE60" },
{ 0x3C090002, NULL, "lui $t1, 0x2" },
{ 0x25298DE0, NULL, "addiu $t1, $t1, -0x7220" },
{ 0xAD000000, NULL, "sw $zero, 0x0($t0)" },
{ 0xAD000004, NULL, "sw $zero, 0x4($t0)" },
{ 0x21080008, NULL, "addi $t0, $t0, 0x8" },
{ 0x2129FFF8, NULL, "addi $t1, $t1, -0x8" },
{ 0x1520FFFB, NULL, "bnez $t1, . + 4 + (-0x5 << 2)" },
{ 0x00000000, NULL, "nop" },
{ 0x3C0A8000, NULL, "lui $t2, 0x8000" },
{ 0x254A0494, NULL, "addiu $t2, $t2, 0x494" },
{ 0x3C1D8002, NULL, "lui $sp, 0x8002" },
{ 0x01400008, NULL, "jr $t2" },
{ 0x27BDF8C0, NULL, "addiu $sp, $sp, -0x740" },
{ 0x3C018001, NULL, "lui $at, 0x8001" },
{ 0x03E00008, NULL, "jr $ra" },
{ 0xAC24E190, NULL, "sw $a0, -0x1E70($at)" },
{ 0x3C018001, "%hi(D_8000E190)", "lui $at, %hi(D_8000E190)" },
{ 0x03E00008, NULL, "jr $ra" },
{ 0xAC24E190, "%lo(D_8000E190)", "sw $a0, %lo(D_8000E190)($at)" },
{ 0x0C001F24, NULL, "jal func_80007C90" },
{ 0x0C001F24, "some_func", "jal some_func" },
{ 0x8F99805C, NULL, "lw $t9, -0x7FA4($gp)"},
{ 0x8F99805C, "%call16(strcmp)", "lw $t9, %call16(strcmp)($gp)"},
{ 0x8F858028, NULL, "lw $a1, -0x7FD8($gp)"},
{ 0x8F858028, "%got(STR_10007C90)", "lw $a1, %got(STR_10007C90)($gp)"},
// Invalid instructions
{ 0x44444444, NULL, ".word 0x44444444 # cfc1 $a0, $8 # 00000444" },
{ 0x77777777, NULL, ".word 0x77777777 # INVALID $k1, $s7, 0x7777 # 00000000" },
{ 0xEEEEEEEE, NULL, ".word 0xEEEEEEEE # INVALID $s7, $t6, -0x1112 # 00000000" },
};
int main() {
int errorCount = 0;
size_t i;
for (i = 0; i < ARRAY_COUNT(entries); i++) {
const TestEntry *entry = &entries[i];
RabbitizerInstruction instr;
char *buffer;
size_t bufferSize;
size_t immOverrideLength = strlen_null(entry->immOverride);
RabbitizerInstruction_init(&instr, entry->word, 0);
RabbitizerInstruction_processUniqueId(&instr);
bufferSize = RabbitizerInstruction_getSizeForBuffer(&instr, immOverrideLength, 0);
buffer = malloc(bufferSize + 1);
assert(buffer != NULL);
RabbitizerInstruction_disassemble(&instr, buffer, entry->immOverride, immOverrideLength, 0);
if (entry->expectedStr == NULL) {
printf("Word '0x%08X' doesn't have a expected str, got '%s'\n", entry->word, buffer);
errorCount++;
} else if (strcmp(buffer, entry->expectedStr) != 0) {
fprintf(stderr, "Error on word '0x%08X'. Expected '%s', got '%s'\n", entry->word, entry->expectedStr, buffer);
errorCount++;
}
free(buffer);
RabbitizerInstruction_destroy(&instr);
}
return errorCount;
}

View File

@ -6,3 +6,4 @@
set -e
./build/tests/c/instruction_checks/jalr.elf
./build/tests/c/instruction_checks/plain_disassembly.elf