<- back to notes ; <- back to syllabus
Source: SPIM — A MIPS32 Simulator
spim
is a self-contained simulator that runsMIPS32
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. So provide only MIP32 assembly program files.
spim
implements almost the entireMIPS32
assembler-extended instruction set. (It omits most floating point comparisons and rounding modes and the memory system page tables.) TheMIPS
architecture has several variants that differ in various ways (e.g., theMIPS64
architecture supports 64-bit integers and addresses), which means thatspim
will not run programs compiled for all MIPS processors.MIPS
compilers also generate a number of assembler directives thatspim
cannot process. These directives usually can be safely ignored.Earlier versions of spim (before 7.0) implemented the
MIPS-I
instruction set used on theMIPS R2000/R3000
computers. This architecture is obsolete (though, never surpassed for its simplicity and elegance).spim
now supports the more modernMIPS32
architecture, which is theMIPS-I
instruction set augmented with a large number of occasionally useful instructions.MIPS
code from earlier versions ofSPIM
should run without changes, except code that handles exceptions and interrupts. This part of the architecture changed over time (and was poorly implemented in earlier versions ofspim
). This type of code will need to be updated. Examples of new exception handling are in the files:exceptions.s
andTests/tt.io.s
.
spim
comes with complete source code and documentation. It also include a torture test to verify a port to a new machine.
spim
implements both a terminal and a window interface. OnMicrosoft Windows
,Linux
, andMac OS X
, thespim
program provides the simple terminal interface and theQtSpim
program provides the windowing interface.
spim
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 Linux—the same source code and the same user interface on all three platforms! QtSpim is the version of spim that currently being actively maintaned. The other versions are still available, but please stop using them and move to QtSpim. It has a modern user interface, extensive help, and is consistent across all three platforms. QtSpim makes my life far easier, and will likely improve yours and your students’ experience as well.
A compiled, immediately installable version of QtSpim is available for Microsoft Windows, Mac OS X, and Linux can be downloaded from: https://sourceforge.net/projects/spimsimulator/files/. Full source code is also available (to compile QtSpim, you need Nokia’s Qt framework, a very nice cross-platform UI framework that can be downloaded from here).
Windows
, Linux
, and MacOS
Download the files from here https://sourceforge.net/projects/spimsimulator/files/.
MacOS
Use Homebrew to install. There are two versions: one to run in a terminal and another to run as a GUI application, called Qtspim
.
Terminal-based spim
:
brew install spim
GUI-based Qtspim
:
brew install --cask qtspim
spim
Working in a Unix-like environment, like Linux
or MacOS
################################################################################
#
# file: program.s
# author: Your Name <your.name@cooper.edu>
# date: 2024-02-24
# purpose: This program is a simple example of an assembly language program
# that can be assembled and run on a MIPS32 simulator, like spim.
#
#2345678901234567890123456789012345678901234567890123456789012345678901234567890
################################################################################
#------------{ global data section } ------------#
# declare all global variables and string #
# constants in this section. #
# The .data section contains the program's data. #
#------------------------------------------------#
.data
# The .asciiz directive creates a null-terminated string.
# The string "Hello, world!" is stored in memory.
hello: .asciiz "Hello, world!"
#------------{ code section }----------------------------#
# place all main code ("mainline") and procedure code in #
# this section of the file #
#--------------------------------------------------------#
.text
# The .globl directive makes the main label visible to the linker.
.globl main
# The main label marks the beginning of the program.
# This is mostly a formality, but it will be very
# important later when we start writing programs with more than one function.
# In between the initialization and exit of the function there is space
# to actually write a program.
main:
# initialize the program stack pointer
subu $sp, $sp, 4
# save the return address on the stack
sw $ra, 4($sp)
# The la (load address) pseudo instruction loads the address of the string
# into register $a0.
la $a0, hello
# The li (load immediate) pseudo instruction loads the system call number
# for printing a string into register $v0.
li $v0, 4
# The syscall instruction makes a system call (OS-provided).
syscall
#
# exit the program
#
# restore the return address from the stack
lw $ra, 4($sp)
addu $sp, $sp, 4
# return to the address in the $ra register
j $ra
#
# OR, use the following code to exit the program
#
# The li (load immediate) pseudo instruction loads the system call number
# for exiting the program into register $v0.
# li $v0, 10
# The syscall instruction makes a system call.
# syscall
.end main
.data
, .text
, and proceduresC: mips-1.c
#include <stdio.h>
char *prompt = "> ";
char *newline = "\n";
char *msg1 = "Hello, World!";
char *msg2 = "Integer =";
char *msg3 = "Pi =";
int foobar = 4;
float pi = 3.14159265;
void main(void)
{
printf("%s", prompt);
printf("%s", msg1);
printf("%s", newline);
printf("%s", prompt);
printf("%s", msg2);
printf("%d", foobar);
printf("%s", newline);
printf("%s", prompt);
printf("%s", msg3);
printf("%f", pi);
printf("%s", newline);
}
Assembly: mips-1.s
# mips-1.s
#
.data
foobar: .word 0x00000004
prompt: .asciiz "> " # a NUL-terminated string
newline:.asciiz "\n"
msg1: .asciiz "Hello, World!"
msg2: .asciiz "Integer = "
msg3: .asciiz "Pi = "
#pi: .word 01000000010010010000111111011011 # 3.14159265
pi: .float 3.14159265
# .extern foobar 4
.text
.globl main
main:
# print prompt
la $a0, prompt
jal print_str # jump to target and save position to $ra
# print msg1
la $a0, msg1
jal print_str # jump to target and save position to $ra
# print newline
la $a0, newline # argument: string
jal print_str # jump to target and save position to $ra
# print prompt
la $a0, prompt
jal print_str # jump to target and save position to $ra
# print msg2
la $a0, msg2
jal print_str # jump to target and save position to $ra
# print foobar
la $t0, foobar
lw $a0, 0($t0)
jal print_int # jump to target and save position to $ra
# print newline
la $a0, newline # argument: string
jal print_str # jump to target and save position to $ra
# print prompt
la $a0, prompt
jal print_str # jump to target and save position to $ra
# print msg3
la $a0, msg3
jal print_str # jump to target and save position to $ra
# print pi
la $t0, pi # load addr of float
lwc1 $f12, 0($t0) # load into fpr
jal print_float # jump to target and save position to $ra
# print newline
la $a0, newline # argument: string
jal print_str # jump to target and save position to $ra
# exit main
# The li (load immediate) pseudo instruction loads the system call number
# for exiting the program into register $v0.
li $v0, 10
# The syscall instruction makes a system call.
syscall
# procedure
print_str:
# $v0/1 and $a0-3 NOT preserved
# fix $sp for procedures
addi $sp,$sp,-4 # Moving Stack pointer
# print string
li $v0, 4 # syscall 4 (print_str)
syscall # print the string
# put back $sp and return
addi $sp,$sp,4 # Moving Stack pointer
jr $ra # return (Copy $ra to PC)
print_int:
# $v0/1 and $a0-3 NOT preserved
# fix $sp for procedures
addi $sp,$sp,-4 # Moving Stack pointer
# print int
li $v0, 1 # syscall 1 (print_int)
syscall # print the string
# put back $sp and return
addi $sp,$sp,4 # Moving Stack pointer
jr $ra # return (Copy $ra to PC)
print_float:
# $v0/1 and $a0-3 NOT preserved
# fix $sp for procedures
addi $sp,$sp,-4 # Moving Stack pointer
# print float
li $v0, 2 # syscall 2 (print_float)
syscall # print the string
# put back $sp and return
addi $sp,$sp,4 # Moving Stack pointer
jr $ra # return (Copy $ra to PC)
Qtspim
TutorialSee https://www.lri.fr/~de/QtSpim-Tutorial.pdf