Using the SPIM Simulator


Unlike the DOS world, the Unix world rarely provides an integrated development environment, such as Turbo C++. Instead, a text editor is used to produce a file which is passed along to another tool. In this case, the second tool is spim, a MIPS R2000 simulator. spim expects to be given a file containing a MIPS R2000 assembly language program. You may use your favorite text editor ( emacs, vi, even pico) to create this file.

spim provides a few amenities over a bare R2000. There is a syscall facility for performing I/O. While not as sophisticated as C I/O, it is superior to using memory mapped I/O (see Section 5 of the SPIM S20 paper). There is also a facility for setting breakpoints, single-stepping a program, and examining the values of registers and memory locations.

The rest of this document is a brief introduction to using SPIM. For additional information, see the article SPIM S20: A MIPS R2000 Simulator.

A Skeletal R2000 Program

Consider this skeletal program:

# Program documentation goes here.

            .data                         # Constants and variables
                                          # declarations.

            <Constant and variable declarations go here.>

            .text                         # Main (must be global).
            .globl main

main:       <Your program starts here.>

            li $v0, 10                    # Syscall to exit.

Running R2000 Programs under SPIM

First, we run a program straight from the shell. Then we run a program from within spim, so that we have the opportunity of setting breakpoints and single-stepping, etc.

The Easy Way to Run an R2000 Program

Let's say you have an R2000 program in the file SaveTheWorld.spim. Here's the easiest way to run it:

abacus% spim -file SaveTheWorld.spim
spim will load and execute the program. When execution finishes, you'll be returned to the shell.

Controlling Program Execution from within SPIM

From the shell, just type spim. This leaves you at the spim prompt:

abacus% spim
SPIM Version 5.3 of Aug 30, 1993
Copyright 1990-92 by James R. Larus (
All Rights Reserved.
See the file README a full copyright notice.
The most important command is help, which prints a summary of all the commands.

To load a program into the simulator, use the load command:

(spim) load "SaveTheWorld.spim"
Note that the program name must be enclosed in quotes.

To run the program, use run:

By default, execution begins with the statement labeled main.

Debugging R2000 Programs

Consider this program fragment:

            .text                   # Main.
            .globl main

main:       li $v0, 4               # Syscall to print prompt string.


            .globl while
while:      blez $t0, endwhile
            li $v0, 4
            la $a0, prmpt2

            li $v0, 5
            add $t1, $t1, $v0       # Increase sum by new input.

            sub $t0, $t0, 1         # Decrement n.

            b while

endwhile:   ...
If I suspected that I had a problem with my while loop, I would begin debugging it by setting a breakpoint at an appropriate statement, in this case the statement labeled while. Note that I have had to declare while .globl. Breakpoints may only be set at global labels.

After loading the program into memory, I set my breakpoint:

(spim) breakpoint while

When the simulator reaches a statement upon which a breakpoint is set, it suspends execution just before executing the statement. The step command is used to execute one (the default) or more statements at a time. continue is used to resume normal operation. delete label removes breakpoints from the statement labeled label. Hitting the return key at a spim prompt re-executes the last command, so the easiest way to single-step a program is to get to a breakpoint, give a step command, and then start pressing return.

step prints program statements as it executes them. Often, they don't correspond to the assembler program because the simulator exchanges symbolic register names ( $v0) for actual register names ( $2), exchanges symbolic labels with the actual memory address, and, most confusingly, replaces certain assembly language statements with different statements. In some cases, a single statement may even be replaced with multiple statements. This is because the assembly language is a bit richer (more abstract) than the actual R2000 instruction set. For example, the assembler provides a load immediate instruction:

li $v0, 1
The instruction set does not provide such an instruction. The assembler must translate this instruction to one that is a part of the R2000 instruction set:
ori $2, $0, 1
The assembler translates $v0 to $2 and uses or immediate on register 0 (which is the constant 0) to implement load immediate.

Here's how to print the value of a register:

(spim) print $v0
Here's how to print the value of a memory location:
(spim) print i
The assumption here is that i is a global label.

Other SPIM Commands

quit will terminate spim, returning you to the shell.

If spim seems to go haywire (it does sometimes, after misbehaved programs have been executed or if you load a second program), use reinitialize to restore it to a state of sanity and then load the assembler program.

Thomas P. Kelliher
Mon Sep 16 12:24:37 EDT 1996
Tom Kelliher