MIPSym User's Guide




Using the MIPSym Simulator




Files

MIPSym is designed to open text files with a .asm or .s extension.

MIPSym can also open MIPSym-assembler generated object files with a .obj extension, using the 'File > Load .obj' command. This is a MIPSym-specific text file format, designed to be human-readable in a text editor; no hex editors required.

Please note that the 'Load .obj' command assumes that you have a .asm file with the same filename in the same directory; it will load this file in the code editor.

As soon as you begin making changes to a source file that you have saved, MIPSym begins making timed backup saves of your code. You can set the amount of time between automatic backups, in seconds, with 'Settings > Set Automatic Backup Interval'. By default, the interval is 5 minutes, but you can set it as low as 1 second. You can turn the feature off by setting it to 0 seconds. Auto-saves are typically saved as the original filename with a tilde and a unique number after it. These files are usually cleaned up when MIPSym exits normally.

MIPSym does not crash often, but if it does, it will make an attempt to open the last file it auto-saved the next time you run it.




Find and Replace

You can access Find and Replace feature with Ctrl-F. This feature is meant to work much the same as it does in other text editors.

Regular expression matching: MIPSym allows you to find and replace using Qt's regular expression engine, QRegExp. You can find documentation on QRegExp at doc.qt.io.

Regular expression capture groups: Regular expression engines allow you to reference capture groups in your replacement strings, often using $1, $2, $3 and so on. Using QRegExp's string replacement tools, you will need to use \1, \2, \3 and so on.

For example, if you had text that looked like this:

    Apples: add     $t0,$t1,$t2

... and you had a search string that looked like this:

    (\w+):\s+add\s+(\$\w+),(\$\w+),(\$\w+)

... and you had a replacement string that looked like this:

    # At label \1, we add \4 to \3 and store the result in \2.

... you could find that string, hit 'Replace', and end up with this string:

    # At label Apples, we add $t2 to $t1 and store the result in $t0.



Code editor shortcut keys

Most of the shortcut keys you might need are written in the menus, right next to the actions they trigger. For instance, under the 'File' menu, the 'Save' action has the text Ctrl-S next to it, or -S on Mac.

There are a few keyboard shortcuts that are not on the menu; these are listed here:

Shortcut KeysMac EquivalentAction
Ctrl-/-/ Toggle-comment the line that the cursor is on.
If multiple lines are selected, every line selected will toggle-comment.
TabTab If any text is selected, the entire line (or block of lines) is indented with Tab characters.
Shift-TabShift-Tab If any text is selected, the entire line (or block of lines) is unindented.
Ctrl-MouseWheel+/--MouseWheel+/- Increase/decrease the size of the text in the IDE or the console.



Panels

The main window of the MIPSym IDE is divided into four panels:

  • The Source Code Panel
  • The Register Panel
  • The Message Log Panel
  • The Memory Panel

By default, only the Source Code panel is visible when you start up MIPSym. You can change this behavior under 'Settings > On Startup Show'.

By default, the Message Log panel will show itself whenever it receives a new message. You can prevent this behavior with 'Settings > Auto Show Messages on Arrival'. The Message Log is used to provide feedback any time MIPSym has something useful to tell you, but doesn't want to use an obtrusive dialog box to do so. It is usually best to leave this setting turned on, unless you are really worried about screen space. If you turn it off, the Message Log will still record messages, and you can access them at any time.

The Register and Memory panels can be accessed at any time, either by using the 'View' menu, or by pulling on the vertical panel sliders at the right edge of the window. The panel sliders look like thick black lines, and your mouse cursor will change shape as you hover over them. If the Message Log is hidden, you can also access the Message Log using the horizontal panel slider at the bottom of the window.




Building Code

To build a program, click 'Run > Build F8'. The assembler should run, and the assembly results should show up in the Listing tab of the source code panel.

Your copy of MIPSym may contain alternate assemblers in a directory marked asm; if you wish to use one of them instead of the default assembler, you can do so with 'Settings > Set Assembler Path'.

Every time the assembler runs, the Message Log will display a note that contains the path to the assembler used and the version number. Considerable effort has been put into fuzz-testing assembler version 3.1; the developers believe that it is very unlikely that this assembler will crash. If the assembler does crash, the Message Log will contain a note with the assembler's return value, and possibly an explanation of what happened. If you are able to get assembler version 3.1 to crash, please alert the developers!




Running Code

You can step through your program one instruction at a time using the 'Run > Step F10' command.

You can run the program with 'Run > RunF9'; this will run your program until you hit a breakpoint, if any are set, or the program ends, or an exception occurs. This command will also save and build your program if you have unsaved changes.

You can pause the program at any time with 'Run > Step F10'. This will be useful if your program uses spin locks or long/infinite loops; your PC will otherwise waste lots of CPU cycles and battery to emulate these.

You will not be able to run your program if you did not define a .text or .code section, or did not specify a global main: label, even if it assembled correctly.

If you run a program, and it finishes, either via exception, syscall $exit, or by running off the end of the .code section, the simulator's PC and registers will all be in the same state so that you can examine them. If you want to re-run your program, hit 'Run > Reset Shift-F8' first, otherwise your program may begin in the wrong state.




Breakpoints

To set breakpoints, go to the listing section, highlight a memory address in the .code/.text section, and click 'Breakpoint > Add Ctrl-B'. This will pause your program at that address the next time you run it.

You can also add and remove breakpoints without highlighting memory addresses; you will see a dialog box that allows you to set the addresses manually.




Privacy

By default, MIPSym looks for updates at MIPSym.com every time it starts up. The Windows installation is capable of updating itself when MIPSym starts up, if you consent to the download (typically 11 MB). The Linux version should be capable of this soon as well.

However, the MIPSym team values your privacy and desire not to be tracked. You can turn off this feature in one of two ways:

  1. The 'Settings > Check for new version on launch' menu item. This item is checked by default, but you can un-check it the first time it runs, and MIPSym will stop contacting MIPSym.com in the future. This means that the first time MIPSym runs, it will contact MIPSym.com. If your preferences file is corrupted or deleted for some reason, it will also contact MIPSym.com until you uncheck this box.
  2. The -p or --private command line option. If you launch MIPSym from the command line, or use a shortcut, you can add this option to your launch command, and MIPSym will never access MIPSym.com for any reason.



Using the MIPSymCLI Simulator




Windows

After installation, there will be two shortcuts in your Start Menu, under a folder labelled MIPSym2. The MIPSym shortcut will run the GUI version of MIPSym; the MIPSymCLI shortcut will launch a Windows terminal with an environment set up to make it easier to run MIPSym from the command line.

This Windows terminal will start you out in your "home" directory. This is meant to encourage you not to try to modify files in the C:\Program Files (x86) directory. If you prefer to start in some other directory, please modify C:\Program Files (x86)\MIPSym2\MipsymCliEnv.bat accordingly.

If MIPSym is installed in the default location, there will be some example MIPS assembly files at C:\Program Files (x86)\MIPSym2\example_code. You may wish to copy these files to your home directory, using the xcopy command:

xcopy "C:\Program Files (x86)\MIPSym2\example_code" MIPS_workspace\

The xcopy command will copy the whole directory into your home directory, in a new directory called MIPS_workspace.

You can move into the MIPS_workspace directory with the cd command:

cd MIPS_workspace

Use the dir command to print a list of all the files in the current directory.

Assembling Programs

Within this terminal, you can assemble a MIPS program in the current directory called hello_world.asm by entering:

%ASM% hello_world.asm

If the assembler runs properly, it should produce an object file, in the same directory as the assembly file, with the .obj extension in place of the .asm extension.

You can check the assembler's return code with this command:

echo %errorlevel%

The assembler referenced by %ASM% returns 0 when assembly succeeded and 1 when assembly failed. Any other return code means the assembler crashed.

Considerable effort has been put into fuzz-testing the assembler at %ASM%; the developers believe that it is very unlikely that this assembler will crash. If you are able to get this assembler (version 3.1, not 3.0) to crash, please alert the developers!

The assembler should have produced a few files when it assembled hello_world.asm:

  1. A log file, hello_world.log. This file stores some basic data about what assembler was used to assemble the program and what arguments were passed to the assembler. After you run the program in MIPSymCLI, some runtime statistics will be appended to this file.
  2. An object file, hello_world.obj. This file represents the machine code that corresponds to the program you assembled. It isn't an actual machine code binary; it is instead stored as ASCII text so that you can read it easily.
  3. A listing file, hello_world.lst. This file shows a direct mapping between the lines of assembly code in the hello_world.asm and the machine code written to hello_world.obj. It is meant to help you figure out what the assembler produced, and why.

You can print any of these files to the terminal, using the type command:

type hello_world.lst

If you prefer, you can also open the files in Notepad.exe:

notepad hello_world.lst

There are two assemblers available in C:\Program Files (x86)\MIPSym2\asm. One is available via the %ASM% environment variable; this is the recommended assembler.

You may decide that you prefer to use the older version of the assembler, C:\Program Files (x86)\MIPSym2\asm\assembler_builder.exe. If you want to use this one, please note that you will need to use the -W flag, and that every assembly source file must be preceded by a \, otherwise the assembler will crash. For example, if you want to assemble hello_world.asm in the working directory, you would need to use this command:

"C:\Program Files (x86)\MIPSym2\asm\assembler_builder.exe" -W .\hello_world.asm

Also, you should know that assembler_builder.exe produces a hello_world.sig file that contains no more than a few bytes. This file is used as a secondary form of communication with the GUI version of MIPSym, and it won't be very interesting to you. It is safe to delete this file. The newer assembler.exe produces .sig files as well, but the %ASM% variable includes a command line flag to suppress these files so that you will not see them.

Running Programs

Within this terminal, you can run a MIPS program in the current directory called hello_world.obj by typing:

MIPSymCLI hello_world.obj

A complete list of the command line flags that MIPSymCLI supports is available by typing:

MIPSymCLI -h

If you need to quit running a program, but you don't want exit the terminal, just press Ctrl-C to return to the command prompt.




Linux

The "MIPSym_x.xx.xxxx.tar.gz" archive includes the file "MIPSymCLI-x86_64.AppImage". This is an AppImage that you may relocate to any directory you wish. You will also find an assembler called "MIPSymAssembler" in the "asm" directory; please keep it in the same directory as "Mips1.adf". You may find it simplest to do something like this:

$ tar -xvzf MIPSym_x.xx.xxxx.tar.gz -C ~

This will extract the archive into your home directory, in a new directory called MIPSym_x.xx.xxxx.

If you expect to use MIPSymCLI for any length of time, you will probably want to add some aliases to your dotfiles to make MIPSymCLI easier to use. The developers recommend that you add these lines to your ~/.bashrc file (or ~/.zshrc, or ~/.config/fish file, depending on your preferred shell):

alias assembler='/home/$USER/MIPSym_x.xx.xxxx/asm/MIPSymAssembler -s'
alias MIPSymCLI='/home/$USER/MIPSym_x.xx.xxxx/MIPSymCLI-x86_64.AppImage'

The next time you open a terminal, you will be able to type assembler to run MIPSymAssembler with the -s flag, or MIPSymCLI to run the command-line version of MIPSym. For instance, if you had the file hello_world.asm in the working directory, you could run it like this:

$ assembler hello_world.asm && MIPSymCLI hello_world.obj

If there are any errors in hello_world.asm, assembler emits a nonzero return code that prevents MIPSymCLI from running.

To make this process automatic, you may wish to interact with MIPSymCLI using a file watcher like inotify-wait. This tool can be used to cause the assembler and MIPSymCLI emulator to run again any time you save changes to the hello_world.asm source.




Mac

The MIPSym.app file in your /Applications directory is actually a directory that includes many files, including an assembler and the MIPSymCLI application. You can access these programs from your terminal by adding the following lines to your ~/.bashrc file (or ~/.zshrc, or ~/.config/fish file, depending on your preferred shell):

alias assembler='/Applications/MIPSym.app/Contents/MacOS/asm/assembler -s'
alias MIPSymCLI='/Applications/MIPSym.app/Contents/MacOS/MIPSymCLI'

When you launch a new terminal session, you will be able to use the commands assembler and MIPSymCLI from any location, as long as MIPSym.app is in your /Applications directory. For instance, if you had the file hello_world.asm in the working directory, you could run it like this:

$ assembler hello_world.asm && MIPSymCLI hello_world.obj

If there are any errors in hello_world.asm, assembler emits a nonzero return code that prevents MIPSymCLI from running.




Debugging Programs in MIPSymCLI

You can put MIPSymCLI in interactive debug mode with this command:

MIPSymCLI -i hello_world.obj

In debug mode, you can type ? at any point to get a list of commands you can use, or x to exit the current mode.

When you enter debug mode, you will see a cryptic series of numbers and letters across the top of the screen. For example, you might see this:

Mem Addr  Contents Inst    Hex Args  Last Reg Diff
00400000  340a0021 ori   0a,00,0021  $ra = 004000f0 >>

The top line is meant to help you to understand the line below it. There are five columns of data here, followed by a >> symbol. The >> symbol is a prompt, meaning that MIPSymCLI expects you to type something.

The five columns of data are:

  1. The memory address that the Program Counter is currently pointed to. The .text section of MIPS programs usually begins at 0x400000, and that's where most MIPS programs start. If you wrote a MIPS program with a main label at some other location, and used the .globl main instruction to export that symbol, you would see some other memory address in this column. Note that all the numbers in this display are printed in hexadecimal; they are more compact and easier to read this way.
  2. The 32-bit integer stored at this memory address. Since we are in the .text section, this integer is most likely machine code for a MIPS instruction. The MIPSym simulator will interpret this number as if it were a MIPS instruction. Hopefully, the author of this program kept all the program's data in the .data section, and out of the .text section, so the MIPSym simulator doesn't try to interpret data as MIPS instructions!
  3. The assembly instruction that MIPSym will try to run when it sees the 32-bit integer at this address.
  4. The arguments to the MIPS instruction at this address, written in hexadecimal.
  5. The integer register that changed during the previous instruction. If no register has changed, this column will point to $ra by default. This column also shows you the value held in that register.

You can step through the program one instruction at a time by pressing the i or F10 key.

At any point, you can set or clear breakpoints, view the contents of the registers, or view and edit the contents of memory. Press ? to see a complete list of commands.

The Memory Viewer/Editor

From debug mode, you can enter the memory editor by pressing m. In this mode, the prompt turns into a >>> to denote that you are in the memory editor, and not in debug mode. From this point, you can press x to get back to debug mode.

In the memory editor, you can press d to display and edit memory. Once you have pressed d, you will see something like this:

0x10010000: 20202020 >

The first number is the hex address of the current location in memory, 0x10010000, which happens to be the beginning of the .data section. The second number is the value at that address: a series of 0x20's. In this program, the beginning of the data section is filled by a string of ASCII space characters. The last thing on this line is the data-entry prompt, a > symbol.

If you were to enter a 32-bit number here, the first four bytes at address 0x10010000 would be replaced by the number you entered.

If you were to press the up or down arrow keys, the memory address would increment/decrement by 4, and the value at the new address would be displayed in place of the previous value.

If you entered nothing at all, and just pressed the Enter key, the next memory address and memory value would appear on the next line. This is a good way to view a large block of memory at once: just press Enter over and over again, and the whole block will print out four bytes at a time.

Press x to leave data-entry mode and go back to the memory editor. Note that the prompt changes back to a >>>.

There are three things you can change in the memory editor:

  1. The current memory address (press a to modify). It could take a long time to press the arrow keys to reach the address you want to display or modify; this will get you there directly.
  2. Size mode (press s to modify). If you are modifying integers, you can choose between modifying 1 byte, 2 bytes, 4 bytes, or 8 bytes at a time.
  3. Entry mode (press e to modify). This allows you to change the way that data is displayed and entered in data-entry mode. You can use this to display blocks of memory as floating-point data, string data, integers, or as disassembled MIPS machine code.

You can press ? at any time in the memory editor to see what address, size mode, and entry mode are currently selected.




Differences between MIPSym's assembler and other MIPS assemblers (SPIM, GCC etc)




Delay slot

The MIPS R2000 processor executes every instruction placed directly after a branch instruction before it executes the branch. This is called the delay slot. By default, the MIPSym simulator disables this behavior. The delay slot behavior may be restored by using the .delay pseudocode at the top of any program. Programs written for SPIM must be modified by adding this pseudocode before all other lines:

    .delay

The following blocks of code illustrate how the delay slot can alter the behavior of your programs.

# Default behavior: the '.delay' pseudocode is absent
    li      $a0,5           # put a 5 in $a0
    jal     some_function   # jump to some_function, with argument $a0 == 5
    addi    $a0,$a0,8       # when some_function returns, set $a0 = 5 + 8


# Delay slot mode: the '.delay' pseudocode appeared at the top of the program
    li      $a0,5           # put a 5 in $a0
    jal     some_function   # jump to some_function, with argument $a0 == 13
    addi    $a0,$a0,8       # delay slot: this instruction runs before some_function

Please do not attempt to use a macro in the delay slot: the first line of the macro will be executed before a branch, but subsequent instructions will not!




Fields

The MIPSym assembler reads each line of assembly code as a series of three fields, separated by whitespace:

  1. the label field
  2. the opcode/pseudo-op field
  3. the arguments field

This has two very important consequences that are common pain points for new users of MIPSym:

  1. Lines of code without a label must be indented

    # Valid code:
        add     $t0,$t0,$t0
    # Not valid:
    add     $t0,$t0,$t0
    
  2. Whitespace is not allowed between arguments or within mathematical expressions.

    # Not valid:
        add     $t0, $t0, $t0
    # Valid code:
        addi    $t0,$t0,1+2+3      # adds 6 to $t0
    # Valid, but not what you meant:
        addi    $t0,$t0,1 + 2 + 3  # adds 1 to $t0, not 6
    



Expressions

Mathematical expressions are evaluated from left to right, with no regard to operator precedence. Parentheses are not allowed.

# Valid code:
    addi  $t0,$0,1+2*3     # stores (1+2)*3, or 9, in $t0
# Not valid:
    addi  $t0,$0,1+(2*3)   # does not assemble

Note that the MIPSym assembler evaluates each value in an expression as an integer, not as floating point data.

# Valid code:
    addi  $t0,$0,3.9+3.9   # stores 3+3, or 6, in $t0



Aliasing and Constant Values

Like SPIM, you can use the assignment operator to assign a constant value to an identifier. This feature is meant to allow you to write readable code that isn't full of magic numbers. For example:

# Valid code:
num_days_in_year = 365
num_days_in_leap_year = num_days_in_year+1
    li    $t0,num_days_in_leap_year    # store 366 in register $t0

Don't forget to use whitespace before and after the = operator:

x=7     # fail; the `=` is interpreted as part of a label
x =7    # fail; the `=7` is interpreted as an undefined opcode
x= 7    # fail; the `x=` is interpreted as part of a label
x = 7   # OK: `7` is now assigned to `x`

This feature is often used with labels as well:

# Valid code:
my_string:  .asciiz   "I am the best programmer in my seat!"
end_my_string:

# assigns the length of the string, plus 1 for the null terminal
my_string_length = end_my_string-my_string

You may also assign identifiers to registers, as long as your identifier begins with a '$':

first_year_of_MIPS = 1986
$year = $t0
    li    $year,first_year_of_MIPS    # load 1986 into $t0

The value attached to the identifier is assigned during assembly, and cannot be reassigned during runtime.

The MIPSym assembler stores these values as integers. If you attempt to assign a floating point value to an identifier, the value will be truncated.




Repeating Data

The MIPSym assembler provides a means of repeating sections of data, using the ':' operator.

Suppose you wanted to write a null-terminated string, consisting of 5 copies of the letter 'A'. You could (and probably should) use the .asciiz pseudocode, but let's see what happens when we use the .byte pseudocode.

five_As:    .byte   65:5      # write 5 'A's
            .byte   0         # null-terminal

The result is a printable string that looks like: "AAAAA\0"

Please note that the MIPSym assembler will repeat all of the data on the line, not just the value that precedes the ':' operator. If you didn't know that, you might be tempted to tack the 0 onto the end of the first line, like this:

five_A0:    .byte   65:5,0

This will not yield the same string; instead, it will result in 5 alternating A's and 0's, like this: "A\0A\0A\0A\0"




Character literals

MIPSym does not currently support unicode. It interprets all ASCII characters as being on IBM code page 437. This was done to make it easy for students to develop text-mode games, using the box-drawing characters in the range 0xb0 to 0xdf. All characters on this code page have a uniform width and height, which makes ASCII art simple to draw. This property is not true of some unicode characters, no matter what font you're using. Each character is exactly 8 bytes, which makes it easy to reason about the positioning of each character in a buffer, as opposed to the variable-length characters in utf-8.

You may represent character literals in code, preceded by a single quote:

    li      $a0,'A      # load 65, the ASCII value for 'A', in register $a0
    li      $a0,'\n     # load 10, the ASCII value for newline, in $a0
    li      $a0,'\'     # load 39, the value for single quote, in $a0
    li      $a0,'\\     # load 92, the value for backslash, in $a0

You may find it useful to run the program 'page2ASCII.asm', included in the 'examples' directory. This program prints every character that MIPSym is capable of printing, alongside the corresponding ASCII values.

The following escape codes are supported by the assembler:

Escape codeASCII valueName
\a7Bell
\b8Backspace
\t9Horizontal Tab
\n10Newline
\v11Vertical tab
\f12Form feed
\r13Carriage return
\xFF255Hex number: any number between 0 and 255
\255255Decimal number: any number between 0 and 255
\o377255Octal number: any number between 0 and 255
\B11111111255Binary number: any number between 0 and 255

If you need to print '⌂' in a string or character literal, you can use the escaped hex value:

    .data
    .ascii  "\x7F"
    .byte   '\x7F
    .text
    li      $a0,'\x7F

Please note that you cannot include raw control characters (ASCII values 0-31 and 127) in string literals or character literals. The assembler will convert these characters to blank space characters, aka ASCII 0x20. Indiscriminate use of these characters can have unpredictable effects, depending on which platform you are using. For example, on Windows, the character 0x1a, aka the 'substitute' character, causes a file IO error when a file is read in text mode. This is not a bug; it is a misuse of the text file format.

If you plan on using text editors other than MIPSym to edit assembly files, please only use characters within the range [32-126] inclusive. Most modern editors expect that text files are encoded in some form of Unicode, and characters outside this range will either cause IO errors or be interpreted as malformed UTF-8 text.

If you absolutely must use UTF-8 text in your programs, you are encouraged to use escape sequences to form UTF-8 characters. For example, to write the UTF-8 form of the character '⌂', you would need to write this sequence of bytes: 0xE2 0x8C 0x82 To write this as an ASCII string, you could use:

house:  .asciiz   "\xE2\x8C\x82"

or:

house:  .byte     '\xE2,'\x8C,'\x82,0

You can print this string as a UTF-8 character if you are using MIPSymCLI in ANSI Mode. To do this, pass the -a flag to MIPSymCLI at the command line:

$ MIPSymCLI -a your_utf8_program.obj



Keywords/Reserved Words

Unlike SPIM and GCC assembler, MIPSym does not consider pseudocodes, opcodes, or registers to be reserved words. This means that you may use labels with the same names as opcodes and pseudocodes. The assembler can decide whether an identifier should be interpreted as a label or an opcode/pseudocode based on which field it is in.

# Valid code (antipattern):

# define a label (addi), and store part of the address of that label in $t0
addi:   addi    $t0,$0,addi

# define a label (.data), and store the address of that label in $s0
.data:  li      $s0,.data

# define a label (.byte), and write 3 copies of the low 8 bits of that label
.byte:  .byte   .byte,.byte,.byte

WARNING: Do not write code like this without a very good reason for doing so! Redefining opcodes and pseudocodes can be fun, but it makes your code very hard to read!

If you want to copy this code into MIPSym, make sure it isn't indented before you try to build it. Notice that the code highlighter can't figure out that addi, .data, and .byte are being used as labels and not opcodes or pseudocodes. The highlighter is meant to run fast and to help make your code more readable, not to parse nonsense like this.




Syscalls, Register Names, Pseudocodes, and Macros

MIPSym aims to provide good compatibility with SPIM, but some differences exist. MIPSym adds several syscalls that do not exist in SPIM, a few nonstandard floating-point instructions, and many convenient macros that do not exist in SPIM or GCC. Specific differences are discussed in the appropriate section of the Quick Reference Guide.




Quick Reference Guide

This section presents a listing of all pseudocodes (assembler directives), syscalls, registers, opcodes, and macros. Please note that all the information presented here is available within MIPSym's code editor, in the form of tooltips. Within the editor, just hover your mouse over a term that you are interested in, and the documentation for that term will pop up.




Pseudocodes (aka assembler directives)

MIPSym handles a subset of the pseudocodes that SPIM and the GCC assembler support. A full listing of these is provided here.

Pseudo NameArgumentsComment
.alignnIncrement the location counter to make the n low order bits of the counter 0.
If n is zero, turns off auto alignment.
.asciistring delimited by double quotesWrites a string without marking an endpoint
.asciizstring delimited by double quotesWrites a null-terminated string
.bytecomma-separated ints or expressionsWrites data in 8-bit chunks
.codeoptional addressEnters the section of the program that contains code.
Alias for '.text'
.dataoptional addressEnters the section of the program that contains data
.delayno argsTurns on branch-delay mode: the simulator will execute the first instruction following a branch instruction before taking the branch.
The assembler will use special versions of macros containing branches.
Should be the first line of a program.
.doublecomma-separated doublesWrites 64-bit floating point datapoints
.endrno argsNot implemented!
Ends the repeated section begun by .repeat.
.externname of variable, size of variableDefines a global symbol offset from the $gp, whose size is n bytes.
.externalname of variableDeclares that a symbol is externally visible so it can be referenced by other files via $gp
.floatcomma-separated floatsWrites 32-bit floating point datapoints
.globalname of variable, size of variableDefines a global symbol whose size is n bytes.
.globlname of variableDeclares that a symbol is externally visible so it can be referenced by other files via $gp
.halfcomma-separated intsWrites data in 16-bit chunks
.kcodeoptional addressEnters the section of the program that contains kernel code
.kdataoptional addressEnters the section of the program that contains data, accessible by the kernel
.ktextoptional addressEnters the section of the program that contains kernel code
.repeatnumber of repetitionsNot implemented!
Repeats all instructions or data between the .repeat and .endr directives.
.sdataoptional addressEnters the small data section;
accessible via $gp using 16-bit addressing
.spacenumber of bytesAdds n bytes of empty space
.structoptional argument: defines inheritance from another structDefines a data structure type as the label.
The value of the label is the length of the structure in bytes.
Subsequent items are included in the structure until the next segment directive or another struct.
The optional 'symbol' argument defines inheritance from another struct.
.textoptional addressEnters the section of the program that contains code.
.wordcomma-separated intsWrites data in 32-bit chunks



Syscalls

Like SPIM, MIPSym employs syscalls to handle operations that would otherwise be very tedious to write. MIPSym provides compatibility with all of SPIM's syscalls and allows you to call them the same way. MIPSym also provides its own syntax for syscalls, which is more concise and readable.

# Valid code (SPIM syntax):
    li      $v0,5     # 5 denotes the read_int syscall
    syscall           # runs the syscall in $v0
# Valid code (MIPSym syntax):
    syscall $read_int # runs the read_int syscall directly

MIPSym supports all of the syscalls that SPIM supports. A full listing of these syscalls is provided here.



SPIM-Compatible Syscalls

Syscall NameArgumentsComment
$close$a0 holds file handleCloses file
$exitno argsends program
$exit2$a0 holds return valueends program, returning the value in $a0
$malloc$a0 holds number of bytes requested.Returns address in $v0
$open$a0 holds address of filename,
$a1 holds flags,
$a2 holds mode.
Returns file handle in $v0
$print_char$a0 holds char to printprints char in $a0
$print_double$a0 holds double to printprints double in $f12
$print_float$a0 holds float to printprints float in $f12
$print_int$a0 holds int to printprints integer in $a0
$print_string$a0 holds string to printprints string in memory at $a0
$read$a0 holds file handle,
$a1 holds buffer address,
$a2 holds buffer length.
Returns number of bytes read in $v0
$read_charno argsreturns char from console input in $v0
$read_doubleno argsreturns double from console input in $f0
$read_floatno argsreturns float from console input in $f0
$read_intno argsreturns integer from console input in $v0
$read_string$a0 holds address of buffer in memory,
$a1 holds buffer length.
Returns string length in $v0
$write$a0 holds file handle,
$a1 holds buffer address,
$a2 holds buffer length.
Returns number of bytes written in $v0


MIPSym-Specific Syscalls

Syscall NameArgumentsComment
$IO_read$a0 holds address,
$a1 holds number of bytes {1,2,4}.
Returns data in $v0
$IO_write$a0 holds address,
$a1 holds number of bytes {1,2,4},
$a2 holds data to write
writes data to hardware
$callback$a0 holds address of interrupt callback routine,
$a1 holds interrupt number [2-7]
assigns callback function
$close_cons$a0 holds id of console to closeUnimplemented
$date_timeno argsReturns local datetime, spanned across $v0-$v1.
Bits from high($v1) to low($v0): 23 bits=year, 4=month, 5=day, 5=hour, 6=min, 6=sec, 10=mil, 5=local timezone offset from UTC
$flush_printno argstransfers the screen buffer to console, avoiding flicker.
$free$a0 holds address of buffer to freeFrees memory at address
$open_cons$a0 is console height,
$a1 is console width
Unimplemented
$position$a0 holds file handle,
$a1 holds number of bytes from $a2,
$a2 = start / current / end of file: 0/1/2
Returns absolute position in $v0
$randomno argsCopies the RANDOM register to $v0.
RANDOM counts down with each instruction run since the program began.
Commonly used to seed an RNG algorithm after waiting for user input.
$select_cons$a0 holds id of console to selectUnimplemented
$spool_printno argsholds outputs to screen buffer until $flush_print
$string2double$a0 holds address of input stringReturns double in $f0 converted from string in memory at $a0
$utc_date_timeno argsReturns datetime in Universal Coordinated Time, spanned across $v0-$v1.
Bits from high($v1) to low($v0): 23 bits=year, 4=month, 5=day, 5=hour, 6=min, 6=sec, 10=mil, 5=local timezone offset from UTC
$utc_millisno argsReturns the number of milliseconds since the Unix Epoch, in Universal Coordinated Time, spanned across $v0-$v1
$xy$a0 holds cursor column [0-79],
$a1 holds cursor row [0-24].
Positions Cursor on the console.
Returns character at ($a0,$a1) in $v0.



Register Names

The GCC assembler refers to registers only by their numeric values, $0-$31. By default MIPSym does not allow the use of $0-$31 as register names, unless you define the symbols $0-$31 in your own code (see aliasing) or add them to MIPSym/asm/mips1.adf. For example, in your own code you could type the following (unindented):

$31 = 31

MIPSym uses the register names enumerated below. SPIM allows the use of either type of register name. Code written for SPIM or GCC must be adjusted accordingly before the MIPSym assembler will be able to assemble it.


Integer Registers

GCC nameMIPSym namePurpose
$0$zero $0Always 0
$1$atAssembler Temporary
$2-$3$v0-$v1Function return values/ syscall choice
$4-$7$a0-$a3Function arguments
$8-$15$t0-$t7Temporary storage, not saved
$16-$23$s0-$s7Saved storage, not overwritten
$24-$25$t8-$t9Temporary storage, not saved
$26-$27$k0-$k1For kernel use only
$28$gpGlobal pointer
$29$spStack pointer
$30$fpFrame pointer
$31$raReturn address


Floating Point Registers

GCC nameMIPSym namePurpose
$0-$31$f0-$f31Floating point registers in coprocessor 1


Coprocessor 0 Control Registers

GCC NameMIPSym NameRegister Type
$0$INDEXCoprocessor 0 Control Register
$1$RANDOMCoprocessor 0 Control Register
$10$ENTRY_HICoprocessor 0 Control Register
$11$COMPARECoprocessor 0 Control Register
$12$STATUSCoprocessor 0 Control Register
$13$CAUSECoprocessor 0 Control Register
$14$EPCCoprocessor 0 Control Register
$15$PRIDCoprocessor 0 Control Register
$16$CONFIGCoprocessor 0 Control Register
$17$LLADDRCoprocessor 0 Control Register
$18$WATCH_LOCoprocessor 0 Control Register
$19$WATCH_HICoprocessor 0 Control Register
$2$ENTRY_LOCoprocessor 0 Control Register
$26$ECCCoprocessor 0 Control Register
$27$CACHE_ERRCoprocessor 0 Control Register
$28$TAG_LOCoprocessor 0 Control Register
$29$TAG_HICoprocessor 0 Control Register
$3$ENTRY_LO1Coprocessor 0 Control Register
$30$ERROR_EPCCoprocessor 0 Control Register
$4$CONTEXTCoprocessor 0 Control Register
$5$PAGEMASKCoprocessor 0 Control Register
$6$WIREDCoprocessor 0 Control Register
$7$ERRORCoprocessor 0 Control Register
$8$BAD_V_ADDRCoprocessor 0 Control Register
$9$COUNTCoprocessor 0 Control Register


Coprocessor 1 Control Registers

GCC NameMIPSym NameRegister Type
$0$FCR0Coprocessor 1 Control Register
$31$FCR31Coprocessor 1 Control Register



Opcodes and Macros




How to read these tables

These tables present each opcode or macro in the R2000 instruction set, along with its required arguments, and in most cases a brief comment to describe what the instruction does.

In general, the destination argument comes first in an argument list, and the source operand(s) come afterwards. However, five of instructions have this order backwards: mtc0, sb, sh, sw, swl, and swr. These instructions have comments marked in bold to warn you of this.

There are several kinds of arguments:

  • imm: This stands for 'immediate value'. This can be any constant integer value. It can be a number, an alias, or a mathematical expression.
  • label: This is exactly the same as an 'immediate value'. The assembler sees both as integers, and it doesn't care whether it's really a label, or just some number you made up. The distinction is meant to show you how the instructions are meant to be used, and to help other programmers to understand your code.
  • rd/rs/rt: These symbols denote integer registers. Usually, the 'd' stands for 'destination' and the 's' stands for 'source.' In the majority of the instructions (r-form instructions), the 't' stands for 'second source' (t comes right after s in the alphabet). Most of the remaining instructions (i-form instructions) use 'rt' as the destination register instead, and rd is unused.
  • fd/fs/ft: These symbols denote single floating point registers ($f0-31). The same general rule for d, s, and t that applies to the integer registers also applies here.
  • dd/ds/dt: These symbols denote double floating point registers: floating point registers with even numbers ($f0-30). The R2000 has 32-bit floating point registers, so a single 64-bit value needs to be spanned across two 32-bit registers. For example:

    # Add the value in $f2-$f3 to the value in $f4-$f5, and store it in $f0-$f1
        add.d   $f0,$f2,$f4
    # Attempt addition with misaligned registers: this is undefined behavior!
        add.d   $f6,$f8,$f9
    
  • cd/cs/ct: These symbols denote registers in Coprocessor 0, the System Control Processor.

  • Cd/Cs/Ct: These symbols denote control word registers in Coprocessor 1 ($FCR0 & $FCR31).

Comments field: The comment field usually includes some pseudocode to describe what the instruction does. This pseudocode includes some abbreviations that may not be clear at first:

  • RF[Rs]: The 'RF' stands for 'Register File', and the Rs denotes the source register. This notation makes more sense if you think of all 32 integer registers as an array of integers. If the source register is $t0 ($t0 is the 8th register), then Rf[Rs] evaluates to the value in register $t0.
  • FpRf[fs]: The 'FpRf' stands for 'Floating Point Register File,' and the 'fs' denotes the source register.
  • un(): This stands for the 'unordered' function. In this context, it means 'check to see if this value is NaN.' See Wikipedia NaN

Memory offsets: Several instructions have the last argument in parentheses. For example, the instruction 'lb' takes the arguments 'rt,imm(rs)'. The comment includes the pseudocode 'RF[Rt] = Mem[RF[Rs] + Offset]'. 'Mem' stands for MIPSym's simulated memory. It is expected that Rs is an integer register that holds a pointer to a particular location in memory. 'Offset' is the 'imm' in the second argument: here, it is used as an offset from the pointer in Rs. So, the 'lb' instruction finds the memory that Rs points to, looks 'imm' bytes away from that address, and copies the byte at that location into Rt.

Note that any instruction that takes the arguments 'rt,imm(rs)' will also take the arguments 'rt,(rs)'. The assembler will interpret the offset as 0 in this case.




Integer Instruction Set

Most of these instructions are standard on the R2000/R3000. A few of these are from later processors; these are marked as 'Unimplemented.'

Opcode NameArgumentsCommentForm
addrd,rs,rtAdd
RF[Rd] = RF[Rs] + RF[Rt]
r
addrt,rs,immAdd
alias for addi rt,rs,imm
RF[Rt] = RF[Rs] + Imm
i
addirt,rs,immAdd Immediate
RF[Rt] = RF[Rs] + Imm
i
addiurt,rs,immAdd Immediate Unsigned
RF[Rt] = RF[Rs] + Imm
i
addurd,rs,rtAdd Unsigned
RF[Rd] = RF[Rs] + RF[Rt]
r
addurt,rs,immAdd Unsigned
alias for addiu rt,rs,imm
RF[Rt] = RF[Rs] + imm
i
andrd,rs,rtBitwise And
RF[Rd] = RF[Rs] & RF[Rt]
r
andirt,rs,immBitwise And Immediate
RF[Rt] = RF[Rs] & Imm
i
blabelBranch
alias for bgez $0,label
PC = label
i
bc0flabelBranch Coprocessor0 True
This is a do nothing. It used to test a pin on the part.
i
bc0tlabelBranch Coprocessor0 False
This is a do nothing. It used to test a pin on the part.
i
beqrs,rt,labelBranch Equal
If (RF[Rs] == RF[Rt] )then PC = PC + Imm<< 2
i
beqzrs,labelBranch Equal to Zero
alias for beq rs,$0,label
If (RF[Rs] == 0) then PC = PC + Imm<< 2
i
bgezrs,labelBranch Greater than or Equal to Zero
If (RF[Rs] >= RF[0]) then PC = PC + Imm<< 2
i
bgezalrs,labelBranch Greater than or Equal to Zero And Link
If ( RF[Rs] >= RF[0] ) then {RF[$ra] = PC; PC = PC + Imm<< 2 }
i
bgtzrs,labelBranch Greater Than Zero
If (RF[Rs] > RF[0] ) then PC = PC + Imm<< 2
i
blezrs,labelBranch Less than or Equal to Zero
If (RF[Rs] <= RF[0]) then PC = PC + Imm<< 2
i
bltzrs,labelBranch Less Than Zero
If RF[Rs] < RF[0] then PC = PC + Imm<< 2
i
bltzalrs,labelBranch Less Than Zero And Link
If ( RF[Rs] < RF[0] ) then {RF[$ra] = PC; PC = PC + Imm<< 2 }
i
bners,rt,labelBranch Not Equal
If RF[Rs] != RF[Rt] then PC = PC + Imm<< 2
i
bnezrs,labelBranch Not Equal to Zero
alias for bne rs,$0,label
If RF[Rs] != 0 then PC = PC + Imm<< 2
i
breakicodepause executionb
breakrcodepause executionb
breakpause execution
alias for break 0
b
divrs,rtDivide (signed)
Low = Quotient ( RF[Rs] / RF[Rt] );
High = Remainder ( RF[Rs] / RF[Rt] )
r
divurs,rtDivide Unsigned
Low = Quotient ( RF[Rs] / RF[Rt] );
High = Remainder ( RF[Rs] / RF[Rt] )
r
jlabelJump
PC = PC(31:28) | Imm<< 2
j
jallabelJump And Link
RF[$ra] = PC;
PC = PC(31:28) | Imm<< 2
j
jalrrd,rsJump And Link Register
RF[Rd] = PC;
PC = RF[Rs]
r
jalrrsJump And Link Register
alias for jalr $ra,rs
$ra = PC;
PC = RF[Rs]
r
jrrsJump Register
PC = RF[Rs]
r
lbrt,imm(rs)Load Byte
RF[Rt] = Mem[RF[Rs] + Offset]
i
lburt,imm(rs)Load Byte Unsigned
RF[Rt] = Mem[RF[Rs] + Offset]
i
lhrt,imm(rs)Load Half
RF[Rt] = Mem[RF[Rs] + Offset]
i
lhurt,imm(rs)Load Half Unsigned
RF[Rt] = Mem[RF[Rs] + Offset]
i
llrt,imm(rs)Load Linked
Unimplemented
i
luirt,immLoad Upper Immediate
RF[Rt] = Imm<<16
i
lwrt,imm(rs)Load Word
RF[Rt] = Mem[RF[Rs] + Offset]
i
lwlrt,imm(rs)Load Word Left
RF[Rt] = Mem[RF[Rs] + Offset]
i
lwrrt,imm(rs)Load Word Right
RF[Rt] = Mem[RF[Rs] + Offset]
i
mfc0rt,cdMove From Coprocessor0:
Rf[rt] = CP0Rf[cd]
r
mfhirdMove From Hi
RF[Rd] = HIGH
r
mflordMove From Low
RF[Rd] = LOW
r
movrd,rsMove
alias for addu rd,rs,$0
RF[Rd] = RF[Rs]
r
moverd,rsMove
alias for addu rd,rs,$0
RF[Rd] = RF[Rs]
r
mtc0rt,cdMove To Coprocessor0:
CP0Rf[cd] = Rf[rt]
Backwards Arguments!
r
mthirsMove To Hi
HIGH = RF[Rs]
r
mtlorsMove To Low
LOW = RF[Rs]
r
multrs,rtMultiply (signed)
High |Low = RF[Rs] * RF[Rt]
r
multurs,rtMultiply Unsigned
High |Low = RF[Rs] * RF[Rt]
r
negrd,rtNegate
alias for sub rd,$0,rt
RF[Rd] = -RF[Rt]
r
negurd,rtNegate
alias for subu rd,$0,rt
RF[Rd] = -RF[Rt]
r
nopno operation
alias for sll $0,$0,0
r
norrd,rs,rtBitwise Nor
RF[Rd] = !(RF[Rs] | RF[Rt])
r
notrd,rsBoolean Not
alias for nor rd,rs,$0
RF[Rd] = !(RF[Rs] | 0)
r
orrd,rs,rtBitwise Or
RF[Rd] = RF[Rs] | RF[Rt]
r
orirt,rs,immBitwise Or Immediate
RF[Rt] = RF[Rs] | Imm
i
rfeRestore From Exception
restores the status register to its value before the last exception occurred.
r
sbrt,imm(rs)Store Byte:
Mem[RF[Rs] + Offset] = RF[Rt]
Backwards Arguments!
i
sgtrd,rt,rsSet Greater Than
alias for slt rd,rs,rt
if (RF[Rt] > RF[Rs] ) then RF[Rd] =1 else RF[Rd] = 0
r
sgturd,rt,rsSet Greater Than Unsigned
alias for sltu rd,rs,rt
if (RF[Rt] > RF[Rs] ) then RF[Rd] =1 else RF[Rd] = 0
r
shrt,imm(rs)Store Half:
Mem[RF[Rs] + Offset] = RF[Rt]
Backwards Arguments!
i
sllrd,rt,nShift Left Logical (immediate)
RF[Rd] = RF[Rt] << n
r
sllrd,rt,rsShift Left Logical
alias for sllv rd,rt,rs
RF[Rd] = RF[Rt] << RF[Rs] amount
r
sllvrd,rt,rsShift Left Logical Variable
RF[Rd] = RF[Rt] << RF[Rs] amount
r
sltrd,rs,rtSet Less Than
if (RF[Rs] < RF[Rt] ) then RF[Rd] =1 else RF[Rd] = 0
r
sltirt,rs,immSet Less Than Immediate
if (RF[Rs] < Imm) then RF[Rt] = 1 else RF[Rt] = 0
i
sltiurt,rs,immSet Less Than Immediate Unsigned
if (RF[Rs] < Imm) then RF[Rt] = 1 else RF[Rt] = 0
i
slturd,rs,rtSet Less Than Unsigned
if (RF[Rs] < RF[Rt] ) then RF[Rd] =1 else RF[Rd] = 0
r
srard,rt,nShift Right Arithmetic (immediate)
RF[Rd] = RF[Rt] >> n (sign-extend)
r
srard,rt,rsShift Right Arithmetic
alias for srav rd,rt,rs
RF[Rd] = RF[Rt] >> RF[Rs] amount (sign-extend)
r
sravrd,rt,rsShift Right Arithmetic Variable
RF[Rd] = RF[Rt] >> RF[Rs] amount (sign-extend)
r
srlrd,rt,nShift Right Logical
RF[Rd] = RF[Rt] >> n (no sign extension)
r
srlrd,rt,rsShift Right Logical
alias for srlv rd,rt,rs
RF[Rd] = RF[Rt] >> RF[Rs] amount (no sign extension)
r
srlvrd,rt,rsShift Right Logical Variable
RF[Rd] = RF[Rt] >> RF[Rs] amount (no sign extension)
r
subrd,rs,rtSubtract
RF[Rd] = RF[Rs] - RF[Rt]
r
suburd,rs,rtSubtract Unsigned
RF[Rd] = RF[Rs] - RF[Rt]
r
swrt,imm(rs)Store Word:
Mem[RF[Rs] + Offset] = RF[Rt]
Backwards Arguments!
i
swlrt,imm(rs)Store Word Left (1-4 bytes, depending on offset):
Mem[RF[Rs] + Offset] = RF[Rt]
Backwards Arguments!
i
swrrt,imm(rs)Store Word Right (1-4 bytes, depending on offset):
Mem[RF[Rs] + Offset] = RF[Rt]
Backwards Arguments!
i
syscallcall syscall in $v0b
syscallscodecall syscall in argumentb
syscallrcodecall syscall in registerb
tlbpProbe TLB For Matching Entry
Unimplemented
r
tlbrRead Indexed TLB Entry
Unimplemented
r
tlbwiWrite Indexed TLB Entry
Unimplemented
r
tlbwrWrite Random TLB Entry
Unimplemented
r
xorrd,rs,rtBitwise Xor
RF[Rd] = RF[Rs] ^ RF[Rt]
r
xorirt,rs,immBitwise Xor Immediate
RF[Rt] = RF[Rs] ^ Imm
i



Floating-Point Instruction Set

Most of these instructions are standard on the R2000/R3000. A few of these are from later processors; these are marked as 'Unimplemented.'

Opcode NameArgumentsCommentForm
abs.ddd,dsAbsolute value double:
FpRf[dd] = |FpRf[ds]|
r
abs.sfd,fsAbsolute value single:
FpRf[fd] = |FpRf[fs]|
r
add.ddd,ds,dtAdd double:
FpRf[dd] = FpRf[ds] + FpRf[dt]
r
add.sfd,fs,ftAdd single:
FpRf[fd] = FpRf[fs] + FpRf[ft]
r
bc1flabelbranch if status flag is falsei
bc1tlabelbranch if status flag is truei
c.eq.dds,dtCompare Equal Doubles:
ControlRf[31].condition_bit = FpRf[dt] == FpRf[ds] && !(un(FpRf[dt]) || un(FpRf[ds]))
r
c.eq.sfs,ftCompare Equal Singles:
ControlRf[31].condition_bit = FpRf[ft] == FpRf[fs] && !(un(FpRf[ft]) || un(FpRf[fs]))
r
c.f.dds,dtCompare False:
ControlRf[31].condition_bit = 0
r
c.f.sfs,ftCompare False:
ControlRf[31].condition_bit = 0
r
c.le.dds,dtCompare Less Than or Equal:
exception if unordered;
ControlRf[31].condition_bit = FpRf[ds] <= FpRf[dt] && !(un(FpRf[ft]) || un(FpRf[fs]))
r
c.le.sfs,ftCompare Less Than or Equal:
exception if unordered;
ControlRf[31].condition_bit = FpRf[fs] <= FpRf[ft] && !(un(FpRf[ft]) || un(FpRf[fs]))
r
c.lt.dds,dtCompare Less Than:
exception if unordered;
ControlRf[31].condition_bit = FpRf[ds] < FpRf[dt] && !(un(FpRf[dt]) || un(FpRf[ds]))
r
c.lt.sfs,ftCompare Less Than:
exception if unordered;
ControlRf[31].condition_bit = FpRf[fs] < FpRf[ft] && !(un(FpRf[ft]) || un(FpRf[fs]))
r
c.nge.dds,dtCompare Not Greater or Equal, or unordered:
exception if unordered;
ControlRf[31].condition_bit = FpRf[ds] < FpRf[dt] || (un(FpRf[ds]) || un(FpRf[dt]))
r
c.nge.sfs,ftCompare Not Greater or Equal, or unordered:
exception if unordered;
ControlRf[31].condition_bit = FpRf[fs] < FpRf[ft] || (un(FpRf[fs]) || un(FpRf[ft]))
r
c.ngl.dds,dtCompare Not Greater or Less Than, or unordered:
exception if unordered;
ControlRf[31].condition_bit = FpRf[ds] == FpRf[dt] || (un(FpRf[ds]) || un(FpRf[dt]))
r
c.ngl.sfs,ftCompare Not Greater or Less Than, or unordered:
exception if unordered;
ControlRf[31].condition_bit = FpRf[fs] == FpRf[ft] || (un(FpRf[fs]) || un(FpRf[ft]))
r
c.ngle.dds,dtCompare Not Greater, Less, or Equal (only true if unordered):
exception if unordered;
ControlRf[31].condition_bit = (un(FpRf[dt]) || un(FpRf[ds]))
r
c.ngle.sfs,ftCompare Not Greater, Less, or Equal (only true if unordered):
exception if unordered;
ControlRf[31].condition_bit = (un(FpRf[ft]) || un(FpRf[fs]))
r
c.ngt.dds,dtCompare Not Greater Than, or unordered:
exception if unordered;
ControlRf[31].condition_bit = FpRf[ds] <= FpRf[dt] || (un(FpRf[fs]) || un(FpRf[ft]))
r
c.ngt.sfs,ftCompare Not Greater Than, or unordered:
exception if unordered;
ControlRf[31].condition_bit = FpRf[fs] <= FpRf[ft] || (un(FpRf[fs]) || un(FpRf[ft]))
r
c.ole.dds,dtCompare Ordered Less Than Or Equal:
ControlRf[31].condition_bit = FpRf[ds] <= FpRf[dt] && !(un(FpRf[dt]) || un(FpRf[ds]))
r
c.ole.sfs,ftCompare Ordered Less Than Or Equal:
ControlRf[31].condition_bit = FpRf[fs] <= FpRf[ft] && !(un(FpRf[ft]) || un(FpRf[fs]))
r
c.olt.dds,dtCompare Ordered Less Than:
ControlRf[31].condition_bit = FpRf[ds] < FpRf[dt] && !(un(FpRf[dt]) || un(FpRf[ds]))
r
c.olt.sfs,ftCompare Ordered Less Than:
ControlRf[31].condition_bit = FpRf[fs] < FpRf[ft] && !(un(FpRf[ft]) || un(FpRf[fs]))
r
c.seq.dds,dtCompare Signaling Equal:
exception if unordered;
ControlRf[31].condition_bit = FpRf[ds] == FpRf[dt] && !(un(FpRf[dt]) || un(FpRf[ds]))
r
c.seq.sfs,ftCompare Signaling Equal:
exception if unordered;
ControlRf[31].condition_bit = FpRf[fs] == FpRf[ft] && !(un(FpRf[ft]) || un(FpRf[fs]))
r
c.sf.dds,dtCompare Signaling False:
exception if unordered;
ControlRf[31].condition_bit = 0
r
c.sf.sfs,ftCompare Signaling False:
exception if unordered;
ControlRf[31].condition_bit = 0
r
c.ueq.dds,dtCompare Unordered/Equal Doubles:
ControlRf[31].condition_bit = (FpRf[dt] == FpRf[ds]) || (un(FpRf[dt]) || un(FpRf[ds]))
r
c.ueq.sfs,ftCompare Unordered/Equal Singles:
ControlRf[31].condition_bit = (FpRf[ft] == FpRf[fs]) || (un(FpRf[ft]) || un(FpRf[fs]))
r
c.ule.dds,dtCompare Unordered Less Than Or Equal:
ControlRf[31].condition_bit = FpRf[ds] <= FpRf[dt] || (un(FpRf[dt]) || un(FpRf[ds]))
r
c.ule.sfs,ftCompare Unordered Less Than Or Equal:
ControlRf[31].condition_bit = FpRf[fs] <= FpRf[ft] || (un(FpRf[ft]) || un(FpRf[fs]))
r
c.ult.dds,dtCompare Unordered Less Than:
ControlRf[31].condition_bit = FpRf[ds] < FpRf[dt] || (un(FpRf[dt]) || un(FpRf[ds]))
r
c.ult.sfs,ftCompare Unordered Less Than:
ControlRf[31].condition_bit = FpRf[fs] < FpRf[ft] || (un(FpRf[ft]) || un(FpRf[fs]))
r
c.un.dds,dtCompare Unordered Doubles:
ControlRf[31].condition_bit = un(FpRf[dt]) || un(FpRf[ds])
r
c.un.sfs,ftCompare Unordered Singles:
ControlRf[31].condition_bit = un(FpRf[ft]) || un(FpRf[fs])
r
cfc1rt,Csmove control word from cop1:
Rf[rt] = ControlRf[Cs]
r
ctc1rt,Csmove control word to cop1:
ControlRf[Cs] = Rf[rt]
r
cvt.d.sdd,fsConvert single to double:
FpRf[dd] = (double) FpRf[fs]
r
cvt.d.wdd,fsConvert integer to double:
FpRf[dd] = (double) FpRf[fs]
r
cvt.s.dfd,dsConvert double to single:
FpRf[fd] = (float) FpRf[ds]
r
cvt.s.wfd,fsConvert integer to single:
FpRf[fd] = (float) FpRf[fs]
r
cvt.w.dfd,dsConvert double to integer:
FpRf[fd] = (int) FpRf[ds]
r
cvt.w.sfd,fsConvert single to integer:
FpRf[fd] = (int) FpRf[fs]
r
div.ddd,ds,dtDivide double:
FpRf[dd] = FpRf[ds] / FpRf[dt]
r
div.sfd,fs,ftDivide single:
FpRf[fd] = FpRf[fs] / FpRf[ft]
r
l.sft,imm(rs)load word to cop1:
FpRf[ft] = Mem[Rf[rs] + Offset]
i
lwc1ft,imm(rs)load word to cop1:
FpRf[ft] = Mem[Rf[rs] + Offset]
i
lwc2rt,imm(rs)load word to cop2:
Unimplemented
i
lwc3rt,imm(rs)load word to cop3:
Unimplemented
i
mfc1rt,fsmove from cop1:
Rf[rt] = FpRf[fs]
r
mov.ddd,dsCopy double value:
FpRf[dd] = FpRf[ds]
r
mov.sfd,fsCopy single value:
FpRf[fd] = FpRf[fs]
r
mtc1rt,fsmove to cop1:
FpRf[fs] = Rf[rt]
r
mul.ddd,ds,dtMultiply double:
FpRf[dd] = FpRf[ds] * FpRf[dt]
r
mul.sfd,fs,ftMultiply single:
FpRf[fd] = FpRf[fs] * FpRf[ft]
r
neg.ddd,dsNegate double value:
FpRf[dd] = -FpRf[ds]
r
neg.sfd,fsNegate single value:
FpRf[fd] = -FpRf[fs]
r
s.sft,imm(rs)store word from cop1:
Mem[Rf[rs] + Offset] = FpRf[ft]
i
scrt,imm(rs)Unimplementedi
sub.ddd,ds,dtSubtract double:
FpRf[dd] = FpRf[ds] - FpRf[dt]
r
sub.sfd,fs,ftSubtract single:
FpRf[fd] = FpRf[fs] - FpRf[ft]
r
swc1ft,imm(rs)store word from cop1:
Mem[Rf[rs] + Offset] = FpRf[ft]
i
swc2rt,imm(rs)store word from cop2:
Mem[Rf[rs] + Offset] = Unimplemented
i
swc3rt,imm(rs)store word from cop3:
Mem[Rf[rs] + Offset] = Unimplemented
i



Floating-Point Math Opcodes, MIPSym-Specific

These are nonstandard opcodes for various mathematic functions. They are not native to the R2000/R3000, but they may be useful for your programs. Some of these opcodes are standard in later versions of MIPS.

Opcode NameArgumentsCommentForm
acos.ddd,dsarc cosine double:
FpRf[dd] = acos(FpRf[ds])
r
acos.sfd,fsarc cosine single:
FpRf[fd] = acos(FpRf[fs])
r
acosh.ddd,dsarc hyperbolic cosine double:
FpRf[dd] = acosh(FpRf[ds])
r
acosh.sfd,fsarc hyperbolic cosine single:
FpRf[fd] = acosh(FpRf[fs])
r
asin.ddd,dsarc sine double:
FpRf[dd] = asin(FpRf[ds])
r
asin.sfd,fsarc sine single:
FpRf[fd] = asin(FpRf[fs])
r
asinh.ddd,dsarc hyperbolic sine double:
FpRf[dd] = asinh(FpRf[ds])
r
asinh.sfd,fsarc hyperbolic sine single:
FpRf[fd] = asinh(FpRf[fs])
r
atan.ddd,dsarc tangent double:
FpRf[dd] = atan(FpRf[ds])
r
atan.sfd,fsarc tangent single:
FpRf[fd] = atan(FpRf[fs])
r
atan2.ddd,ds,dtarc tangent of y,x double:
FpRf[dd] = atan2(FpRf[ds],FpRf[dt])
r
atan2.sfd,fs,ftarc tangent of y,x single:
FpRf[fd] = atan2(FpRf[fs],FpRf[ft])
r
atanh.ddd,dsarc hyperbolic tangent double:
FpRf[dd] = atanh(FpRf[ds])
r
atanh.sfd,fsarc hyperbolic tangent single:
FpRf[fd] = atanh(FpRf[fs])
r
ceil.ddd,dsceiling double:
FpRf[dd] = ceil(FpRf[ds])
r
ceil.sfd,fsceiling single:
FpRf[fd] = ceil(FpRf[fs])
r
cos.ddd,dscosine double:
FpRf[dd] = cos(FpRf[ds])
r
cos.sfd,fscosine single:
FpRf[fd] = cos(FpRf[fs])
r
cosh.ddd,dshyperbolic cosine double:
FpRf[dd] = cosh(FpRf[ds])
r
cosh.sfd,fshyperbolic cosine single:
FpRf[fd] = cosh(FpRf[fs])
r
exp.ddd,dse to the x power double:
FpRf[dd] = exp(FpRf[ds])
r
exp.sfd,fse to the x power single:
FpRf[fd] = exp(FpRf[fs])
r
floor.ddd,dsfloor double:
FpRf[dd] = floor(FpRf[ds])
r
floor.sfd,fsfloor single:
FpRf[fd] = floor(FpRf[fs])
r
ln.ddd,dsnatural log double:
FpRf[dd] = ln(FpRf[ds])
r
ln.sfd,fsnatural log single:
FpRf[fd] = ln(FpRf[fs])
r
round.ddd,dsround double:
FpRf[dd] = round(FpRf[ds])
r
round.sfd,fsround single:
FpRf[fd] = round(FpRf[fs])
r
sin.ddd,dssine double:
FpRf[dd] = sin(FpRf[ds])
r
sin.sfd,fssine single:
FpRf[fd] = sin(FpRf[fs])
r
sinh.ddd,dshyperbolic sine double:
FpRf[dd] = sinh(FpRf[ds])
r
sinh.sfd,fshyperbolic sine single:
FpRf[fd] = sinh(FpRf[fs])
r
sqrt.ddd,dssquare root double:
FpRf[dd] = sqrt(FpRf[ds])
r
sqrt.sfd,fssquare root single:
FpRf[fd] = sqrt(FpRf[fs])
r
tan.ddd,dstangent double:
FpRf[dd] = tan(FpRf[ds])
r
tan.sfd,fstangent single:
FpRf[fd] = tan(FpRf[fs])
r
tanh.ddd,dshyperbolic tangent double:
FpRf[dd] = tanh(FpRf[ds])
r
tanh.sfd,fshyperbolic tangent single:
FpRf[fd] = tanh(FpRf[fs])
r
trunc.ddd,dstruncate double:
FpRf[dd] = trunc(FpRf[ds])
r
trunc.sfd,fstruncate single:
FpRf[fd] = trunc(FpRf[fs])
r



Macros

In addition to the original instructions implemented in the R2000, MIPSym also supports the use of several macros to make the process of writing assembly code easier.

Unlike SPIM, macros cannot be defined in program code. Supported macros are defined in the file MIPSym/asm/Mips1.adf.

Macro NameArgumentsComment
absrd,rsAbsolute Value
Rf[rd] = abs(Rf[rs])
Note that if Rf[rs] == 0x80000000, an arithmetic overflow will occur, because 'positive 0x80000000' cannot be represented as a 32-bit signed integer.
Use `absu` to prevent this.

Delay Slot OffDelay Slot On
  addu  rd,$0,rs
  bgez  rs,09f
  sub   rd,$0,rs
09:
  bgez  rs,09f
  addu  rd,$0,rs
  sub   rd,$0,rs
09:
absurd,rsAbsolute Value Unsigned
Rf[rd] = abs(Rf[rs])
Stores an unsigned 32-bit integer in Rf[rd].
Note that this can store 'positive 0x80000000' in Rf[rd], which is negative when interpreted as a signed integer.
Use `abs` to prevent this.

Delay Slot OffDelay Slot On
  addu  rd,$0,rs
  bgez  rs,09f
  subu  rd,$0,rs
09:
  bgez  rs,09f
  addu  rd,$0,rs
  subu  rd,$0,rs
09:
addirt,immAdd immediate:
Rf[rt] = Rf[rt] + imm

  addi  rt,rt,imm
addiurt,immAdd immediate unsigned:
Rf[rt] = Rf[rt] + imm

  addiu rt,rt,imm
andirt,immAnd immediate:
Rf[rt] = Rf[rt] & imm

  andi  rt,rt,imm
beqrs,imm,labelBranch equal to
If (RF[Rs] == Imm) then branch to Label

  li    $at,imm
  beq   rs,$at,label
bgers,rt,labelBranch greater than or equal to
If (RF[Rs] >= Rf[Rt]) then branch to Label

  slt   $at,rs,rt
  beq   $at,$0,label
bgers,imm,labelBranch greater than or equal to
If (RF[Rs] >= Imm) then branch to Label

  li    $at,imm
  slt   $at,rs,$at
  beq   $at,$0,label
bgeurs,rt,labelBranch greater than or equal to (Unsigned)
If (RF[Rs] >= Rf[Rt]) then branch to Label

  sltu  $at,rs,rt
  beq   $at,$0,label
bgeurs,imm,labelBranch greater than or equal to (Unsigned)
If (RF[Rs] >= Imm) then branch to Label

  li    $at,imm
  sltu  $at,rs,$at
  beq   $at,$0,label
bgtrs,rt,labelBranch greater than
If (RF[Rs] > Rf[Rt]) then branch to Label

  slt   $at,rt,rs
  bne   $at,$0,label
bgtrs,imm,labelBranch greater than
If (RF[Rs] > Imm) then branch to Label

  li    $at,imm
  slt   $at,$at,rs
  bne   $at,$0,label
bgturs,rt,labelBranch greater than (Unsigned)
If (RF[Rs] > Rf[Rt]) then branch to Label

  sltu  $at,rt,rs
  bne   $at,$0,label
bgturs,imm,labelBranch greater than (Unsigned)
If (RF[Rs] > Imm) then branch to Label

  li    $at,imm
  sltu  $at,$at,rs
  bne   $at,$0,label
blers,rt,labelBranch less than or equal to
If (RF[Rs] <= Rf[Rt]) then branch to Label

  slt   $at,rt,rs
  beq   $at,$0,label
blers,imm,labelBranch less than or equal to
If (RF[Rs] <= Imm) then branch to Label

  li    $at,imm
  slt   $at,$at,rs
  beq   $at,$0,label
bleurs,rt,labelBranch less than or equal to (Unsigned)
If (RF[Rs] <= Rf[Rt]) then branch to Label

  sltu  $at,rt,rs
  beq   $at,$0,label
bleurs,imm,labelBranch less than or equal to (Unsigned)
If (RF[Rs] <= Imm) then branch to Label

  li    $at,imm
  sltu  $at,$at,rs
  beq   $at,$0,label
bltrs,rt,labelBranch less than
If (RF[Rs] < Rf[Rt]) then branch to Label

  slt   $at,rs,rt
  bne   $at,$0,label
bltrs,imm,labelBranch less than
If (RF[Rs] < Imm) then branch to Label

  li    $at,imm
  slt   $at,rs,$at
  bne   $at,$0,label
blturs,rt,labelBranch less than (Unsigned)
If (RF[Rs] < Rf[Rt]) then branch to Label

  sltu  $at,rs,rt
  bne   $at,$0,label
blturs,imm,labelBranch less than (Unsigned)
If (RF[Rs] < Imm) then branch to Label

  li    $at,imm
  sltu  $at,rs,$at
  bne   $at,$0,label
bners,imm,labelBranch not equal
If (RF[Rs] != Imm) then branch to Label

  li    $at,imm
  bne   rs,$at,label
divrd,rs,rtDivide:
Rf[rd] = Rf[rs]/Rf[rt]
(break on divide by zero)

Delay Slot OffDelay Slot On
  bne   rt,$0,08f
  break
08:
  div   rs,rt
  mflo  rd
  bne   rt,$0,08f
  nop
  break
08:
  div   rs,rt
  mflo  rd
divrd,rs,nDivide:
Rf[rd] = Rf[rs]/n

  li    $at,n
  div   rs,$at
  mflo  rd
divrd,nDivide:
Rf[rd] = Rf[rd]/n

  li    $at,n
  div   rd,$at
  mflo  rd
divurd,rs,rtDivide unsigned:
Rf[rd] = Rf[rs] / Rf[rt]
(break on divide by zero)

Delay Slot OffDelay Slot On
  bne   rt,$0,08f
  break
08:
  divu  rs,rt
  mflo  rd
  bne   rt,$0,08f
  nop
  break
08:
  divu  rs,rt
  mflo  rd
divurd,rs,nDivide unsigned:
Rf[rd] = Rf[rs] / n

  li    $at,n
  divu  rs,$at
  mflo  rd
divurd,nDivide unsigned:
Rf[rd] = Rf[rd] / n

  li    $at,n
  divu  rd,$at
  mflo  rd
l.ddd,laddressLoad double:
FpRf[dd] = laddress

  lui   $at,laddress&0x8000<<1+laddress>>16
  lwc1  dd,laddress&0xFFFF($at)
  lwc1  dd+1,laddress&0xFFFF+4($at)
l.ddd,imm(rs)Load double:
FpRf[dd] = Mem[RF[Rs] + Offset]

  lwc1  dd,imm(rs)
  lwc1  dd+1,imm+4(rs)
l.sfd,laddressLoad single:
FpRf[fd] = laddress

  lui   $at,laddress&0x8000<<1+laddress>>16
  lwc1  fd,laddress&0xFFFF($at)
lard,laddressLoad Address into Rf[rd]

  lui   rd,laddress>>16
  ori   rd,rd,laddress&0xffff
lbrd,laddressLoad byte (low 8 bits):
Rf[rd] = Mem[laddress]

  lui   $at,laddress&0x8000<<1+laddress>>16
  lb    rd,laddress&0xFFFF($at)
lburd,laddressLoad byte unsigned (low 8 bits):
Rf[rd] = Mem[laddress]

  lui   $at,laddress&0x8000<<1+laddress>>16
  lbu   rd,laddress&0xFFFF($at)
lhrd,laddressLoad half (low 16 bits):
Rf[rd] = Mem[laddress]

  lui   $at,laddress&0x8000<<1+laddress>>16
  lh    rd,laddress&0xFFFF($at)
lhurd,laddressLoad half unsigned (low 16 bits):
Rf[rd] = Mem[laddress]

  lui   $at,laddress&0x8000<<1+laddress>>16
  lhu   rd,laddress&0xFFFF($at)
lird,immLoad Immediate into Rf[rd] variable size, no forward reference.
This macro is used when the high 16 bits of imm are empty.

ori   rd,$0,imm
lird,immLoad Immediate into Rf[rd] variable size, no forward reference.
This macro is used when the low 16 bits of imm are empty.

lui   rd,imm
lird,immLoad Immediate into Rf[rd] variable size, no forward reference.
This macro is used when the high 17 bits of imm are 1 (it's a small negative number).

addi   rd,$0,imm
lird,immLoad Immediate into Rf[rd] variable size, no forward reference.
This macro is used when none of the three other forms can be used.

lui   rd,imm
ori   rd,$0,imm
lwrd,laddressLoad word (full 32 bits):
Rf[rd] = Mem[laddress]

  lui   $at,laddress&0x8000<<1+laddress>>16
  lw    rd,laddress&0xFFFF($at)
mulrd,rs,rtMultiply:
Rf[rd] = Rf[rs] * Rf[rt]

  mult  rs,rt
  mflo  rd
mulrd,rs,nMultiply:
Rf[rd] = Rf[rs]*n

  li    $at,n
  mult  rs,$at
  mflo  rd
mulrd,nMultiply:
Rf[rd] = Rf[rd]*n

  li    $at,n
  mult  rd,$at
  mflo  rd
mulord,rs,rtMultiply, break on overflow

Delay Slot OffDelay Slot On
  mult  rs,rt
  mfhi  $at
  mflo  rd
  sra   rd,rd,31
  beq   $at,rd,08f
  break
08:
  mflo  rd
  mult  rs,rt
  mfhi  $at
  mflo  rd
  sra   rd,rd,31
  beq   $at,rd,08f
  mflo  rd
  break
08:
mulourd,rs,rtMultiply unsigned, break on overflow

Delay Slot OffDelay Slot On
  multu rs,rt
  mfhi  $at
  beq   $at,$0,08f
  break
08:
  mflo  rd
  multu rs,rt
  mfhi  $at
  beq   $at,$0,08f
  mflo  rd
  break
08:
mulurd,rs,rtMultiply unsigned:
Rf[rd] = Rf[rs] * Rf[rt]

  multu rs,rt
  mflo  rd
mulurd,rs,nMultiply unsigned:
Rf[rd] = Rf[rs] * n

  li    $at,n
  multu rs,$at
  mflo  rd
mulurd,nMultiply unsigned:
Rf[rd] = Rf[rd] * n

  li    $at,n
  multu rd,$at
  mflo  rd
orirt,immOr immediate:
Rf[rt] = Rf[rt] | imm

  ori   rt,rt,imm
remrd,rs,rtRemainder:
Rf[rd] = Rf[rs] % Rf[rt]

Delay Slot OffDelay Slot On
  bne   rt,$0,08f
  break
08:
  div   rs,rt
  mfhi  rd
  bne   rt,$0,08f
  nop
  break
08:
  div   rs,rt
  mfhi  rd
remrd,rs,nRemainder:
Rf[rd] = Rf[rs] % n

  li    $at,n
  div   rs,$at
  mfhi  rd
remrd,nRemainder:
Rf[rd] = Rf[rd] % n

  li    $at,n
  div   rd,$at
  mfhi  rd
remurd,rs,rtRemainder unsigned:
Rf[rd] = Rf[rs] % Rf[rt]

Delay Slot OffDelay Slot On
  bne   rt,$0,08f
  break
08:
  divu  rs,rt
  mfhi  rd
  bne   rt,$0,08f
  nop
  break
08:
  divu  rs,rt
  mfhi  rd
remurd,rs,nRemainder unsigned:
Rf[rd] = Rf[rs] % n

  li    $at,n
  divu  rs,$at
  mfhi  rd
remurd,nRemainder unsigned:
Rf[rd] = Rf[rd] % n

  li    $at,n
  divu  rd,$at
  mfhi  rd
rolrd,rt,rsRotate left

  subu  $at,$0,rs
  srlv  $at,rt,$at
  sllv  rd,rt,rs
  or    rd,rd,$at
rolrd,rt,nRotate left

  srl   $at,rt,-n
  sll   rd,rt,n
  or    rd,rd,$at
rorrd,rt,rsRotate right

  subu  $at,$0,rs
  sllv  $at,rt,$at
  srlv  rd,rt,rs
  or    rd,rd,$at
rorrd,rt,nRotate right

  sll   $at,rt,-n
  srl   rd,rt,n
  or    rd,rd,$at
s.ddd,laddressStore double:
Mem[laddress] = FpRf[dd]

  lui   $at,laddress&0x8000<<1+laddress>>16
  swc1  dd,laddress&0xFFFF($at)
  swc1  dd+1,laddress&0xFFFF+4($at)
s.ddd,imm(rs)Store double:
Mem[RF[Rs] + Offset] = FpRf[dd]

  swc1  dd,imm(rs)
  swc1  dd+1,imm+4(rs)
s.sfd,laddressStore single:
Mem[laddress] = FpRf[fd]

  lui   $at,laddress&0x8000<<1+laddress>>16
  swc1  fd,laddress&0xFFFF($at)
sbrd,laddressStore byte (low 8 bits):
Mem[laddress] = Rf[rd]

  lui   $at,laddress&0x8000<<1+laddress>>16
  sb    rd,laddress&0xFFFF($at)
seqrd,rs,rtSet if equal:
Rf[rd] = Rf[rs] == Rf[rt]

  subu  $at,rs,rt
  sltiu rd,$at,1
sgerd,rs,rtSet greater than:
Rf[rd] = Rf[rs] > Rf[rt]

  slt   rd,rs,rt
  slti  rd,rd,1
sgeurd,rs,rtSet greater than unsigned:
Rf[rd] = Rf[rs] > Rf[rt]

  sltu  rd,rs,rt
  slti  rd,rd,1
shrd,laddressStore half (low 16 bits):
Mem[laddress] = Rf[rd]

  lui   $at,laddress&0x8000<<1+laddress>>16
  sh    rd,laddress&0xFFFF($at)
slerd,rs,rtSet less than or equal:
Rf[rd] = Rf[rs] <= Rf[rt]

  slt   rd,rt,rs
  slti  rd,rd,1
sleurd,rs,rtSet less than or equal unsigned:
Rf[rd] = Rf[rs] <= Rf[rt]

  sltu  rd,rt,rs
  slti  rd,rd,1
snerd,rs,rtSet if not equal:
Rf[rd] = Rf[rs] != Rf[rt]

  subu  $at,rs,rt
  sltu  rd,$0,$at
subrt,rs,immSubtract:
Rf[rt] = Rf[rs] - imm

  addi  rt,rs,-imm
subrt,immSubtract:
Rf[rt] = Rf[rt] - imm

  addi  rt,rt,-imm
suburt,immSubtract unsigned:
Rf[rt] = Rf[rt] - imm

  addiu rt,rt,-imm
suburt,rs,immSubtract unsigned:
Rf[rt] = Rf[rs] - imm

  addiu rt,rs,-imm
swrd,laddressStore word (full 32 bits):
Mem[laddress] = Rf[rd]

  lui   $at,laddress&0x8000<<1+laddress>>16
  sw    rd,laddress&0xFFFF($at)
ulhrt,imm(rs)

  lb    rt,imm+1(rs)
  lbu   $at,imm(rs)
  sll   rt,rt,8
  or    rt,rt,$at
ulhurt,imm(rs)

  lbu   rt,imm+1(rs)
  lbu   $at,imm(rs)
  sll   rt,rt,8
  or    rt,rt,$at
ulwrt,imm(rs)

  lwl   rt,imm+3(rs)
  lwr   rt,imm(rs)
ushrt,imm(rs)

  sb    rt,imm(rs)
  srl   $at,rt,8
  sb    $at,imm+1(rs)
uswrt,imm(rs)

  swl   rt,imm+3(rs)
  swr   rt,imm(rs)
xorirt,immXor immediate:
Rf[rt] = Rf[rt] ^ imm

  xori  rt,rt,imm



Full Listing of All Opcodes and Macros

For your convenience, all of the opcodes and macros are repeated here, alphabetized. Many of the opcodes have overloaded macro definitions, which will be invoked based on the arguments you provide. This view is intended to help you to see what those overloads are.

Opcode/Macro NameArgumentsCommentForm
absrd,rsAbsolute Value
Rf[rd] = abs(Rf[rs])
Note that if Rf[rs] == 0x80000000, an arithmetic overflow will occur, because 'positive 0x80000000' cannot be represented as a 32-bit signed integer.
Use `absu` to prevent this.

Delay Slot OffDelay Slot On
  addu  rd,$0,rs
  bgez  rs,09f
  sub   rd,$0,rs
09:
  bgez  rs,09f
  addu  rd,$0,rs
  sub   rd,$0,rs
09:
abs.ddd,dsAbsolute value double:
FpRf[dd] = |FpRf[ds]|
r
abs.sfd,fsAbsolute value single:
FpRf[fd] = |FpRf[fs]|
r
absurd,rsAbsolute Value Unsigned
Rf[rd] = abs(Rf[rs])
Stores an unsigned 32-bit integer in Rf[rd].
Note that this can store 'positive 0x80000000' in Rf[rd], which is negative when interpreted as a signed integer.
Use `abs` to prevent this.

Delay Slot OffDelay Slot On
  addu  rd,$0,rs
  bgez  rs,09f
  subu  rd,$0,rs
09:
  bgez  rs,09f
  addu  rd,$0,rs
  subu  rd,$0,rs
09:
acos.ddd,dsarc cosine double:
FpRf[dd] = acos(FpRf[ds])
r
acos.sfd,fsarc cosine single:
FpRf[fd] = acos(FpRf[fs])
r
acosh.ddd,dsarc hyperbolic cosine double:
FpRf[dd] = acosh(FpRf[ds])
r
acosh.sfd,fsarc hyperbolic cosine single:
FpRf[fd] = acosh(FpRf[fs])
r
addrd,rs,rtAdd
RF[Rd] = RF[Rs] + RF[Rt]
r
addrt,rs,immAdd
alias for addi rt,rs,imm
RF[Rt] = RF[Rs] + Imm
i
add.ddd,ds,dtAdd double:
FpRf[dd] = FpRf[ds] + FpRf[dt]
r
add.sfd,fs,ftAdd single:
FpRf[fd] = FpRf[fs] + FpRf[ft]
r
addirt,rs,immAdd Immediate
RF[Rt] = RF[Rs] + Imm
i
addirt,immAdd immediate:
Rf[rt] = Rf[rt] + imm

  addi  rt,rt,imm
addiurt,rs,immAdd Immediate Unsigned
RF[Rt] = RF[Rs] + Imm
i
addiurt,immAdd immediate unsigned:
Rf[rt] = Rf[rt] + imm

  addiu rt,rt,imm
addurd,rs,rtAdd Unsigned
RF[Rd] = RF[Rs] + RF[Rt]
r
addurt,rs,immAdd Unsigned
alias for addiu rt,rs,imm
RF[Rt] = RF[Rs] + imm
i
andrd,rs,rtBitwise And
RF[Rd] = RF[Rs] & RF[Rt]
r
andirt,rs,immBitwise And Immediate
RF[Rt] = RF[Rs] & Imm
i
andirt,immAnd immediate:
Rf[rt] = Rf[rt] & imm

  andi  rt,rt,imm
asin.ddd,dsarc sine double:
FpRf[dd] = asin(FpRf[ds])
r
asin.sfd,fsarc sine single:
FpRf[fd] = asin(FpRf[fs])
r
asinh.ddd,dsarc hyperbolic sine double:
FpRf[dd] = asinh(FpRf[ds])
r
asinh.sfd,fsarc hyperbolic sine single:
FpRf[fd] = asinh(FpRf[fs])
r
atan.ddd,dsarc tangent double:
FpRf[dd] = atan(FpRf[ds])
r
atan.sfd,fsarc tangent single:
FpRf[fd] = atan(FpRf[fs])
r
atan2.ddd,ds,dtarc tangent of y,x double:
FpRf[dd] = atan2(FpRf[ds],FpRf[dt])
r
atan2.sfd,fs,ftarc tangent of y,x single:
FpRf[fd] = atan2(FpRf[fs],FpRf[ft])
r
atanh.ddd,dsarc hyperbolic tangent double:
FpRf[dd] = atanh(FpRf[ds])
r
atanh.sfd,fsarc hyperbolic tangent single:
FpRf[fd] = atanh(FpRf[fs])
r
blabelBranch
alias for bgez $0,label
PC = label
i
bc0flabelBranch Coprocessor0 True
This is a do nothing. It used to test a pin on the part.
i
bc0tlabelBranch Coprocessor0 False
This is a do nothing. It used to test a pin on the part.
i
bc1flabelbranch if status flag is falsei
bc1tlabelbranch if status flag is truei
beqrs,rt,labelBranch Equal
If (RF[Rs] == RF[Rt] )then PC = PC + Imm<< 2
i
beqrs,imm,labelBranch equal to
If (RF[Rs] == Imm) then branch to Label

  li    $at,imm
  beq   rs,$at,label
beqzrs,labelBranch Equal to Zero
alias for beq rs,$0,label
If (RF[Rs] == 0) then PC = PC + Imm<< 2
i
bgers,rt,labelBranch greater than or equal to
If (RF[Rs] >= Rf[Rt]) then branch to Label

  slt   $at,rs,rt
  beq   $at,$0,label
bgers,imm,labelBranch greater than or equal to
If (RF[Rs] >= Imm) then branch to Label

  li    $at,imm
  slt   $at,rs,$at
  beq   $at,$0,label
bgeurs,rt,labelBranch greater than or equal to (Unsigned)
If (RF[Rs] >= Rf[Rt]) then branch to Label

  sltu  $at,rs,rt
  beq   $at,$0,label
bgeurs,imm,labelBranch greater than or equal to (Unsigned)
If (RF[Rs] >= Imm) then branch to Label

  li    $at,imm
  sltu  $at,rs,$at
  beq   $at,$0,label
bgezrs,labelBranch Greater than or Equal to Zero
If (RF[Rs] >= RF[0]) then PC = PC + Imm<< 2
i
bgezalrs,labelBranch Greater than or Equal to Zero And Link
If ( RF[Rs] >= RF[0] ) then {RF[$ra] = PC; PC = PC + Imm<< 2 }
i
bgtrs,rt,labelBranch greater than
If (RF[Rs] > Rf[Rt]) then branch to Label

  slt   $at,rt,rs
  bne   $at,$0,label
bgtrs,imm,labelBranch greater than
If (RF[Rs] > Imm) then branch to Label

  li    $at,imm
  slt   $at,$at,rs
  bne   $at,$0,label
bgturs,rt,labelBranch greater than (Unsigned)
If (RF[Rs] > Rf[Rt]) then branch to Label

  sltu  $at,rt,rs
  bne   $at,$0,label
bgturs,imm,labelBranch greater than (Unsigned)
If (RF[Rs] > Imm) then branch to Label

  li    $at,imm
  sltu  $at,$at,rs
  bne   $at,$0,label
bgtzrs,labelBranch Greater Than Zero
If (RF[Rs] > RF[0] ) then PC = PC + Imm<< 2
i
blers,rt,labelBranch less than or equal to
If (RF[Rs] <= Rf[Rt]) then branch to Label

  slt   $at,rt,rs
  beq   $at,$0,label
blers,imm,labelBranch less than or equal to
If (RF[Rs] <= Imm) then branch to Label

  li    $at,imm
  slt   $at,$at,rs
  beq   $at,$0,label
bleurs,rt,labelBranch less than or equal to (Unsigned)
If (RF[Rs] <= Rf[Rt]) then branch to Label

  sltu  $at,rt,rs
  beq   $at,$0,label
bleurs,imm,labelBranch less than or equal to (Unsigned)
If (RF[Rs] <= Imm) then branch to Label

  li    $at,imm
  sltu  $at,$at,rs
  beq   $at,$0,label
blezrs,labelBranch Less than or Equal to Zero
If (RF[Rs] <= RF[0]) then PC = PC + Imm<< 2
i
bltrs,rt,labelBranch less than
If (RF[Rs] < Rf[Rt]) then branch to Label

  slt   $at,rs,rt
  bne   $at,$0,label
bltrs,imm,labelBranch less than
If (RF[Rs] < Imm) then branch to Label

  li    $at,imm
  slt   $at,rs,$at
  bne   $at,$0,label
blturs,rt,labelBranch less than (Unsigned)
If (RF[Rs] < Rf[Rt]) then branch to Label

  sltu  $at,rs,rt
  bne   $at,$0,label
blturs,imm,labelBranch less than (Unsigned)
If (RF[Rs] < Imm) then branch to Label

  li    $at,imm
  sltu  $at,rs,$at
  bne   $at,$0,label
bltzrs,labelBranch Less Than Zero
If RF[Rs] < RF[0] then PC = PC + Imm<< 2
i
bltzalrs,labelBranch Less Than Zero And Link
If ( RF[Rs] < RF[0] ) then {RF[$ra] = PC; PC = PC + Imm<< 2 }
i
bners,rt,labelBranch Not Equal
If RF[Rs] != RF[Rt] then PC = PC + Imm<< 2
i
bners,imm,labelBranch not equal
If (RF[Rs] != Imm) then branch to Label

  li    $at,imm
  bne   rs,$at,label
bnezrs,labelBranch Not Equal to Zero
alias for bne rs,$0,label
If RF[Rs] != 0 then PC = PC + Imm<< 2
i
breakicodepause executionb
breakrcodepause executionb
breakpause execution
alias for break 0
b
c.eq.dds,dtCompare Equal Doubles:
ControlRf[31].condition_bit = FpRf[dt] == FpRf[ds] && !(un(FpRf[dt]) || un(FpRf[ds]))
r
c.eq.sfs,ftCompare Equal Singles:
ControlRf[31].condition_bit = FpRf[ft] == FpRf[fs] && !(un(FpRf[ft]) || un(FpRf[fs]))
r
c.f.dds,dtCompare False:
ControlRf[31].condition_bit = 0
r
c.f.sfs,ftCompare False:
ControlRf[31].condition_bit = 0
r
c.le.dds,dtCompare Less Than or Equal:
exception if unordered;
ControlRf[31].condition_bit = FpRf[ds] <= FpRf[dt] && !(un(FpRf[ft]) || un(FpRf[fs]))
r
c.le.sfs,ftCompare Less Than or Equal:
exception if unordered;
ControlRf[31].condition_bit = FpRf[fs] <= FpRf[ft] && !(un(FpRf[ft]) || un(FpRf[fs]))
r
c.lt.dds,dtCompare Less Than:
exception if unordered;
ControlRf[31].condition_bit = FpRf[ds] < FpRf[dt] && !(un(FpRf[dt]) || un(FpRf[ds]))
r
c.lt.sfs,ftCompare Less Than:
exception if unordered;
ControlRf[31].condition_bit = FpRf[fs] < FpRf[ft] && !(un(FpRf[ft]) || un(FpRf[fs]))
r
c.nge.dds,dtCompare Not Greater or Equal, or unordered:
exception if unordered;
ControlRf[31].condition_bit = FpRf[ds] < FpRf[dt] || (un(FpRf[ds]) || un(FpRf[dt]))
r
c.nge.sfs,ftCompare Not Greater or Equal, or unordered:
exception if unordered;
ControlRf[31].condition_bit = FpRf[fs] < FpRf[ft] || (un(FpRf[fs]) || un(FpRf[ft]))
r
c.ngl.dds,dtCompare Not Greater or Less Than, or unordered:
exception if unordered;
ControlRf[31].condition_bit = FpRf[ds] == FpRf[dt] || (un(FpRf[ds]) || un(FpRf[dt]))
r
c.ngl.sfs,ftCompare Not Greater or Less Than, or unordered:
exception if unordered;
ControlRf[31].condition_bit = FpRf[fs] == FpRf[ft] || (un(FpRf[fs]) || un(FpRf[ft]))
r
c.ngle.dds,dtCompare Not Greater, Less, or Equal (only true if unordered):
exception if unordered;
ControlRf[31].condition_bit = (un(FpRf[dt]) || un(FpRf[ds]))
r
c.ngle.sfs,ftCompare Not Greater, Less, or Equal (only true if unordered):
exception if unordered;
ControlRf[31].condition_bit = (un(FpRf[ft]) || un(FpRf[fs]))
r
c.ngt.dds,dtCompare Not Greater Than, or unordered:
exception if unordered;
ControlRf[31].condition_bit = FpRf[ds] <= FpRf[dt] || (un(FpRf[fs]) || un(FpRf[ft]))
r
c.ngt.sfs,ftCompare Not Greater Than, or unordered:
exception if unordered;
ControlRf[31].condition_bit = FpRf[fs] <= FpRf[ft] || (un(FpRf[fs]) || un(FpRf[ft]))
r
c.ole.dds,dtCompare Ordered Less Than Or Equal:
ControlRf[31].condition_bit = FpRf[ds] <= FpRf[dt] && !(un(FpRf[dt]) || un(FpRf[ds]))
r
c.ole.sfs,ftCompare Ordered Less Than Or Equal:
ControlRf[31].condition_bit = FpRf[fs] <= FpRf[ft] && !(un(FpRf[ft]) || un(FpRf[fs]))
r
c.olt.dds,dtCompare Ordered Less Than:
ControlRf[31].condition_bit = FpRf[ds] < FpRf[dt] && !(un(FpRf[dt]) || un(FpRf[ds]))
r
c.olt.sfs,ftCompare Ordered Less Than:
ControlRf[31].condition_bit = FpRf[fs] < FpRf[ft] && !(un(FpRf[ft]) || un(FpRf[fs]))
r
c.seq.dds,dtCompare Signaling Equal:
exception if unordered;
ControlRf[31].condition_bit = FpRf[ds] == FpRf[dt] && !(un(FpRf[dt]) || un(FpRf[ds]))
r
c.seq.sfs,ftCompare Signaling Equal:
exception if unordered;
ControlRf[31].condition_bit = FpRf[fs] == FpRf[ft] && !(un(FpRf[ft]) || un(FpRf[fs]))
r
c.sf.dds,dtCompare Signaling False:
exception if unordered;
ControlRf[31].condition_bit = 0
r
c.sf.sfs,ftCompare Signaling False:
exception if unordered;
ControlRf[31].condition_bit = 0
r
c.ueq.dds,dtCompare Unordered/Equal Doubles:
ControlRf[31].condition_bit = (FpRf[dt] == FpRf[ds]) || (un(FpRf[dt]) || un(FpRf[ds]))
r
c.ueq.sfs,ftCompare Unordered/Equal Singles:
ControlRf[31].condition_bit = (FpRf[ft] == FpRf[fs]) || (un(FpRf[ft]) || un(FpRf[fs]))
r
c.ule.dds,dtCompare Unordered Less Than Or Equal:
ControlRf[31].condition_bit = FpRf[ds] <= FpRf[dt] || (un(FpRf[dt]) || un(FpRf[ds]))
r
c.ule.sfs,ftCompare Unordered Less Than Or Equal:
ControlRf[31].condition_bit = FpRf[fs] <= FpRf[ft] || (un(FpRf[ft]) || un(FpRf[fs]))
r
c.ult.dds,dtCompare Unordered Less Than:
ControlRf[31].condition_bit = FpRf[ds] < FpRf[dt] || (un(FpRf[dt]) || un(FpRf[ds]))
r
c.ult.sfs,ftCompare Unordered Less Than:
ControlRf[31].condition_bit = FpRf[fs] < FpRf[ft] || (un(FpRf[ft]) || un(FpRf[fs]))
r
c.un.dds,dtCompare Unordered Doubles:
ControlRf[31].condition_bit = un(FpRf[dt]) || un(FpRf[ds])
r
c.un.sfs,ftCompare Unordered Singles:
ControlRf[31].condition_bit = un(FpRf[ft]) || un(FpRf[fs])
r
ceil.ddd,dsceiling double:
FpRf[dd] = ceil(FpRf[ds])
r
ceil.sfd,fsceiling single:
FpRf[fd] = ceil(FpRf[fs])
r
cfc1rt,Csmove control word from cop1:
Rf[rt] = ControlRf[Cs]
r
cos.ddd,dscosine double:
FpRf[dd] = cos(FpRf[ds])
r
cos.sfd,fscosine single:
FpRf[fd] = cos(FpRf[fs])
r
cosh.ddd,dshyperbolic cosine double:
FpRf[dd] = cosh(FpRf[ds])
r
cosh.sfd,fshyperbolic cosine single:
FpRf[fd] = cosh(FpRf[fs])
r
ctc1rt,Csmove control word to cop1:
ControlRf[Cs] = Rf[rt]
r
cvt.d.sdd,fsConvert single to double:
FpRf[dd] = (double) FpRf[fs]
r
cvt.d.wdd,fsConvert integer to double:
FpRf[dd] = (double) FpRf[fs]
r
cvt.s.dfd,dsConvert double to single:
FpRf[fd] = (float) FpRf[ds]
r
cvt.s.wfd,fsConvert integer to single:
FpRf[fd] = (float) FpRf[fs]
r
cvt.w.dfd,dsConvert double to integer:
FpRf[fd] = (int) FpRf[ds]
r
cvt.w.sfd,fsConvert single to integer:
FpRf[fd] = (int) FpRf[fs]
r
divrs,rtDivide (signed)
Low = Quotient ( RF[Rs] / RF[Rt] );
High = Remainder ( RF[Rs] / RF[Rt] )
r
divrd,rs,rtDivide:
Rf[rd] = Rf[rs]/Rf[rt]
(break on divide by zero)

Delay Slot OffDelay Slot On
  bne   rt,$0,08f
  break
08:
  div   rs,rt
  mflo  rd
  bne   rt,$0,08f
  nop
  break
08:
  div   rs,rt
  mflo  rd
divrd,rs,nDivide:
Rf[rd] = Rf[rs]/n

  li    $at,n
  div   rs,$at
  mflo  rd
divrd,nDivide:
Rf[rd] = Rf[rd]/n

  li    $at,n
  div   rd,$at
  mflo  rd
div.ddd,ds,dtDivide double:
FpRf[dd] = FpRf[ds] / FpRf[dt]
r
div.sfd,fs,ftDivide single:
FpRf[fd] = FpRf[fs] / FpRf[ft]
r
divurs,rtDivide Unsigned
Low = Quotient ( RF[Rs] / RF[Rt] );
High = Remainder ( RF[Rs] / RF[Rt] )
r
divurd,rs,rtDivide unsigned:
Rf[rd] = Rf[rs] / Rf[rt]
(break on divide by zero)

Delay Slot OffDelay Slot On
  bne   rt,$0,08f
  break
08:
  divu  rs,rt
  mflo  rd
  bne   rt,$0,08f
  nop
  break
08:
  divu  rs,rt
  mflo  rd
divurd,rs,nDivide unsigned:
Rf[rd] = Rf[rs] / n

  li    $at,n
  divu  rs,$at
  mflo  rd
divurd,nDivide unsigned:
Rf[rd] = Rf[rd] / n

  li    $at,n
  divu  rd,$at
  mflo  rd
exp.ddd,dse to the x power double:
FpRf[dd] = exp(FpRf[ds])
r
exp.sfd,fse to the x power single:
FpRf[fd] = exp(FpRf[fs])
r
floor.ddd,dsfloor double:
FpRf[dd] = floor(FpRf[ds])
r
floor.sfd,fsfloor single:
FpRf[fd] = floor(FpRf[fs])
r
jlabelJump
PC = PC(31:28) | Imm<< 2
j
jallabelJump And Link
RF[$ra] = PC;
PC = PC(31:28) | Imm<< 2
j
jalrrd,rsJump And Link Register
RF[Rd] = PC;
PC = RF[Rs]
r
jalrrsJump And Link Register
alias for jalr $ra,rs
$ra = PC;
PC = RF[Rs]
r
jrrsJump Register
PC = RF[Rs]
r
l.ddd,laddressLoad double:
FpRf[dd] = laddress

  lui   $at,laddress&0x8000<<1+laddress>>16
  lwc1  dd,laddress&0xFFFF($at)
  lwc1  dd+1,laddress&0xFFFF+4($at)
l.ddd,imm(rs)Load double:
FpRf[dd] = Mem[RF[Rs] + Offset]

  lwc1  dd,imm(rs)
  lwc1  dd+1,imm+4(rs)
l.sft,imm(rs)load word to cop1:
FpRf[ft] = Mem[Rf[rs] + Offset]
i
l.sfd,laddressLoad single:
FpRf[fd] = laddress

  lui   $at,laddress&0x8000<<1+laddress>>16
  lwc1  fd,laddress&0xFFFF($at)
lard,laddressLoad Address into Rf[rd]

  lui   rd,laddress>>16
  ori   rd,rd,laddress&0xffff
lbrt,imm(rs)Load Byte
RF[Rt] = Mem[RF[Rs] + Offset]
i
lbrd,laddressLoad byte (low 8 bits):
Rf[rd] = Mem[laddress]

  lui   $at,laddress&0x8000<<1+laddress>>16
  lb    rd,laddress&0xFFFF($at)
lburt,imm(rs)Load Byte Unsigned
RF[Rt] = Mem[RF[Rs] + Offset]
i
lburd,laddressLoad byte unsigned (low 8 bits):
Rf[rd] = Mem[laddress]

  lui   $at,laddress&0x8000<<1+laddress>>16
  lbu   rd,laddress&0xFFFF($at)
lhrt,imm(rs)Load Half
RF[Rt] = Mem[RF[Rs] + Offset]
i
lhrd,laddressLoad half (low 16 bits):
Rf[rd] = Mem[laddress]

  lui   $at,laddress&0x8000<<1+laddress>>16
  lh    rd,laddress&0xFFFF($at)
lhurt,imm(rs)Load Half Unsigned
RF[Rt] = Mem[RF[Rs] + Offset]
i
lhurd,laddressLoad half unsigned (low 16 bits):
Rf[rd] = Mem[laddress]

  lui   $at,laddress&0x8000<<1+laddress>>16
  lhu   rd,laddress&0xFFFF($at)
lird,immLoad Immediate into Rf[rd] variable size, no forward reference.
This macro is used when the high 16 bits of imm are empty.

ori   rd,$0,imm
lird,immLoad Immediate into Rf[rd] variable size, no forward reference.
This macro is used when the low 16 bits of imm are empty.

lui   rd,imm
lird,immLoad Immediate into Rf[rd] variable size, no forward reference.
This macro is used when the high 17 bits of imm are 1 (it's a small negative number).

addi   rd,$0,imm
lird,immLoad Immediate into Rf[rd] variable size, no forward reference.
This macro is used when none of the three other forms can be used.

lui   rd,imm
ori   rd,$0,imm
llrt,imm(rs)Load Linked
Unimplemented
i
ln.ddd,dsnatural log double:
FpRf[dd] = ln(FpRf[ds])
r
ln.sfd,fsnatural log single:
FpRf[fd] = ln(FpRf[fs])
r
luirt,immLoad Upper Immediate
RF[Rt] = Imm<<16
i
lwrt,imm(rs)Load Word
RF[Rt] = Mem[RF[Rs] + Offset]
i
lwrd,laddressLoad word (full 32 bits):
Rf[rd] = Mem[laddress]

  lui   $at,laddress&0x8000<<1+laddress>>16
  lw    rd,laddress&0xFFFF($at)
lwc1ft,imm(rs)load word to cop1:
FpRf[ft] = Mem[Rf[rs] + Offset]
i
lwc2rt,imm(rs)load word to cop2:
Unimplemented
i
lwc3rt,imm(rs)load word to cop3:
Unimplemented
i
lwlrt,imm(rs)Load Word Left
RF[Rt] = Mem[RF[Rs] + Offset]
i
lwrrt,imm(rs)Load Word Right
RF[Rt] = Mem[RF[Rs] + Offset]
i
mfc0rt,cdMove From Coprocessor0:
Rf[rt] = CP0Rf[cd]
r
mfc1rt,fsmove from cop1:
Rf[rt] = FpRf[fs]
r
mfhirdMove From Hi
RF[Rd] = HIGH
r
mflordMove From Low
RF[Rd] = LOW
r
movrd,rsMove
alias for addu rd,rs,$0
RF[Rd] = RF[Rs]
r
mov.ddd,dsCopy double value:
FpRf[dd] = FpRf[ds]
r
mov.sfd,fsCopy single value:
FpRf[fd] = FpRf[fs]
r
moverd,rsMove
alias for addu rd,rs,$0
RF[Rd] = RF[Rs]
r
mtc0rt,cdMove To Coprocessor0:
CP0Rf[cd] = Rf[rt]
Backwards Arguments!
r
mtc1rt,fsmove to cop1:
FpRf[fs] = Rf[rt]
r
mthirsMove To Hi
HIGH = RF[Rs]
r
mtlorsMove To Low
LOW = RF[Rs]
r
mulrd,rs,rtMultiply:
Rf[rd] = Rf[rs] * Rf[rt]

  mult  rs,rt
  mflo  rd
mulrd,rs,nMultiply:
Rf[rd] = Rf[rs]*n

  li    $at,n
  mult  rs,$at
  mflo  rd
mulrd,nMultiply:
Rf[rd] = Rf[rd]*n

  li    $at,n
  mult  rd,$at
  mflo  rd
mul.ddd,ds,dtMultiply double:
FpRf[dd] = FpRf[ds] * FpRf[dt]
r
mul.sfd,fs,ftMultiply single:
FpRf[fd] = FpRf[fs] * FpRf[ft]
r
mulord,rs,rtMultiply, break on overflow

Delay Slot OffDelay Slot On
  mult  rs,rt
  mfhi  $at
  mflo  rd
  sra   rd,rd,31
  beq   $at,rd,08f
  break
08:
  mflo  rd
  mult  rs,rt
  mfhi  $at
  mflo  rd
  sra   rd,rd,31
  beq   $at,rd,08f
  mflo  rd
  break
08:
mulourd,rs,rtMultiply unsigned, break on overflow

Delay Slot OffDelay Slot On
  multu rs,rt
  mfhi  $at
  beq   $at,$0,08f
  break
08:
  mflo  rd
  multu rs,rt
  mfhi  $at
  beq   $at,$0,08f
  mflo  rd
  break
08:
multrs,rtMultiply (signed)
High |Low = RF[Rs] * RF[Rt]
r
multurs,rtMultiply Unsigned
High |Low = RF[Rs] * RF[Rt]
r
mulurd,rs,rtMultiply unsigned:
Rf[rd] = Rf[rs] * Rf[rt]

  multu rs,rt
  mflo  rd
mulurd,rs,nMultiply unsigned:
Rf[rd] = Rf[rs] * n

  li    $at,n
  multu rs,$at
  mflo  rd
mulurd,nMultiply unsigned:
Rf[rd] = Rf[rd] * n

  li    $at,n
  multu rd,$at
  mflo  rd
negrd,rtNegate
alias for sub rd,$0,rt
RF[Rd] = -RF[Rt]
r
neg.ddd,dsNegate double value:
FpRf[dd] = -FpRf[ds]
r
neg.sfd,fsNegate single value:
FpRf[fd] = -FpRf[fs]
r
negurd,rtNegate
alias for subu rd,$0,rt
RF[Rd] = -RF[Rt]
r
nopno operation
alias for sll $0,$0,0
r
norrd,rs,rtBitwise Nor
RF[Rd] = !(RF[Rs] | RF[Rt])
r
notrd,rsBoolean Not
alias for nor rd,rs,$0
RF[Rd] = !(RF[Rs] | 0)
r
orrd,rs,rtBitwise Or
RF[Rd] = RF[Rs] | RF[Rt]
r
orirt,rs,immBitwise Or Immediate
RF[Rt] = RF[Rs] | Imm
i
orirt,immOr immediate:
Rf[rt] = Rf[rt] | imm

  ori   rt,rt,imm
remrd,rs,rtRemainder:
Rf[rd] = Rf[rs] % Rf[rt]

Delay Slot OffDelay Slot On
  bne   rt,$0,08f
  break
08:
  div   rs,rt
  mfhi  rd
  bne   rt,$0,08f
  nop
  break
08:
  div   rs,rt
  mfhi  rd
remrd,rs,nRemainder:
Rf[rd] = Rf[rs] % n

  li    $at,n
  div   rs,$at
  mfhi  rd
remrd,nRemainder:
Rf[rd] = Rf[rd] % n

  li    $at,n
  div   rd,$at
  mfhi  rd
remurd,rs,rtRemainder unsigned:
Rf[rd] = Rf[rs] % Rf[rt]

Delay Slot OffDelay Slot On
  bne   rt,$0,08f
  break
08:
  divu  rs,rt
  mfhi  rd
  bne   rt,$0,08f
  nop
  break
08:
  divu  rs,rt
  mfhi  rd
remurd,rs,nRemainder unsigned:
Rf[rd] = Rf[rs] % n

  li    $at,n
  divu  rs,$at
  mfhi  rd
remurd,nRemainder unsigned:
Rf[rd] = Rf[rd] % n

  li    $at,n
  divu  rd,$at
  mfhi  rd
rfeRestore From Exception
restores the status register to its value before the last exception occurred.
r
rolrd,rt,rsRotate left

  subu  $at,$0,rs
  srlv  $at,rt,$at
  sllv  rd,rt,rs
  or    rd,rd,$at
rolrd,rt,nRotate left

  srl   $at,rt,-n
  sll   rd,rt,n
  or    rd,rd,$at
rorrd,rt,rsRotate right

  subu  $at,$0,rs
  sllv  $at,rt,$at
  srlv  rd,rt,rs
  or    rd,rd,$at
rorrd,rt,nRotate right

  sll   $at,rt,-n
  srl   rd,rt,n
  or    rd,rd,$at
round.ddd,dsround double:
FpRf[dd] = round(FpRf[ds])
r
round.sfd,fsround single:
FpRf[fd] = round(FpRf[fs])
r
s.ddd,laddressStore double:
Mem[laddress] = FpRf[dd]

  lui   $at,laddress&0x8000<<1+laddress>>16
  swc1  dd,laddress&0xFFFF($at)
  swc1  dd+1,laddress&0xFFFF+4($at)
s.ddd,imm(rs)Store double:
Mem[RF[Rs] + Offset] = FpRf[dd]

  swc1  dd,imm(rs)
  swc1  dd+1,imm+4(rs)
s.sft,imm(rs)store word from cop1:
Mem[Rf[rs] + Offset] = FpRf[ft]
i
s.sfd,laddressStore single:
Mem[laddress] = FpRf[fd]

  lui   $at,laddress&0x8000<<1+laddress>>16
  swc1  fd,laddress&0xFFFF($at)
sbrt,imm(rs)Store Byte:
Mem[RF[Rs] + Offset] = RF[Rt]
Backwards Arguments!
i
sbrd,laddressStore byte (low 8 bits):
Mem[laddress] = Rf[rd]

  lui   $at,laddress&0x8000<<1+laddress>>16
  sb    rd,laddress&0xFFFF($at)
scrt,imm(rs)Unimplementedi
seqrd,rs,rtSet if equal:
Rf[rd] = Rf[rs] == Rf[rt]

  subu  $at,rs,rt
  sltiu rd,$at,1
sgerd,rs,rtSet greater than:
Rf[rd] = Rf[rs] > Rf[rt]

  slt   rd,rs,rt
  slti  rd,rd,1
sgeurd,rs,rtSet greater than unsigned:
Rf[rd] = Rf[rs] > Rf[rt]

  sltu  rd,rs,rt
  slti  rd,rd,1
sgtrd,rt,rsSet Greater Than
alias for slt rd,rs,rt
if (RF[Rt] > RF[Rs] ) then RF[Rd] =1 else RF[Rd] = 0
r
sgturd,rt,rsSet Greater Than Unsigned
alias for sltu rd,rs,rt
if (RF[Rt] > RF[Rs] ) then RF[Rd] =1 else RF[Rd] = 0
r
shrt,imm(rs)Store Half:
Mem[RF[Rs] + Offset] = RF[Rt]
Backwards Arguments!
i
shrd,laddressStore half (low 16 bits):
Mem[laddress] = Rf[rd]

  lui   $at,laddress&0x8000<<1+laddress>>16
  sh    rd,laddress&0xFFFF($at)
sin.ddd,dssine double:
FpRf[dd] = sin(FpRf[ds])
r
sin.sfd,fssine single:
FpRf[fd] = sin(FpRf[fs])
r
sinh.ddd,dshyperbolic sine double:
FpRf[dd] = sinh(FpRf[ds])
r
sinh.sfd,fshyperbolic sine single:
FpRf[fd] = sinh(FpRf[fs])
r
slerd,rs,rtSet less than or equal:
Rf[rd] = Rf[rs] <= Rf[rt]

  slt   rd,rt,rs
  slti  rd,rd,1
sleurd,rs,rtSet less than or equal unsigned:
Rf[rd] = Rf[rs] <= Rf[rt]

  sltu  rd,rt,rs
  slti  rd,rd,1
sllrd,rt,nShift Left Logical (immediate)
RF[Rd] = RF[Rt] << n
r
sllrd,rt,rsShift Left Logical
alias for sllv rd,rt,rs
RF[Rd] = RF[Rt] << RF[Rs] amount
r
sllvrd,rt,rsShift Left Logical Variable
RF[Rd] = RF[Rt] << RF[Rs] amount
r
sltrd,rs,rtSet Less Than
if (RF[Rs] < RF[Rt] ) then RF[Rd] =1 else RF[Rd] = 0
r
sltirt,rs,immSet Less Than Immediate
if (RF[Rs] < Imm) then RF[Rt] = 1 else RF[Rt] = 0
i
sltiurt,rs,immSet Less Than Immediate Unsigned
if (RF[Rs] < Imm) then RF[Rt] = 1 else RF[Rt] = 0
i
slturd,rs,rtSet Less Than Unsigned
if (RF[Rs] < RF[Rt] ) then RF[Rd] =1 else RF[Rd] = 0
r
snerd,rs,rtSet if not equal:
Rf[rd] = Rf[rs] != Rf[rt]

  subu  $at,rs,rt
  sltu  rd,$0,$at
sqrt.ddd,dssquare root double:
FpRf[dd] = sqrt(FpRf[ds])
r
sqrt.sfd,fssquare root single:
FpRf[fd] = sqrt(FpRf[fs])
r
srard,rt,nShift Right Arithmetic (immediate)
RF[Rd] = RF[Rt] >> n (sign-extend)
r
srard,rt,rsShift Right Arithmetic
alias for srav rd,rt,rs
RF[Rd] = RF[Rt] >> RF[Rs] amount (sign-extend)
r
sravrd,rt,rsShift Right Arithmetic Variable
RF[Rd] = RF[Rt] >> RF[Rs] amount (sign-extend)
r
srlrd,rt,nShift Right Logical
RF[Rd] = RF[Rt] >> n (no sign extension)
r
srlrd,rt,rsShift Right Logical
alias for srlv rd,rt,rs
RF[Rd] = RF[Rt] >> RF[Rs] amount (no sign extension)
r
srlvrd,rt,rsShift Right Logical Variable
RF[Rd] = RF[Rt] >> RF[Rs] amount (no sign extension)
r
subrd,rs,rtSubtract
RF[Rd] = RF[Rs] - RF[Rt]
r
subrt,rs,immSubtract:
Rf[rt] = Rf[rs] - imm

  addi  rt,rs,-imm
subrt,immSubtract:
Rf[rt] = Rf[rt] - imm

  addi  rt,rt,-imm
sub.ddd,ds,dtSubtract double:
FpRf[dd] = FpRf[ds] - FpRf[dt]
r
sub.sfd,fs,ftSubtract single:
FpRf[fd] = FpRf[fs] - FpRf[ft]
r
suburd,rs,rtSubtract Unsigned
RF[Rd] = RF[Rs] - RF[Rt]
r
suburt,immSubtract unsigned:
Rf[rt] = Rf[rt] - imm

  addiu rt,rt,-imm
suburt,rs,immSubtract unsigned:
Rf[rt] = Rf[rs] - imm

  addiu rt,rs,-imm
swrt,imm(rs)Store Word:
Mem[RF[Rs] + Offset] = RF[Rt]
Backwards Arguments!
i
swrd,laddressStore word (full 32 bits):
Mem[laddress] = Rf[rd]

  lui   $at,laddress&0x8000<<1+laddress>>16
  sw    rd,laddress&0xFFFF($at)
swc1ft,imm(rs)store word from cop1:
Mem[Rf[rs] + Offset] = FpRf[ft]
i
swc2rt,imm(rs)store word from cop2:
Mem[Rf[rs] + Offset] = Unimplemented
i
swc3rt,imm(rs)store word from cop3:
Mem[Rf[rs] + Offset] = Unimplemented
i
swlrt,imm(rs)Store Word Left (1-4 bytes, depending on offset):
Mem[RF[Rs] + Offset] = RF[Rt]
Backwards Arguments!
i
swrrt,imm(rs)Store Word Right (1-4 bytes, depending on offset):
Mem[RF[Rs] + Offset] = RF[Rt]
Backwards Arguments!
i
syscallcall syscall in $v0b
syscallscodecall syscall in argumentb
syscallrcodecall syscall in registerb
tan.ddd,dstangent double:
FpRf[dd] = tan(FpRf[ds])
r
tan.sfd,fstangent single:
FpRf[fd] = tan(FpRf[fs])
r
tanh.ddd,dshyperbolic tangent double:
FpRf[dd] = tanh(FpRf[ds])
r
tanh.sfd,fshyperbolic tangent single:
FpRf[fd] = tanh(FpRf[fs])
r
tlbpProbe TLB For Matching Entry
Unimplemented
r
tlbrRead Indexed TLB Entry
Unimplemented
r
tlbwiWrite Indexed TLB Entry
Unimplemented
r
tlbwrWrite Random TLB Entry
Unimplemented
r
trunc.ddd,dstruncate double:
FpRf[dd] = trunc(FpRf[ds])
r
trunc.sfd,fstruncate single:
FpRf[fd] = trunc(FpRf[fs])
r
ulhrt,imm(rs)

  lb    rt,imm+1(rs)
  lbu   $at,imm(rs)
  sll   rt,rt,8
  or    rt,rt,$at
ulhurt,imm(rs)

  lbu   rt,imm+1(rs)
  lbu   $at,imm(rs)
  sll   rt,rt,8
  or    rt,rt,$at
ulwrt,imm(rs)

  lwl   rt,imm+3(rs)
  lwr   rt,imm(rs)
ushrt,imm(rs)

  sb    rt,imm(rs)
  srl   $at,rt,8
  sb    $at,imm+1(rs)
uswrt,imm(rs)

  swl   rt,imm+3(rs)
  swr   rt,imm(rs)
xorrd,rs,rtBitwise Xor
RF[Rd] = RF[Rs] ^ RF[Rt]
r
xorirt,rs,immBitwise Xor Immediate
RF[Rt] = RF[Rs] ^ Imm
i
xorirt,immXor immediate:
Rf[rt] = Rf[rt] ^ imm

  xori  rt,rt,imm