mirror of
https://github.com/Decompollaborate/rabbitizer.git
synced 2025-01-30 15:32:43 +00:00
commit
f7ac917f80
4
.markdownlint.json
Normal file
4
.markdownlint.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"MD029": false,
|
||||
"MD013": { "code_block_line_length": 120}
|
||||
}
|
1
Makefile
1
Makefile
@ -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)
|
||||
|
70
README.md
70
README.md
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -19,6 +19,7 @@ cpu_ft,
|
||||
cpu_fd,
|
||||
cpu_cop1cs,
|
||||
cpu_cop2t,
|
||||
cpu_cop2cd,
|
||||
cpu_op,
|
||||
cpu_code,
|
||||
cpu_code_lower,
|
||||
|
@ -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,
|
||||
|
@ -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
504
docs/usage_c_api.md
Normal 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.
|
@ -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)
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
26
include/instructions/instr_id/cpu/cpu_cop2.inc
Normal file
26
include/instructions/instr_id/cpu/cpu_cop2.inc
Normal 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
|
||||
)
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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: ...
|
||||
|
@ -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, ""),
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -19,6 +19,7 @@ cpu_ft,
|
||||
cpu_fd,
|
||||
cpu_cop1cs,
|
||||
cpu_cop2t,
|
||||
cpu_cop2cd,
|
||||
cpu_op,
|
||||
cpu_code,
|
||||
cpu_code_lower,
|
||||
|
@ -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} },
|
||||
|
@ -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",
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
96
tests/c/instruction_checks/plain_disassembly.c
Normal file
96
tests/c/instruction_checks/plain_disassembly.c
Normal 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;
|
||||
}
|
@ -6,3 +6,4 @@
|
||||
set -e
|
||||
|
||||
./build/tests/c/instruction_checks/jalr.elf
|
||||
./build/tests/c/instruction_checks/plain_disassembly.elf
|
||||
|
Loading…
x
Reference in New Issue
Block a user