QtSPIM Tutorial
QtSPIM Tutorial
QtSPIM Tutorial
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 almost the entire MIPS32 assembler-extended instruction set. (It omits most floating point
comparisons and rounding modes and the memory system page tables.) The MIPS architecture has several
variants that differ in various ways (e.g., the MIPS64 architecture supports 64-bit integers and addresses), which
means that Spim will not run programs for all MIPS processors.
There are three primary sections contained within this window. The Register pane shows the contents of all the
MIPS registers. There are two tabs in this pane, one for the floating point registers and one for the integer
registers. The integer registers include the general purpose registers, the Program Counter, etc.
The Memory pane has two tabs, Data and Text. The Text tab shows the contents of the Program memory space.
This includes the hexadecimal memory addresses (contained in the brackets), the hexadecimal op codes, your
assembly language instructions (on the right) including pseudo-instructions you might use, and the actual
assembly instructions that correspond to the op codes.
The Data tab shows the contents of the Data memory space. This includes the variables and array data you
create, along with the stack content.
Finally, the Messages pane is where dialogue and messages from QtSPim are displayed to the user.
2 Writing and Running Assembly Program
The purpose of this lab handout is to get you familiar with the SPIM simulator that we will be using to study
and experiment with MIPS assembly before working on real MIPS hardware. This tutorial includes a number of
questions for you to answer as you go through the tutorial. Record your answers to these questions as you do the
tutorial.
Task 2.1: Editing Open a text editor such as notepad or gedit and type (or cut and paste) the following:
# comments are delimited by hash marks
.data
my_str: .asciiz "MIPS Workshop Day1\n"
.text
main:
li $v0, 4 # load the value "4" into register $v0
la $a0, my_str # load the address of "my_str" into register $a0
syscall # perform the "print_string" system call ($v0 = 4)
jr $ra # return to the calling procedure
The code has two parts. First is the data segment, labeled with the .data directive. The data segment is used to
allocate storage and initialize global variables. The above program allocates a single variable my_str.
The .asciiz directive shows that this variable is an ASCII string that should be terminated with a zero (that's
what the z means). This statement will cause the assembler to allocate 23 bytes of space (one for each character
and one more for a terminating zero) for the variable and load it with the ASCII values for the characters,
followed by a zero.
Second is the text segment, indicated by the .text directive. This is where we put the instructions we want the
processor to execute. In the above program, there is a single function, which is called main. The name main is
special; it will be the first function of our program that gets called. Our main function prints my_str to the
console and then returns. This is accomplished in four instructions:
1. li is short for load immediate; that means put a constant into a register (in this case the constant 4 in the
register $v0).
2. la is short for load address; that means put an address into a register (in this case the address of the
string my_str in the register $a0).
3. syscall is short for system call; SPIM provides a number of operating system services that aren't really a
part of MIPS assembly language, but are useful for playing with little assembly programs. We indicate
to SPIM which system call to perform by putting a particular number in register $v0. System call
number 4 is print_string which interprets the contents of register $a0 as the address of a null-terminated
string (i.e., a string that ends with a zero) and copies the string to the console.
4. jr is short for jump register; this instruction performs the return for us. As we will see shortly, the piece
of code that calls our main function puts a return address into register $ra (the return address register).
The jump register command sets the processor's program counter (PC) to the contents of register $ra,
returning execution to the calling function.
Task 2.2 Save the file as test.s. The .s extension is typically used for assembly files.
Task 2.3 Load your assembly program by selecting File Load File.
You'll see the contents of the the Text Segments and Data Segments window update themselves.
You can scroll down in the Text pane to see that your assembly code has been loaded into Program memory
space. In this case, the first instruction is at memory location 0x00400024.
Task 2.4 Click the run button to run the program. It will display a window indicating the PC to begin execution
(0x00400000) and the assembly file to execute test.s. SPIM should fill in these fields correctly and you will
only need to click ok.
Task 2.5. Look at Console Window
If you typed in the program correctly, the SPIM console should pop up and print the message Computer
Architecture Lab. You might have noticed that some of the register values at the top of the main xspim window
changed also. We'll now look closer at what SPIM is doing.
SPIM provides a number of features to support debugging that you will find useful while developing your
assembly programs. The two most important are stepping and breakpoints. Stepping allows you to look at the
effect of your program instruction by instruction. Breakpoints allow you to stop the execution just before a
particular instruction is executed.
Task 3.1 Reload Program To run the test program again, you need to return the machine back to its initial
state. This can be done with the “reinitialize and reload file” button:
3.1.1 Click the Reinitialize button and reselect assembly file. The PC register (in the upper left corner)
should have reverted back to 0.
The first line in the Text Segments window should also be highlighted. Each line in the text segment
window describes one instruction; the four fields (from left to right) are: the instruction address, the binary
representation of the instruction, the machine instruction, and the assembly code statement that was translated
into the instruction
The first 9 instructions (0x00400000-0x00400020) shown in the Text Segments window don't actually come
from your assembly program. The test.s code begins at address 0x00400024.
3.1.2 Click on the step button. A window will pop up. Again, we will accept the default parameters (single
instruction stepping and our test.s program).
. The last two columns differ in two ways: 1) register names ($sp) have been translated into register numbers
($29), and 2) some assembly instructions (e.g., li) don't actually exist on the hardware so must be translated
into instructions that the machine implements (e.g., ori). The first instruction is highlighted because it is at the
address currently held in the program counter (PC) register, and, thus, is the next instruction to be executed.
3. The program starts at 0x00400000. Click on the step button in the dialog window to execute the first
instruction. This first instruction is a lw or load word instruction that loads a value into register $4.
Question 1: What is the value of the word that was loaded? ______________
This value was loaded from the top of the stack (a 0 offset from the stack pointer register $sp).
Question 2: What is the value of the stack pointer ($sp) register? ___________
Question 3: Look at the tab labeled Data Segments, and look at label User Stack. What is the value of the
word at the address (your answer to Question 2) pointed to by the $sp register? _____________
4. Find the address under the word User STACK. To the right of this address there are up to four 32-bit data
words; the leftmost one is at the address in brackets, each position to the right adds 4 to the address.
You will notice that execution of the first instruction also changed the contents of the PC register.
5. Click the step button (in the dialog) 2 more times so that instruction 0x0040000c is highlighted.
Instruction 0x00400008 is of type addiu or ADD Immediate Unsigned, which means add a constant (in this
case 4) to a register (R5) and put it in another register (R6).
Question 5: What value does the addiu write into R6? __________________
6. Set a breakpoint on address 0x00400014, by right-clicking on that instruction and selecting set breakpoint.
7. Click the run/continue button in the menu bar to skip some of the initilization code. When QTSpim stops, it
pops up a dialog box; click on abort command to dismiss it. Also, the Text Segments window is highlighting the
instruction at which we set the break point.
8. Clear the breakpoint and then single step to the jal instruction.
The jal or jump and link instruction is used to implement function calls. The jump specifies an address (in this
case 0x00400024) of the next instruction to be executed; this address will be written to the PC register. In
addition, a link operation is performed to allow the called function to return to this function. This is
accomplished by writing PC+4 to the return address ($ra) register.
Question 6: What value is written by JAL to the register R31? ________________
Finally, we have arrived at the code you typed in. In the text segment window, you can see that QT SPIM
converted the li instruction we used into an ori instruction. It stands for (logical) OR immediate. The
li instruction is a pseudo instructions and isn't really a MIPS machine instruction, but is provided to simplify
assembly programming. If we were to try to load a very large immediate, it would take multiple MIPS
instructions to compute the immediate. For a small immediate like 4, SPIM performs a logical OR of the
immediate with the $0 register (whose contents is always the value 0).
8. Step one instruction to verify that register R2 is written with the value 4.
Similarly, the la pseudo instruction is converted into the MIPS primitive lui or load upper immediate. lui is
used for setting the upper 16 bits of a register. It turns out that SPIM places my_str at address 0x10010000, the
bottom 16 bits of which are all zeros. As a result SPIM can write the address of my_str into a register with a
single instruction that writes (4097 << 16) into R4. Looking at the Data Segments window, in the DATA
section, you can see address 0x10010000. The string in our assembly file has been converted into ASCII and
runs from address 0x10010000 to 0x10010016. Each ASCII character is eight bits, so four are packed together
into the 32-bit data words in the data segment.
9. Step across that instruction and verify that the string is written to the console window.
The last instruction of our program performs the return. The $ra register should still contain the value placed
there by the jal instruction. The jump register instruction will copy the contents of the $ra register back to the
PC register.
Modifying a program
1. Return to your text editor. Replace the contents of my_str with your name. It should look something like:
my_str: .asciiz "zahid\n"
2. Save the file, and reload it using the reinitialize and load menue button. Click on the reload button
and select until assembly file item is highlighted, then release the button.
You should see the contents of the Data Segments window change (as well as the re-initializing of
the register and the Text Segments window).
4. Run the program to see your name written into the console window.