You are on page 1of 11

Islamic University Gaza

Engineering Faculty
Department of Computer Engineering
ECOM 3010: Computer Architecture Discussion

Lecture # 1

SPIM & MIPS Programming

Eng. Eman R. Habib


September, 2013

Computer Architecture Discussion

SPIM
Spim is a self-contained simulator that runs MIPS32 programs. It reads and executes assembly
language programs written for this processor. Spim also provides a simple debugger and
minimal set of operating system services. Spim does not execute binary (compiled) programs.
Spim implements both a terminal and windows interfaces. On Microsoft Windows, Linux, and
Mac OS X, the spim program offers a simple terminal interface and the QtSpim program
provides the windowing interface.

QtSpim
The newest version of Spim is called QtSpim, and unlike all of the other version, it runs on
Microsoft Windows, Mac OS X, and Linuxthe same source code and the same user interface
on all three platforms! QtSpim is the version of Spim that currently being actively maintained. It
has a modern user interface, extensive help, and is consistent across all three platforms.
When you open QtSpim, A window will open as shown in Figure 1. The window is divided into
different sections:
1. The Register tabs display the content of all registers.
2. Buttons across the top are used to load and run a simulation
3. The Text tab displays the MIPS instructions loaded into memory to be executed. (From
left-to-right, the memory address of an instruction, the contents of the address in hex,
the actual MIPS instructions where register numbers are used, the MIPS assembly that
you wrote, and any comments you made in your code are displayed.)
4. The Data tab displays memory addresses and their values in the data and stack
segments of the memory.
5. The Information Console lists the actions performed by the simulator.
Buttons

Register
tabs

Text & Data tabs

Messages
Figure 1: QtSpim

Computer Architecture Discussion

MIPS
The MIPS architecture is a Reduced Instruction Set Computer (RISC). This means that there are
a smaller number of instructions, using a uniform instruction encoding format. Each
instruction/operation does one thing (memory access, computation, conditional, etc.). The idea
is to make the lesser number of instructions execute faster. In general RISC architectures, and
specifically the MIPS architecture, are designed for high-speed implementations.

MIPS Programming: add.asm


To get our feet wet, we'll write an MIPS assembly language program named add.asm that
computes the sum of 1 and 2, and stores the result in register $t0.

Commenting:
Before we start to write the executable statements of program, however, we'll need to write a
comment that describes what the program is supposed to do. In the MIPS assembly language,
any text between a pound sign (#) and the subsequent newline is considered to be a comment.
# add.asm-- A program that computes the sum of 1 and 2,
# leaving the result in register $t0.
# Registers used:
# t0 - used to hold the result.
# end of add.asm

Finding the Right Instructions:


Next, we need to figure out what instructions the computer will need to execute in order to add
two numbers.
We need the add instruction, which adds two numbers together.
The add operation takes three operands:
1. A register that will be used to store the result of the addition. For our program, this will
be $t0.
2. A register which contains the first number to be added. Therefore, we're going to have
to get 1 into a register before we can use it as an operand of add. We select $t1, and
make note of this in the comments.
3. A register which holds the second number, or a 32-bit constant. In this case, since 2 is a
constant that fits in 32 bits, we can just use 2 as the third operand of add.
We now know how we can add the numbers, but we have to figure out how to get 1 into
register $t1. To do this, we can use the li (load immediate value) instruction, which loads a 32bit constant into a register.

Computer Architecture Discussion

Therefore, we arrive at the following sequence of instructions:


# add.asm-- A program that computes the sum of 1 and 2,
# leaving the result in register $t0.
# Registers used:
# t0 - used to hold the result.
# t1 - used to hold the constant 1.
li $t1, 1
add $t0, $t1, 2
# end of add.asm

# load 1 into $t1.


# $t0 = $t1 + 2.

Completing the Program


These two instructions perform the calculation that we want, but they do not form a complete
program. Much like C, an assembly language program must contain some additional
information that tells the assembler where the program begins and ends.

Labels and main


To begin with, we need to tell the assembler where the program starts. In SPIM, program
execution begins at the location with the label main. A label is a symbolic name for an address
in memory. In MIPS assembly, a label is a symbol name, followed by a colon. Labels must be the
first item on a line. Therefore, to tell SPIM that it should assign the label main to the first
instruction of our program, we could write the following:
# add.asm-- A program that computes the sum of 1 and 2,
# leaving the result in register $t0.
# Registers used:
# t0 - used to hold the result.
# t1 - used to hold the constant 1.
main:
li $t1, 1
add $t0, $t1, 2
# end of add.asm

# SPIM starts execution at main.


# load 1 into $t1.
# $t0 = $t1 + 2.

Syscall
The way to tell SPIM that it should stop executing your program, and also to do a number of
other useful things, is with a special instruction called a syscall. The syscall instruction suspends
the execution of your program and transfers control to the operating system. The operating
system then looks at the contents of register $v0 to determine what it is that your program is
asking it to do.

Computer Architecture Discussion

Table (1): SPIM syscalls

Service

Code

Arguments

Result

print_int

$a0

none

print_float

$f12

none

print_double
print_string

3
4

$f12
$a0

none
none

read_int
read_float

5
6

none
none

$v0
$f0

read_double

none

$f0

read_string
sbrk

8
9

$a0 (address), $a1(length)


$a0 (length)

none
$v0

exit

10

none

none

In this case, what we want is for the operating system to do whatever is necessary to exit our
program. Looking in table 1, we see that this is done by placing a 10 (the number for the exit
syscall) into $v0 before executing the syscall instruction.
We can use the li instruction again in order to do this:
# add.asm-- A program that computes the sum of 1 and 2,
# leaving the result in register $t0.
# Registers used:
# t0 - used to hold the result.
# t1 - used to hold the constant 1.
main:
li $t1, 1
add $t0, $t1, 2

# SPIM starts execution at main.


# load 1 into $t1.
# compute the sum of $t1 and 2, and
# put it into $t0.

li $v0, 10
syscall

# syscall code 10 is for exit.


# make the syscall.

# end of add.asm

Computer Architecture Discussion

Using QtSpim
1- Click on the load button

and open add.asm

Standard startup
code
The code start
here

Figure (2): add.asm code


2- You can then run the program by simply pressing the run (play) button
all
instructions will be executed, and the final contents of memory and the register file will
be reflected in the QtSpim window as shown in figure 3.

Figure (3): $t0, $t1 registers after run

Debugging
Suppose your program does not do what you expect. What can you do? QtSpim has two
features that help debug your program.
The first, and perhaps the most useful, is single stepping, which allows you to run your program
an instruction at a time. The single stepping icon
can be found in the toolbar. Every time
you do single stepping, QtSpim will execute one instruction and update its display, so that you
can see what the instruction changed in the registers or memory.

Computer Architecture Discussion

Figure (4): Single Step, after li $t1, 1

Figure (5): Single Step, after add $t0, $t1, 2

What do you do if your program runs for a long time before the bug arises? You could single
step until you get to the bug, but that can take a long time. A better alternative is to use a
breakpoint, which tells QtSpim to stop your program immediately before it executes a
particular instruction. When QtSpim is about to execute the instruction where there is a
breakpoint, it asks for continue, single stepping or abort.
Single-stepping and setting breakpoints will probably help you find a bug in your program
quickly. How do you fix it? Go back to the editor that you used to create your program and
change it. Click on the Riinitialize simulator tab in the toolbar and load the sourcefile again.

Computer Architecture Discussion

Figure(6): Set Breakpoint

Figure(7): After Seting Breakpoint

Figure(8): When reaching Breakpoint

Computer Architecture Discussion

Generally Useful Information


When using QtSpim, you may find the following information to be useful:
You can access all of the commands via the File and Simulator menus as well.
When examining register or memory data, you can view the data in binary, hex, or
decimal format. Just use the Register pull down menu to select.
To view memory data, simply click on the Data tab.
By right clicking on a register file value or memory address value, you can change its
contents dynamically.

Second Example: add2.asm


For our next example, we'll write a program named add2.asm that computes the sum of two
numbers specified by the user at runtime, and displays the result on the screen.
The algorithm this program will follow is:
1. Read the two numbers from the user.
We'll need two registers to hold these two numbers. We can use $t0 and $t1 for this.
2. Compute their sum.
We'll need a register to hold the result of this addition. We can use $t2 for this.
3. Print the sum.
4. Exit.
The only parts of the algorithm that we don't know how to do yet are to read the numbers from
the user, and print out the sum. Luckily, both of these operations can be done with a syscall.
Looking again in table 1, we see that syscall 5 can be used to read an integer into register $v0,
and syscall 1 can be used to print out the integer stored in $a0.
The syscall to read an integer leaves the result in register $v0, however, which is a small
problem, since we want to put the first number into $t0 and the second into $t1. Luckily, there
is move instruction, which copies the contents of one register into another.
Note that there are good reasons why we need to get the numbers out of $v0 and move them
into other registers: first, since we need to read in two integers, we'll need to make a copy of
the first number so that when we read in the second number, the first isn't lost. In addition,
register $v0 is not a recommended place to keep anything, so we shouldn't leave the second
number in $v0 either.
This gives the following program:
# add2.asm-- A program that computes and prints the sum
# of two numbers specified at runtime by the user.
# Registers used:
# $t0 - used to hold the first number.
# $t1 - used to hold the second number.
# $t2 - used to hold the sum of the $t1 and $t2.

10

Computer Architecture Discussion

# $v0 - syscall parameter and return value.


# $a0 - syscall parameter.
main:
## Get first number from user, put into $t0.
li $v0, 5
# load syscall read_int into $v0.
syscall
# make the syscall.
move $t0, $v0
# move the number read into $t0.
## Get second number from user, put into $t1.
li $v0, 5
# load syscall read_int into $v0.
syscall
# make the syscall.
move $t1, $v0
# move the number read into $t1.
add $t2, $t0, $t1

# compute the sum.

## Print out $t2.


move $a0, $t2
li $v0, 1
syscall

# move the number to print into $a0.


# load syscall print_int into $v0.
# make the syscall.

li $v0, 10
syscall
# end of add2.asm.

# syscall code 10 is for exit.


# make the syscall.

Third Example: hello Program


The next program that we will write is the "Hello World" program. Looking in table 1 once
again, we note that there is a syscall to print out a string. All we need to do is to put the
address of the string we want to print into register $a0, the constant 4 into $v0, and execute
syscall. The only things that we don't know how to do are how to define a string, and then how
to determine its address. The string "Hello World" should not be part of the executable part of
the program (which contains all of the instructions to execute), which is called the text segment
of the program. Instead, the string should be part of the data used by the program, which is, by
convention, stored in the data segment. The MIPS assembler allows the programmer to specify
which segment to store each item in a program by the use of several assembler directives.
To put something in the data segment, all we need to do is to put a .data before we define it.
Everything between a .data directive and the next .text directive (or the end of the file) is put
into the data segment. Note that by default, the assembler starts in the text segment, which is
why our earlier programs worked properly even though we didn't explicitly mention which
segment to use. In general, however, it is a good idea to include segment directives in your
code, and we will do so from this point on.
We also need to know how to allocate space for and define a null-terminated string.
In the MIPS assembler, this can be done with the .asciiz (ASCII, zero terminated string)
directive. For a string that is not null-terminated, the .ascii directive can be used.

11

Computer Architecture Discussion

Therefore, the following program will fulfill our requirements:


# hello.asm-- A "Hello World" program.
# Registers used:
# $v0 - syscall parameter and return value.
# $a0 - syscall parameter-- the string to print.
# Data for the program:
.data
hello_msg: .asciiz

"Hello World\n"

.text
main:
la $a0, hello_msg
li $v0, 4
syscall

# load the addr of hello_msg into $a0.


# 4 is the print_string syscall.
# do the syscall.

li $v0, 10
syscall

# 10 is the exit syscall.


# do the syscall.

# end hello.asm

Homework
Write a MIPS assembly language program that computes the difference between two numbers
specified by the user at runtime, and displays the result on the screen.
The program should display the message "Enter First Integer >>" to let the user enter the first
integer and store the first integer in $t1, then display the message "Enter Second Integer >> "
and store the second integer in $t2. After computing the result display "The Result is = " then
display the result.
You must submit the program printed with screenshot of Console after run the program.

Best Wishes

You might also like