You know one of the things people have asked me is how to do X things or Y things (a specific question). Do you know one of the reason why hackers/modders ignored your questions? Because they don't know how to give/express/explain to you their information since they figured it out 'naturally'. I had that problem too. I analyzed and I figured out that you HAVE TO LEARN THE BASIC first. Everyone ignored that and kept insisting us to help them doing that X things when clearly they are not LISTENING. Then they made a memes out of us (which confused me because I could not do what they did right now). Listening skill is actually a skill to listen to other people's method but I think to be sympathy with them as well. For example someone who is on the computer for 24/7 hacking might not have the chance to go out in the sun to meet new friends, figuring what is wrong with the world and suffering from mental illness such as high ego. Do you EXPECT them to have any strong arguments? When you do that you see that as COOL but I see that as poor communication skills (speaking-related). Listening skill is not AGREEING all of the other person's opinion like a copycat. HEY HEY, don't believe me. I will prove that later.
There are instructions exclusively for PS2 and PSP as well but I'm not going into something so specific. I will only cover the instructions that all MIPS might have.
The basics are MIPS CPU has 32 registers ( I will add them later). They are either named r0 to r31 where the first register is always zero, think of register as SUPER FAST MEMORY in the CPU , sure cache are fast but registers are faster.
- RAM Instructions: Loading something from RAM. It needs 3 parameter
* The destination register, the offset (16 bits signed int), the RAM register
lb c, 0xAAAA(b)
- Load a byte from offset at the address of (b + 0xAAAA) and stored it into register c
lbu c, 0xAAAA(b)
- Load an unsigned byte from offset at the address of (b + 0xAAAA) and stored it into register c
lh c, 0xAAAA(b)
- Load a half (2 bytes) from offset at the address of (b + 0xAAAA) and stored it into register c
* MIPS alignment rules: The address of b + 0xAAAA must be a multiple of 2.
lhu c, 0xAAAA(b)
Same as lh but unsigned
lw c , 0xAAAA(b)
- Load a word (4 bytes) from offset (b + 0xAAAA) and store it into register c
* MIPS alignment rules: The address of b + 0xAAAA must be a multiple of 4
!!! You don't need lwu if your console register size is 32bit.
- Math instruction (there is a fancy word for that too):
* add a , b, c
ADDITION
register a = register b + register c
TRAP IF OVERFLOW
Unless you are taking the extreme path of handling exception MANUALLY, never use this because if there is overflow occurs, your game will TRAP (Google it). I don't remember seeing this behavior in C.
* addu a, b, c
ADDITION UNSIGNED
register a = register b + register c
Using this one because if overflow occurs your game will continue normally. Yes in software practice ignoring errors is deadly but you are a hacker there. You can't just have a mindset of a software developer. Adding even a single line of code is a big deal itself, if you handle exception it will be extreme. Software developer, programmer has everything taken care off by programming language for them. (yes appreciate C compiler or python or any compiler , interpreter people)
* addi a, b, 0xAAAA
* addiu a, b, 0xAAAA
ADDITION WITH IMMEDIATE
register a = register b + 0xAAAA
Same as above but are you wondering if it all involves register then where does the constant comes from? Yes in MIPS they come from IMMEDIATE opcodes people. IMMEDIATE is a fancy word for 'CONSTANT' in this case and 'CONSTANT' is a fancy word for 'a value that never changes'.
* sub a, b, c
* subu a, b, c
SAME as add equivalent. There is no IMMEDIATE version of it because the one who works with CPU only implements what IS NEEDED. If there is something that can be converted into other thing they won't bother to create an opcode for it. This reduces cost and redundancy (maybe complexity as well?)
I only see one usage of sub is to quickly loads negative into a register from a source register.
* sll a, b, sa (shift left logical)
a = b << sa (sa is a constant but it has limited range)
this is equivalent to:
a = b * 2^sa.
A fast way to multiple to a power of 2. (integer division)
* srl a, b, sa (shift right logical)
* sra a, b, sa (shift right arthimetic)
a = b >> sa
a = b / 2^sa
A fast way to divide to a power of 2 (integer division)
What is the difference? Google.
Why there is no shift left arthimetic? Because they work the same as shift left logical. It saves us hacker from having to remember redundant things for no good reason. Going for a general way actually is a good way to 'connect' your memories together and to 'compress' your memories as well.
I am a hacker and even I forgot the difference between shift right everytime I encounter it, partly because I have never got the chance to use it.
* mult a, b
* mult c, a, b (this one is harder to encode)
hi register = (upper 32bit) a * b
lo register = (lower 32bit) a * b (Just use the lo register for most case)
Multiplication opcodes!!! Take any kind of number and put in there!
* div a, b
lo register = a / b
hi register = a % b ( remainder of a / b)
Division opcodes!!! Take any kind of number and put in there!
-- Oh really you shouldn't use mult or div if there is a sll or shift right equivalent because the opcodes are 'general' , and 'general' things are slower if there is a limited-feature thing involved in CPU design. Sure for emulators you won't feel it but you might feel it when users complained about your code made the game slower especially for a code that gets executed every frame in real console. Hey hey don't believe me, google and research this for yourself.
* mflo a
* mfhi a
Move from lo register to register a
Move from hi register to register a
* Compare, Branching (fancy word for Condition)
slt a,b, c (set less than)
slti a, b, 0xAAAA (set less than IMMEDIATE)
sltiu a, b, 0xAAAA (set less than unsigned IMMEDIATE)
a = b < c
a = b < 0xAAAA
a = (b < 0xAAAA) unsigned
But ERM, I studied programming and a bool variable contains True,False!
Ok False is 0 and True is not equal to 0. In registers you only see values. This is only a recommedation , a programmer might put a CONSTANT True as 0 and False as 29 to laugh at people like you. And the extreme case, if 0,3,5,6,8 or < 13 or > 59 is true, the other is false. So you might need a programmer to decipher what the code actually means or make a table of 2^32 possible values, brute-force rules!
You will see if a game follows the definition, then the game developer is actually generous. I see hackers only appreciate the game developer that managed to annoy them. Game developers became evil when hackers released something that affects their income or their reputation, and hackers see that as a challegen!. Think about Hot Coffee mod for GTA SA. It is good that the GTAGarage put it down in respect to Rockstar.
beq a, b, address
// branch to address if register a == register b
bne a, b , address
// branch to address if register a != register b
In PS2 there are 'branch likely' opcode which executes the delay slot only when the condition is true while the above two execute the delay slot everytime.
There are branch greater or equal to zero as well but I used slti all the time. Those opcode saved code space (by a little)
* BOOLEAN OPCODE
and a,b, c
andi a,b, 0xAAAA (Andy !)
a = b & c
a = b & 0xAAAA
or a,b,c
ori a,b, 0xAAAA
a = b | c
a = b | 0xAAAA
xor a,b, c
xori a,b, 0xAAAA (Sorry !)
a = b ^ c
a = b ^ 0xAAAA
nor a,b,c
( I don't remember ever seeing a nori)
a = b NOR c
* A fast way to compare with -1
Google their truth table but I will show you that practice is the best.
// Table gotten from
www.cs.uwm.edu/classes/cs315/Bacon/Lect ... 05s03.html
// Wow tapatalk can let you paste table directly into your post people. In GTAGarage we did that by using BBCodes and in zetaboard I don't know how to do that. I just figured out that you can paste it directly. I am an idiot!
[table]
[tr][td]
[table][tr][td]Register Number[/td]
[td]Conventional Name[/td]
[td]Usage[/td][/tr][/table]
[/td][/tr]
[tr]
[td]$0[/td]
[td]$zero [/td]
[td]Hard-wired to 0
[/td]
[/tr]
[tr]
[td]$1 [/td]
[td]$f20 - $f31 [/td]
[td]Reserved for pseudo-instructions
[/td]
[/tr]
[tr]
[td]$2 - $3 [/td]
[td]$v0, $v1 [/td]
[td]Return values from functions
[/td]
[/tr]
[tr]
[td]$4 - $7[/td]
[td]$a0 - $a3 [/td]
[td]Arguments to functions - not preserved by subprograms
[/td]
[/tr]
[tr]
[td]$8 - $15 [/td]
[td]$t0 - $t7 [/td]
[td]Temporary data, not preserved by subprograms
[/td]
[/tr]
[tr]
[td]$16 - $23 [/td]
[td]$s0 - $s7 [/td]
[td]Saved registers, preserved by subprograms
[/td]
[/tr]
[tr]
[td]$24 - $25 [/td]
[td]$t8 - $t9 [/td]
[td]More temporary registers, not preserved by subprograms
[/td]
[/tr]
[tr]
[td]$24 - $25 [/td]
[td]$k0 - $k1 [/td]
[td]Reserved for kernel. Do not use.
[/td]
[/tr]
[tr]
[td]$28 [/td]
[td]$gp [/td]
[td]Global Area Pointer (base of global data segment)
[/td]
[/tr]
[tr]
[td]$29[/td]
[td]$sp [/td]
[td]Stack Pointer
[/td]
[/tr]
[tr]
[td]$30[/td]
[td]$fp [/td]
[td]Frame Pointer
[/td]
[/tr]
[tr]
[td]$31[/td]
[td]$ra [/td]
[td]Return Address
[/td]
[/tr]
[tr]
[td]$f0 - $f3 [/td]
[td]- [/td]
[td]Floating point return values
[/td]
[/tr]
[tr]
[td]$f4 - $f10 [/td]
[td]- [/td]
[td]Temporary registers, not preserved by subprograms
[/td]
[/tr]
[tr]
[td]$f12 - $f14 [/td]
[td]- [/td]
[td]First two arguments to subprograms, not preserved by subprograms
[/td]
[/tr]
[tr]
[td]$f16 - $f18 [/td]
[td]- [/td]
[td]More temporary registers, not preserved by subprograms
[/td]
[/tr]
[tr]
[td]$f20 - $f31 [/td]
[td]- [/td]
[td]Saved registers, preserved by subprograms
[/td]
[/tr]
[/table]
- I am using the named register and PCSX2 and PPSSPP used named registers. They allow data highlighting as well and when something change, you will notice it.
Here is the structure of a MIPS function (but not means to necessarily follow through, it is a recommended process):
- Decreases the stack pointer.
- Saves the saved register to a stack.
- Processing argument registers.
- Calculating , printing, drawing.
- Returning data to v0.
- If it is 64bit, returning data to v1.
- Adding the stack pointer back to where it belongs.