Back to Miscellaneous

MIPS Architecture

I wrote these notes on July 6th, 1998 and as of March 2007 no longer have any idea what I used them for. Ricardo Nabinger Sanchez has helpfully pointed out what is almost certainly an error, in that identical subu instructions are used to allocate and free the stack frame. I do not know which one should be corrected, and how. -- John Chew <>

Memory Model

0000 0000003F FFFFReserved
0040 0000____ ____Code (.text)
____ ____0FFF FFFFShared libraries
1000 0000____ ____Read-only data (.rdata)
____ ________ ____Data (.data)
____ ____$gp Short-offset data (.sdata)
$gp ____ ____Short-offset uninitialised data (.sbss)
____ ________ ____Uninitialised data (.bss)
____ ________ ____Heap (expanded by sbrk and break)
____ ____$sp Protected
$sp 7FFF EFFFStack
7FFF F0007FFF FFFFNot accessible
8000 0000FFFF FFFFKernel


See also /usr/include/regdefs.h.

Integer Registers

Register NameSoftware NameDescription
$0Always set to zero
$atAssembler temporary register
$2, $3v0, v1Expression evaluation, integer function results, static link for nested procedure calls
$4..$7a0..a3First four volatile int arguments
$8..$15t0..t7Not preserved across procedure calls
$16..$23s0..s7Preserved across procedure calls
$24, $25t8, t9Not preserved across procedure calls
$kt0, $kt1k0, k1Kernel use only
$28 or $gpgpGlobal pointer
$29 or $spspStack pointer
$30 or $fpfpFrame pointer (if used)
$31raReturn address


Calling a Procedure

The first four integer arguments must be placed in registers $4 through $7 and the first two floating point arguments must be placed in registers f12 and f14.

Return values go in $2 and $f0.

To call a procedure, use the jal instruction.

                jal     procedure_name

Writing a Procedure

Start all procedures with a .ent directive and entry label.

                .ent     procedure_name
If your procedure requires stack storage, either because it calls other procedures, or because it needs to put local variables on the stack, allocate the required storage. You should not modify the stack pointer again, except to restore it on return.

                subu     $sp, framesize
Regardless of whether or not you use stack storage, include the following pseudo-op. It tells the debugger how big your stack frame is.

                .frame   framereg, framesize, returnreg
Framereg is usually $sp, returnreg is usually $31.

If you need to save integer registers, e.g. $16, $17 and $31, do so as follows.

                .mask    bitmask, frameoffset
                sw       $31, framesize+frameoffset-0($sp)
                sw       $17, framesize+frameoffset-4($sp)
                sw       $16, framesize+frameoffset-8($sp)
If you need to save floating point registers, use s.s or s.d instead of sw, and .fmask instead of .mask. Allow four bytes for singles, eight bytes for doubles.

Include your procedure body (if any) here.

To restore registers, use lw, l.s and l.d.

                lw       $16, framesize+frameoffset-8($sp)
                lw       $17, framesize+frameoffset-4($sp)
                lw       $31, framesize+frameoffset-0($sp)
Remove the stack frame.

                subu     $sp, framesize

                j        $31
End the procedure definition.

                .end     procedure_name