PCSpim is a freely available personal computer simulator for MIPS. It simulates the behavior of a MIPS processor on an Intel-based machine. SPIM was originally developed by Dr. James Larus at the University of Wisconsin, Madison, around 20 years ago. You can download it from the University of Wisconsin, Madison website: http://www.cs.wisc.edu/~larus/SPIM/pcspim.zip. Using this simulator, you can single-step your program instruction by instruction and see the changes in register and memory contents during the execution of the program. The programs are written in MIPS assembly language using any text editor like Notepad. Please note that you need to save your program using the extension “.asm” or “.s“.
Understanding the PCSpim GUI
Before understanding PCSPIM, you need to install PCSPIM software on your system. Check this video to learn how to download and install PCSPIM software:
Double click on PCSpim and the following screen will appear (picture taken from internet).
Different areas of the PCSpim screen are explained below:
- The Registers Window is called this window. It contains information about the Program Counter (PC), General registers, Single and Double Floating Point Registers. Each of these registers is 32 bits wide. You can view register values in decimal by selecting Settings in the Simulator menu and unchecking View General Registers in Hex.
- The contents of the Text/Code Segment are displayed in this window. The text segment is the portion of the memory that contains the code/instructions to be executed. The first column contains the address of the instruction. The second column contains the instruction expressed in Hex form (which will be discussed in class). The third column contains the actual machine language instruction (processor assembly) to be executed, while the last column contains the original instruction in MIPS assembly that you wrote.
- The contents of the Data Segment are displayed in this window. The Data segment reserves space for declarations (int, char, etc.) that you made while writing the program. You can see the variables and arrays that you declared here. It also shows the contents of the stack.
- The messages generated by PCSpim are shown in this window. It also informs if a program was successfully loaded or if some error was encountered.
Writing and Analyzing a Simple Program in PCSpim
We have provided a complete overview of PCspim software and also provided examples to write your first MIPS assembly language program in MIPS. Check this video to know how to write your first assembly program using PCspim.
Let’s run a simple program and observe how the processor and simulator work. Open Notepad and type in the following code: (Note: PCSpim is case-sensitive. Also, make sure to spell .globl correctly, and keep all program code in lowercase except for labels. The # symbol is used for comments. Please avoid adding comments.)
The start of the text section of the program indicates by .text. During the execution of this program, manually calculate and record the decimal values that should be stored in various registers. I have provided the results of each instruction, so verify the results of each instruction to deepen your understanding.
Write Your First MIPS code in PCSpim
.text
.globl main # C equivalent
main:
addi $s0, $zero, 10 # X = 10; $s0 = X, Value in $s0: 10
addi $s1, $zero, 20 # Y = 20; $s1 = Y, Value in $s1: 20
addi $s2, $zero, -30 # Z = -30;$s2 = Z, Value in $s2: -30
add $t0, $s0, $s1 # A = X+Y;$t0 = A, Value in $t0: 30
sub $t1, $s1, $s2 # B = Y-Z;$t1 = B, Value in $t1: 50
add $t2, $t0, $t1 # C = A+B;$t2 = C, Value in $t2: 80
or $t3, $s0, $s2 # D = X|Z;$t3 = D, Value in $t3: -22
slt $t4, $s0, $s1 # Set on less then (slt)
# $t4 is set to 1 if $s0 < $s1, 0 otherwise.
# if(X<Y){E=1};$t4 = E Value in $t4: 1
slti $t5, $s2, -400 # if(Z<-400){F=1};$t5 = F Value in $t5: 0
Save this code as “FirstProgram.s” in your Z drive or on the D drive of the computer that you are using. Note that you need to save your program using quotation marks like “FirstProgram.s” in order to save it with the correct extension.
How to Run PCSpim Simulator
Load PCSpim by clicking its icon on the desktop or by opening it from the Start menu. If it asks for a path to a file, provide the file path from the folder where you have installed or copied the PCSpim simulator. When PCSpim opens, go to the File menu and select Open. Open the file FirstProgram.s from the location where you saved it.
Running Your Program One Instruction at a Time (Single-Stepping) in PCSpim
To run the program in single steps in PCSpim, press F10 for each instruction. Getting to Main: Keep pressing F10 until you reach the instruction at main’s address 0x00400024 (shown on the left side in the test window). This is where your program’s main starts, and here you will be able to see your program in the window, as mentioned above. Verify that the instructions from here onwards correspond to the instructions of your program above.
If your program is giving some strange error, make sure you have the following three lines of your code in the correct order (shown here). Remember this for all upcoming tutorials.
.text
.globl main
main:
MIPS Logical Operations in PCSpim
let’s see example of MIPS logical operations in PCSPIM.
MIPS Shift Operations
srl and sll shift the number by a specified number of bits towards the right and left respectively. Recall that shifting a number in binary is equivalent to multiplying or dividing the number by powers of 2, e.g.
- sll $t1, $t1, 3 multiplies the number in the register $t1 by 8.
- srl $t1, $t1, 4 divides the number in the register $t1 by 16.
More Bitwise Operations
and, or, andi, ori are bitwise operations available in MIPS.
Masking can be used to extract bits from a given number, e.g.
- andi $t1, $t0, 64 extracts the 7th bit from $t0 and saves it in $t1. All other bits become zero.
- andi $t1, $t0, 15 extracts the last (least significant) four bits from $t0 and saves them in $t1.
MIPS Example Programs in PCSpim
Example1
Write a program to load the value 333 into the $t0 register. Shift the value in $t0 left by 5, then shift it right by 7, and finally shift it left by 2. Run the program.
.text
.globl main
main:
addi $t0, $zero, 333
sll $t0, $t0, 5
srl $t0, $t0, 7
sll $t0, $t0, 2
This MIPS assembly code performs a series of bit manipulation operations on the value 333 (which is loaded into register $t0) using shift instructions. Let’s break down each instruction:
- addi $t0, $zero, 333: This instruction loads the immediate value 333 into register $t0. $zero is a reserved register that always contains the value 0.
- sll $t0, $t0, 5: This instruction performs a logical left shift (sll) on the value in $t0. It shifts the bits in $t0 5 positions to the left. After this operation, the value in $t0 will be 333 * (2^5) or 333 * 32, which is 10656.
- srl $t0, $t0, 7: This instruction performs a logical right shift (srl) on the value in $t0. It shifts the bits in $t0 7 positions to the right. After this operation, the value in $t0 will be 10656 / (2^7) or 10656 / 128, which is 83.
- sll $t0, $t0, 2: This instruction performs another logical left shift (sll) on the value in $t0. It shifts the bits in $t0 2 positions to the left. After this operation, the value in $t0 will be 83 * (2^2) or 83 * 4, which is 332.
So, the final value stored in register $t0 after executing these instructions will be 332. The code essentially takes the value 333, performs left and right shifts on it, and ends up with 332 as the result.
Example-2
Write a program to load 796 into register $s0. Mask $s0 using the and operation to obtain the least significant five bits of $s0, and store them in $s1. Find the sum of 8×$s1 and $s1/4 using shift operations only. Use $t0 to hold the result of 8×**$s1**, use $t1 to hold the result of $s1/4, and use $t2 to hold the final sum.
Assembly Code
.text
.globl main
main:
addi $s0, $zero, 796
andi $s1, $s0, 31
sll $t0, $s1, 3
srl $t1, $s1, 2
add $t2, $t0, $t1
This MIPS assembly code performs a series of bitwise and arithmetic operations on the values stored in registers $s0
and $s1
to compute a final result in register $t2
. Let’s break down each instruction:
addi $s0, $zero, 796
: This instruction loads the immediate value 796 into register$s0
.$zero
is a reserved register that always contains the value 0.andi $s1, $s0, 31
: This instruction performs a bitwise AND operation between the value in$s0
(which is 796) and the immediate value 31. The result is stored in register$s1
. The AND operation with 31 effectively extracts the lower 5 bits of the value in$s0
. After this operation,$s1
will contain the value 12, which is the remainder when 796 is divided by 32.sll $t0, $s1, 3
: This instruction performs a logical left shift (sll) on the value in$s1
. It shifts the bits in$s1
3 positions to the left. After this operation, the value in$t0
will be12 * (2^3)
or12 * 8
, which is 96.srl $t1, $s1, 2
: This instruction performs a logical right shift (srl) on the value in$s1
. It shifts the bits in$s1
2 positions to the right. After this operation, the value in$t1
will be12 / (2^2)
or12 / 4
, which is 3.add $t2, $t0, $t1
: This instruction adds the values in registers$t0
and$t1
and stores the result in register$t2
. The values in$t0
and$t1
are 96 and 3, respectively. So, the final result in$t2
will be 96 + 3, which is 99.
In summary, the code takes the value 796, extracts the lower 5 bits (resulting in 12), performs some shifts and additions, and the final result in register $t2
is 99.
Example-3
Recall that the immediate field in addi can hold 16 bits. We now learn how to load a 32-bit value into a register. Let us try that. Say, we would like to load 0x12345678 into a register.
The method is:
- Load upper (most significant) 16 bits in a register.
- Shift it left by 16 places.
- Add lower (least significant) 16 bits to that register.
Using the abovementioned method, load the value 0x12345678 in $t0. You can load hex values using 0x notation, e.g., addi $t0, $zero, 0x1234.
.text
.globl main
main:
addi $t0, $zero, 0x1234
sll $t0, $t0, 16
addi $t0, $t0, 0x5678
This MIPS assembly code performs bit manipulation and addition operations on the value initially stored in register $t0
. Let’s break down each instruction:
addi $t0, $zero, 0x1234
: This instruction loads the immediate value0x1234
into register$t0
.$zero
is a reserved register that always contains the value 0. So, after this instruction, the value in$t0
becomes0x1234
.sll $t0, $t0, 16
: This instruction performs a logical left shift (sll) on the value in$t0
. It shifts the bits in$t0
16 positions to the left. After this operation, the value in$t0
will be0x1234
shifted left by 16 bits, which effectively results in0x12340000
.addi $t0, $t0, 0x5678
: This instruction adds the immediate value0x5678
to the value in$t0
. The value in$t0
was0x12340000
from the previous operation, and adding0x5678
to it results in0x12345678
.
So, the final value stored in register $t0
after executing these instructions is 0x12345678
. The code takes an initial value of 0x1234
, shifts it left by 16 bits, and then adds 0x5678
to it to obtain the final value.
Pseudo Instructions in MIPS
Some instructions are more readable in assembly language but not directly converted into processor machine language. They are first converted to the processor’s actual assembly language and then to its equivalent machine language form. These are called Pseudo Instructions. Try the following program:
.text
.globl main
main:
li $t0, -100 # load -100 in $t0
li $t1, 0x1234abcd # load a 32-bit number
li $t2, -1223455 # same
Load this program and observe how the instructions convert into MIPS processor assembly by observing the third column of the text segment.
Related content: