If you want to learn MIPS get theCheatsheet! it has all the MIPS commands, it covers the
commands and how those commands compile to bytecode
These
tutorials assume you have a basic understanding of concepts like
HEX and Registers...
If you're not familiar with these, take a look at one of the
other tutorials first!
MIPS Registers
Bits
Reg
Num
Name
Detail
00000
0
$zero
Hard-wired zero
00001
1
$at
Reserved for Assembler
Used by psuedo-ops (macros)
00010
2
$v0
Return Value
Used for return values from function calls
00011
3
$v1
Return Value
Used for return values from function calls
00100
4
$a0
Argument for function
Used to pass values to function calls
00101
5
$a1
Argument for function
Used to pass values to function calls
00110
6
$a2
Argument for function
Used to pass values to function calls
00111
7
$a3
Argument for function
Used to pass values to function calls
01000
8
$t0
Temporaries Caller
May be changed by sub
01001
9
$t1
Temporaries Caller
May be changed by sub
01010
10
$t2
Temporaries Caller
May be changed by sub
01011
11
$t3
Temporaries Caller
May be changed by sub
01100
12
$t4
Temporaries Caller
May be changed by sub
01101
13
$t5
Temporaries Caller
May be changed by sub
01110
14
$t6
Temporaries Caller
May be changed by sub
01111
15
$t7
Temporaries Caller
May be changed by sub
10000
16
$s0
Saved registers Callee
if changed by Sub must be backed up
10001
17
$s1
Saved registers Callee
if changed by Sub must be backed up
10010
18
$s2
Saved registers Callee
if changed by Sub must be backed up
10011
19
$s3
Saved registers Callee
if changed by Sub must be backed up
10100
20
$s4
Saved registers Callee
if changed by Sub must be backed up
10101
21
$s5
Saved registers Callee
if changed by Sub must be backed up
10110
22
$s6
Saved registers Callee
if changed by Sub must be backed up
10111
23
$s7
Saved registers Callee
if changed by Sub must be backed up
11000
24
$t8
Temporaries Caller
May be changed by sub
11001
25
$t9
Temporaries Caller
May be changed by sub
11010
26
$k0
Reserved for OS Kernel
11011
27
$k1
Reserved for OS Kernel
11100
28
$gp
Global area Pointer
11101
29
$sp
Stack Pointer
11110
30
$fp
Frame Pointer
11111
31
$ra
Return Address Caller
Special Registers
Name
Detail
PC
Program Counter
LO
LOw part
of multiplication result
HI
HIgh part of multiplication result
All the registers function the same... but there
are 'Official Rules!'
A calling function should use the Ax registers to send data to a
subroutine... if the calling function needs the Tx registers to stay
the same it should back them up - the Ax registers may also
change...
The Sx registers can be changed by the subroutine - but it's the
subroutines job to back them up if it changes them... not the
calling function!
The
syntax may vary depending on your assembler!
Some need the $ prefix before a register name, others don't use
it... also some use # to denote a comment, whereas others use a
semicolon ;
Float Reg
Name
Detail
f0
ft0
FP
temporaries Caller
f1
ft1
FP
temporaries Caller
f2
ft2
FP
temporaries Caller
f3
ft3
FP
temporaries Caller
f4
ft4
FP
temporaries Caller
f5
ft5
FP
temporaries Caller
f6
ft6
FP
temporaries Caller
f7
ft7
FP
temporaries Caller
f8
fs0
FP
saved registers Callee
f9
fs1
FP
saved registers Callee
f10
fa0
FP
arguments/return values Caller
f11
fa1
FP
arguments/return values Caller
f12
fa2
FP
arguments Caller
f13
fa3
FP
arguments Caller
f14
fa4
FP
arguments Caller
f15
fa5
FP
arguments Caller
f16
fa6
FP
arguments Caller
f17
fa7
FP
arguments Caller
f18
fs2
FP
saved registers Callee
f19
fs3
FP
saved registers Callee
f20
fs4
FP
saved registers Callee
f21
fs5
FP
saved registers Callee
f22
fs6
FP
saved registers Callee
f23
fs7
FP
saved registers Callee
f24
fs8
FP
saved registers Callee
f25
fs9
FP
saved registers Callee
f26
fs10
FP
saved registers Callee
f27
fs11
FP
saved registers Callee
f28
ft8
FP
temporaries Caller
f29
ft9
FP
temporaries Caller
f30
ft10
FP
temporaries Caller
f31
ft11
FP
temporaries Caller
Delay slots
Due to the processor pipeline, there will be times when a command is
executed 'out of order'... happening before, or after the command it
appears in the code... Here are the ones you need to watch.
1.Delayed branches: When a branch occurs
(either conditional or non conditional) the command AFTER the branch in
the code will occur BEFORE the branch when executed!
2. Load Delays: on MIPS-I When a load occurs the
data will not be available until AFTER the next instruction... Basically
the data load takes an extra command. This is no longer an issue on
MIPS-II (The PSX is MIPS-I, the N64 is MIPS-II)....
Note: it seems the emulator may not actually simulate this 'bug' so our
code may work even if it should not... though our armips will warn us!
MIPS Addressing Modes
MIPS is a 'Load and Store' architecture processor, meaning that many of
the commands only work between registers.
Mode
Notes
Format
Example
Immediate Addressing
A fixed number is the parameter for an operation.
n
ANDI a0,a1,0xF
Register Addressing
A register itself will be used as a source or destination of an
operation.
Rn
Register Indirect with Offset Addressing
This Addressing mode uses the value from the address in a
register, offset by a fixed numeric value.
n(Rm)
Program Counter Relative with Offset Addressing
used for relative jump and branch operations.
BEQ label
BNE label
Psuedo Direct Addressing
26 bits of the parameter are shifted left two bits, and the top 4
bits are taken from the program counter:
%PPPPnnnnnnnnnnnnnnnnnnnnnnnnnn00
Lesson
1 - Getting Started with the MIPS
Lets start learning about the Mips... Lets learn how to do simple
maths operations, and how to transfer data to and from memory.
There's a video of this lesson, just click the icon to
the right to watch it ->
Lesson1.asm
A template program
To allow us to get started programming quickly and see the
results, we'll be using a 'template program'...
This consists of 3 parts:
A Header - this includes some parameters in
the data segment for our program
The Program - this is the body of our
program where we do our work.
A Generic Footer - this will return control to
the system
The DevTools on this
website come with headers to allow this program to compile for
either the N64 or PSX, but without them you couldn't compile
this program.
It takes a lot more code to get either of these machines to
actually boot!
Commands, Labels and jumps
Lets take a look at a simple program!...
There will be times we need to jump around the code... the
simplest way to do this is the command
'J'... this will jump to another position in the code ...
notice, commands like this are indented by a tab.
Notice the line which is not indented and ends with a colon :
- that makes it a label called 'InfLoop'
... labels tell the assembler to 'name' this position in the
program - the assembler will convert the label to a byte number in
the executable... thanks to the assembler we don't need to worry
what number that ends up being...
you'll also notice text in green starting with a Semicolon ; - this is a comment
(REMark) - they have no effect on the code (Note the MARS
simulator uses the # symbol for comments)
You will notice there is a NOP command
after the J and JAL commands -
There is something known as a 'Delay slot' after jumps, and for
now we need to fill them with NOP (No OPeration)... NOP itself
does nothing - We'll discuss Delay slots again soon.
Loading Immediate values
We have 31 registers in total - but we'll be using a0-a7 for
testing... the t0-5 and s0-11 registers all work the same.
To load a register we use the function LI (Load
Immediate)... This sets a register to a fixed value in the code..
the destination register is on the left of
the comma... the source value is on the
right.
We can use decimal, Hexadecimal (by starting the value with 0x) or
Ascii (by putting a character in quotes '')
'Immediate values are values on the same source code line - rather
than being taken from a register or memory address.
The Registers will be loaded as specified.
If we want to give a number a label we can use a Symbol... these
are defined with EQU - a name
and value are specified
The symbol can then be used in the source
code, the assembler will convert the symbols back to their
numeric values in the bytecode.
They are similar to labels, both give a number to a text value...
but a label's value is the final byte address of the code line,
calculated by the assembler
We can also load the value of a Label... but rather than LI, we
use LA (Load Address) to load
the label value into a register
Here's the result!
Some of these commands are
'Psuedo-ops'... this is where the assembler compiles one command
into multiple in the final binary...
It makes things easier for us to let the assembler to do as much
of the work as possible, so we won't differentiate between
Psuedo and 'Real' commands.
Moving between registers
We can transfer values
between registers with MOVE
As before, The destination register is on the left, the source
is on the right.
The value is copied from A0 to A1 and A2
Load Upper Immediate
LUI stands for Load Upper
Immediate... this command takes a 16 bit value, and loads it into
the top 16 bits of the 32 bit register (EG 0xFFFF---- )
We can't actually load 32 bits of data into a register in one go,
our LI command is actually converted to multiple commands, such as
LUI and ADDI
here is the result
Addition and Subtraction
We can add an immediate value (a fixed value) with ADDI.
Somewhat surprisingly there is no SUBI, however we can use ADDI with a negative immediate
here is the result
Of course we usually won't want to work with immediates.
We can ADD or SUBtract
one register from another, and store the result in a third.
Here are the results
Reading and Writing to and from Ram
The
MIPS is a 32 bit CPU - so WORDS are 32 bits (not 16 like on 8/16
bit systems)...
A Half-Word is 16 bits!... but relax, a byte is still 8 bits! so
at least everything hasn't changed!
To read from an address we need to load it into a
register with LA (LoadAddress) -
any register can be used for this... we need to specify the source
address in brackets () - the destination register is on the left of
the comma as always
LW can be used to Load a Word (32 bit) from the
specified address SW can be used to Store a Word (32 bit)
to the specified address.
There are other size options, but we'll look at those later.
A0 was loaded from the address in A2
A1 was stored to the address in A2
Typically
(but not always) the MIPS CPU is a LITTLE ENDIAN system... that
means the least significant byte of the 32 bit word is stored
first in memory, so it may look like it's 'Reversed'. Don't
worry! It will be in the correct order when we load it back.
Actually the PSX runs the CPU in LITTLE ENDIAN mode - but the
N64 uses BIG ENDIAN, so your results may vary!
Jumps: J JR JAL JALR... and RET!
There's something known as a
'Delay slot' after a jump'... for now will fill it with a NOP -
which does nothing !
We'll discuss delay slots in detail in just a moment.
J - Jump
J is a simple jump to label command... we specify the label to jump
to, and the code execution will continue there... there's not RETurn
command like a call - if we want the code to continue after the
jump, we probably want another jump back.
JR - Jump to Register
Rather than specifying a label as an 'immediate' value, we can use a
register value
we would just load the address into the register, then specify that
address
JAL - Jump and Link ... This is the equivalent
of a Call / Gosub
Unlike other CPU's this function does not use the stack... the
return address is loaded into RA. We return with JR
RA
... which will jump to the return address - equivalent to a RETURN
command
If we want to nest calls with JAL - we should push RA
onto the stack at the start, and pop it at the end.
JALR - Jump and Link to Register
This function also uses a return address... however it jumps to the
address in a register...
This function also allows an alternative return
register (normally RA)
Delay Slots
Delay slots are a bit of a weird concept!
Jump delays mean the command after a jump actually occurs before
it - this is weird, but helps the processor work more
efficiently
Load delays mean loading from memory takes more than one
command, so the data loaded may not be available for the next
command - though the emulators may not represent this
limitation!
Load Delays refer to the fact that a memory load takes more than
one command.
This means that if the command after a load uses the destination of
the load, then it may not have been loaded yet!
In this example the ORI command is in the load
delay slot, and uses the loaded A1, but it may not have
been loaded yet - so may not work properly... we should put a NOP
before the ORI command
The PSX R3000 processor DOES have load delays, but it is not
simulated by the emulator, but we will get an assembler warning.
The N64 R4000 processor does not have this limitation (The command
will be slower, but no error will occur)
Branch Delays are where the command after a branch actually occurs
before it!... this is why we've been putting NOPs in after all out
jumps.
This seems very weird, but allows the processor to save a little
time, as the command after a jump is loaded before the jump is
processed.
In this example, we've put an ORI in the branch
delay slot, and it actually occurs before the jump!
The ORI command occurred before the jump.
We can take advantage of this when doing a loop!
Here we've used A0 as a loop counter, we decrease it by one each
time... we can move the DEC commandinto the delay slot... it actually occurs
before the branch - and we gain a little performance!
Here are the results
Lesson
2 - Addressing modes and more
We've covered the absolute basics, now lets look at more of the
options we have for working with values in memory.
Lesson2.asm
Addressing Modes
Being a RISC CPU, MIPS has a very limited number of addressing modes, but
for completeness lets take a look at each now.
Immediate Addressing is probably the
simplest mode, it's just a constant numeric parameter.
A fixed number is the parameter for an operation.
Here is the result.
Register Addressing is very simple,
it's just when a register itself will be used as a source or
destination of an operation.
Here is the result.
Register Indirect with Offset Addressing
is the mode used for reading from, and writing to memory.
This Addressing mode uses the value from the address in a register,
offset by a fixed numeric value.
The offset can be positive, negative or zero... it can be omitted
altogether if zero.
Here are the results
Program Counter Relative with Offset
Addressing is used for branch commands.
While we've used a label in the source code, it will be converted to
a positive or negative offset in the final program.
Psuedo Direct Addressing is used for
Jump commands.
It's nearly an absolute address (a complete address) however the top
4 bits are taken from the program counter.
Load And Store data sizes
We looked at loading and storing 32 bit values with LW and SW before, but
there are many more options!
Also, how we load values will vary depending on if the value is
negative... A loaded decimal 8 bit value of -1 has a 32 bit hex value of
0xFFFFFFF ... in this case We'll need to fill all the 'extra 24 bits' of
the 32 bit register with the top bit 7 of the loaded byte.
LW will Load a Word - filling the full 32 bit
destination register. As the whole register is loaded This will work
for signed or unsigned values.
LHU will Load a Half word as Unsigned - the
16 bit value will be treated as unsigned and effectively can have a
value from 0 to +65535 LH will Load a Half word as signed - the 16
bit value will be treated as signed, and 'sign extended' to fill the
32 bit destination. Effectively the value can be -32768 to +32767
LBU will Load a Byte as Unsigned - the 8 bit
value will be treated as unsigned and effectively can have a value
from 0 to +255 LB will Load a Byte as signed - the 8 bit
value will be treated as signed, and 'sign extended' to fill the 32
bit destination. Effectively the value can be -128 to +127
Here are the results
SW will Store a Word - saving the
full 32 bit register.
SH will Store a Half word - saving a
16 bit value.
SB will Store a Byte - saving
an 8 bit value.
There is no need for special 'signed' and 'unsigned' commands for
saving registers, these commands will work correctly for either
signed or unsigned.
Here are the results
Unaligned Loads and Stores
Like many CPU's the MIPS CPU can only load and save 32 bit words on 32
bit 'aligned' addresses (where the bottom two bits of the address are
zero).
The same is true of 16 bit Half words, which can only be loaded from
'even' addresses (Where the bottom bit of the address is zero).
However we do have some 'special' commands which we can use to load from
unaligned addresses.
The MIPS cpu can't truly load unaligned data, not in one command,
but we do have commands to load partial data!
LWL will Load the Word from the
Left hand side from an unaligned addresses. LWR will Load the Word from the Right
hand side from an unaligned addresses.
These commands can be combined to
load a full 32 bits from an unaligned address.
These commands are a bit tricky to use, but we have some psuedo-ops
which provide macros to make them more useful
ULW will Unaligned Load a Word (32
bit signed or unsigned) ULH will Unaligned Load a Half Word
(16 bit signed) ULHU will Unaligned Load a
Half Word Unsigned (16 bit unsigned)
There is no need for unaligned byte loading commands.
Here are the results
We also have commands for storing.
SWL will Store part of a Word to the
Left side of an unaligned address SWR will Store part of a Word to
the Right side of an unaligned address
These commands don't really save what we want. but we have
psuedo-ops to make these more usable
USW will Unaligned Store a Word (32
bits) USH will Unaligned Store a Half (16
bit)
There is no need for unaligned byte, or signed/unsigned versions of
save commands.
Here are the results
The Stack
The Stack pointer uses register SP (Register 29) to point to the
top of the stack...
We actually have no 'proper' Stack commands!... to 'push'
an item onto the stack, we subtract 4 from SP - then load the
register we want to push to the SP address
To 'pop' an item off the stack we do the
reverse - loading the register from the address in SP - and then add
4 to the SP register.
We can define these as macros to make our lives easier.
Here we've loaded a value into A0...
pushed it onto the stack, loaded a different
value onto the stack and then performed a call...
We also use the stack to backup the Return
address when we call the subroutine
Finally we pop the old value off the stack.
We dump the state of the system at each stage
The changes to the stack can be seen here...
Each push to the stack can be seen in memory.
Lesson
3 - Conditions, Branches and Sets
There will be many times when we need to do things based on certain
'conditions', and it's branches which allow us to do this! In fact
we can use branches just like JAL
We can also set registers based on certain conditions... Lets take a
look!
Lesson3.asm
Comparisons
Unlike other CPU's the MIPS does not have a flag register as such... when
we want to do a conditional branch, we use a branch command with two
registers to compare, and a label to jump to if the condition is true...
Lets look at all the options!...
The examples
shown here are all available for download!... there are various
possible values and conditions remmed out with # -
You should try enabling different conditions, and providing
different input values and see how things change!
Equals - Not Equals - EQ / NE
if we want to perform actions if the two registers are the same -
or different - we can do this with BEQ and BNE
BEQ will Branch if Equal BNE will Branch if Not Equal
The results can be seen here
Less - Greater - Unsigned - LTU / LEU / GEU / GTU
Because Hexadecimal signed numbers have their top bit as 1 we have
to use different compare commands for signed and unsigned numbers...
there is a U at the end of unsigned comparisons.
We have 4 options:
BLTU - Branch if Less Than Unsigned BGTU - Branch if Greater Than Unsigned BLEU - Branch if Less Than or Equals Unsigned BGEU - Branch if Greater Than or Equals
Unsigned
The results are shown here
Less - Greater - Signed- LT / LE / GE / GT
If we're working with Signed numbers, we have alternate versions -
these do not have U at the end
We have 4 options:
BLT - Branch if Less Than signed BGT - Branch if Greater Than signed BLE - Branch if Less Than or Equals signed BGE - Branch if Greater Than or Equals signed
The results are shown here
Comparing with Zero
Many off the MIPS functions compare to zero, and there aremany
functions to do this.
Here is the result
Here are the full set of possible Conditions:
Some even perform a 'Link', setting the RA register to the return
address!
Bcc
Description
Condition
BEQ
rs,rt,offset
Branch on Equals
rs = rt
BGEZ
rs,offset
Branch on Greater or Equal to
Zero
rs >= 0
BGEZAL rs,offset
Branch on Greater or Equal to
Zero And Link
rs >= 0
BGTZ rs,offset
Branch on Greater Than Zero
rs > 0
BLEZ rs,offset
Branch on Less than or Equal to
Zero
rs <= 0
BLTZ rs,offset
Branch on Less Than Zero
rs < 0
BLTZAL rs,offset
Branch on Less Than Zero And Link
rs < 0
BNE rs,rt,offset
Branch on Not Equal
rs <> rt
There are many other conditions which are performed via psuedo operations
Bcc
Description
Condition
BGE
rs,rt,offset
Branch on Greater than or Equals
rs >= rt
BGEU
rs,rt,offset
Branch on Greater than or Equals
(Unsigned)
rs >= rt
BGT
rs,rt,offset
Branch on Greater Than
rs > rt
BGTU
rs,rt,offset
Branch on Greater Than Unsigned
rs > rt
BLE
rs,rt,offset
Branch on Less than or Equals
rs <= rt
BLEU
rs,rt,offset
Branch on Less than or Equals
Unsigned
rs <= rt
BLT
rs,rt,offset
Branch on Less Than
rs < rt
BLTU
rs,rt,offset
Branch on Less Than Unsigned
rs <> rt
BEQZ
rs,offset
Branch on EQual to Zero
rs = 0
BNEZ
rs,offset
Branch on Not Equal to Zero
rs <> 0
Branch Always!
Jumps go to an absolute address, so are not really relocatable,
but branches are a 'relative offset' to the current position.
B will perform a Branch, which is the
relative equivalent of the J jump command.
BAL will perform a Branch and
Link, which like JAL puts the return address in the RA register.
This is actually a psuedo op using BGEZAL, so unlike JAL it is not
possible to put the return address in any other register than RA
Here are the results
Set based on conditions
We have some slightly strange commands, which will set a register to
either 1 or 0 based on a condition.
SLTU will Set the destination if src1
is Less Than src2 (both Unsigned) SGTU will Set the destination if
src1 is Greater Than src2 (both Unsigned)
SLT will Set the destination if src1
is Less Than src2 (both signed) SGT will Set the destination if src1
is Greater Than src2 (both signed)
There are a wide range of other options! - there is a table of them
below!
Here are the results.
Try changing the values of A1 and A2 for different results!
Here is the full range of SET commands.
Command
Function
SGT
dest,src1,src2
Set Greater
SGE
dest,src1,src2
Set Greater/Equal
SGEU
dest,src1,src2
Set Greater/Equal Unsigned
SGTU
dest,src1,src2
Set Greater Unsigned
SLT
dest,src1,src2
Set Less Than
SLE
dest,src1,src2
Set Less/Equal
SLEU
dest,src1,src2
Set Less/Equal Unsigned
SLTU
dest,src1,src2
Set Less Unsigned
SNE
dest,src1,src2
Set Not Equal
The purpose of these commands
may not seem immediately apparent, but these
are actually used with the Branch commands to form some of the
branch psuedo-ops.
SysCall
Syscall is a special operating system 'Trap'
On the MIPS simulator MARS it will take a parameter in $v0, and can
be used to perform various I/O tasks with the console.
Here we use SYSCALL with $v0=4 to
show the string in $a0 to the screen, and return to the operating
system (exit) with SYSCALL and
$v0=10
Here are the results
Lesson
4 - Bit ops and more maths!
We've looked at basic maths, addressing modes and branches... but
we've not covered all the maths functions of the MIPS yet...
Lets take a look at the other options
Lesson4.asm
Logical ops - AND, OR, XOR, NOR!
We have XOR, AND
and OR functions...
As always they have a Desitnation on the left, and two parameters
for the logical operation...
OR, AND and XOR have an Immediate version, where the second
parameter is a fixed number - these are ORI ANDI and XORI
The results are shown here.
NOR is a bit of a rarity! it stands
for 'Not OR' - and returns a bit of 1 if Neither parameter a OR b is
1
There is also a NOT function,
which will flip all the bits of a register. so "NOT a1" as the same
effect as "XORI a1,a1,0xFFFFFFFF" would
Here are the results
Here is a comparison of the various results of various logical operations:
A
AND
B
=
A
OR
B
=
A
XOR
B
=
A
BIC
B
=
A
NOR
B
=
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
1
0
0
1
1
0
1
1
0
1
0
0
1
0
1
0
0
1
0
1
1
0
1
1
0
1
1
0
0
1
1
1
1
1
1
1
1
0
1
1
0
1
1
0
Bit Shifts... and rotates!
The MIPS offers three kinds of bitshifts, each of
which supports a register shift amount, or an immediate one
Where the instruction ends with a V the Value will be taken from a
register (eg SLLV)
SLL is Shift Left Logical Left - all bits move
to the left - any bits pushed out the register are lost SRL is Shift Right Logical - all bits move to
the right - any bits pushed out the register are lost SRA is Shift Right Ari thematic - all bits
move to the right - any bits pushed out the register are lost - any
new bits on the left contain the previous leftmost bit - maintaining
the sign of the register.
We've performed 4 shifts of the registers.
Notice each shift to the left doubles the value, and a shift to the
right halves it - provided no bits are 'pushed out' of the
registers.
We can also perform Rotate commands. Unlike shifts, with rotation
any bits that 'leave' the register return on the other side, so with
a 1 bit shift to the left, the new bit 0 is the old bit 31, and all
other bits shift in a leftwards motion.
We have two options - they cannot work with immediates only work
with a shift amount in a register.
ROL will rotate left.
ROR will rotate right.
Here are the results
Shifting Left doubles
the value in a register, Shifting Right will halve it, and it's
faster than Multiplication and Division commands!
There is no SLA command (shift arithmetic left) because there is
no need for one.. SLL will do the job you need!
More problematic is the lack of rotation commands... ROR/ROL don't
exist!... you'll have to use AND/OR and the shift commands that do
exist to simulate them.
Lesson
5 - More Maths!
There's a few other maths commands left to look at, as well as the
MULT and DIV commands!
Lets get through the last of the commands.
Lesson5.asm
Signed Numbers
We've already done lots of work with signed and unsigned numbers,
but there's a few more commands we've not covered yet!
If we want to convert a number from positive to negative, we can
flip all the bits (NOT) and add 1... but we have a command to give
this result for us.
NEG will convert a negative number to
a positive, and a positive to a negative.
If we want t convert a number to a positive number (whatever it was)
we can use ABS.
If we use this command, whether our register contained -5 or +5, the
result would be +5
Here are the results
Finally we have NEGU, which is
almost the same as NEG. A signed 32 bit register has a range of
-0x80000000 to +0x7FFFFFFF... any value out of this range will cause
an 'overflow trap'
If we want to allow a value outside this range we can use NEGU
(NEGate Unsigned), and convert our very large positive number in the
same way without the trap.
Here are the results
Multiplication
We can perform signed multiplication with MULT
The result is NOT stored in either of the two passed parameters,
it's stored in the special HI LO registers.
Here are the results
We need to use special commands to access the HI and LO registers.
MFHI will Move From the HI register to
the specified register. MFLO will Move From the LO register
to the specified register.
MTHI will Move To the HI register
from the specified register. MTLO will Move To the HI register
from the specified register.
Here are the results
The MULT command is a signed command, but for unsigned values over
0x7FFFFFFF we will need to use MULTU
This will correctly multiply unsigned numbers
Here are the results
Division
We have two possible commands for Division.
DIV will divide parameter 1 by
parameter 2, treating both as signed numbers DIVU will do the same, treating both
as unsigned numbers
After the division, LO will contain the
quotient (The integer result of the division), HI is the remainder
Here are the results
Phew! We've covered the basics!
MIPS has extensions for 64 bit and floating point, but they are
beyond what this tutorial was intended to cover... you should at
least have enough now to get started!