PCSpim is a freely available personal computer simulator for MIPS. It simulates 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 know 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:
- This window is called the Registers 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. To view register values in decimal, select Settings in Simulator menu and unchecked View General Registers in Hex.
- This window displays the contents of the Text/Code Segment. 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 (will be discussed in the 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.
- This window displays the contents of the Data Segment. Data segment reserves the space for declarations (int, char, etc.) that you do while writing the program. You can see the variables, arrays that you declared, here. It also shows the contents of the stack.
- This window shows the messages generated by PCSpim. It also informs if a program was successfully loaded or if some error was encountered.
Writing and Analyzing a Simple Program in pcspim
I have given 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 us run a simple program and see the working of the processor and the simulator. Open Notepad and type in the following code: (Note that PCSpim is case sensitive, also see the spellings of globl, all program code is in lower case except labels. The sign # is used for comments. Do not type comments.) .text signifies the start of the text section of the program. Manually work out and write down the decimal values that various registers should contain after the execution of this program. I have written results of each instruction, you should verify results of each instruction to get better understanding.
writing first 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 inverted commas like “FirstProgram.s” in order to save your program with the required extension.
How to run pcspim simulator
Load PCSpim by clicking its icon present on the desktop or by opening it from the Start menu. If it asks for a path to some file, provide the path file from the folder where you have installed or copied pcspim simulator. When PCSpim opens, pull down 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 till you reach the instruction at main’s address 0x00400024 (shown on left side in test window). This is where you program’s main starts and here you will be able to see your program in widow as mentioned above. Verify that the instructions from here on wards 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 labs. .text .globl main main: |
Viewing Registers in pcspim as they change with each Instruction
Single step your program using F10, stop and fill the following table after execution of each instruction by observing the register window. You can also use window’s calculator as needed, but be informed that Windows built-in calculator is 64-bit and PCSPIM is 32-bit. Place a Ö in OK column if you agree with the answer (i.e., after comparing with the results that you worked out manually earlier) .. You shall be required to provide all the answers in HEX form. However, you should view registers in decimal form to confirm your answers. I have already filled the table. But I suggest you to compare your results with this table for better understanding.
Step 1: What is the value of $s0 after executing the first statement?
Decimal: 10, Hex: 0000000a, Ok: Ö
Step 2: What is the value of $s1 after executing the second statement?
Decimal: 20, Hex: 00000014, Ok: Ö
Step 3: What is the value of $s2 after executing the third statement?
Decimal: −30, Hex: ffffffe2, Ok: Ö
Step 4: What is the value of $t0 after executing the fourth statement?
Decimal: 30, Hex: 0000001e, Ok: Ö
Step 5: What is the value of $t1 after executing the fifth statement?
Decimal: 50, Hex: 00000032, Ok: Ö
Step 6: What is the value of $t2 after executing the sixth statement?
Decimal: 80, Hex: 00000050, Ok: Ö
Step 7: What is the value of $t3 after executing the 7th statement?
Decimal: −22, Hex: ffffffea, Ok: Ö
Step 8: What is the value of $t4 after executing the 8th statement?
Decimal: 1, Hex: 00000001, Ok: Ö
Step 9: What is the value of $t5 after executing the 9th statement?
Decimal: 0, Hex: 00000000, Ok: Ö
For $t3, do the calculations in 32-bit binary (by directly converting hex values of $s0 and $s1 given above) on the back of this page to verify your answer.
More 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 with 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.
Example number 2 in pcspim
Write a program to load the value 333 in $t0 register. Shift the value in $t0, left by 5, then shift it right by 7 and then shift it left by 2. Run the program
What is the Hex value of 333 loaded in $t0: 0000014d
What is the Hex value of $t0 after it is shifted left by 5? 000029a0
What is the Hex value of $t0 after it is shifted right by 7? 00000053
What is the Hex value of $t0 after it is shifted left by 2? 0000014c
Is the final result different from 333? Why? Yes the answer is different from 333. It is 332. The reason for this difference is that the number was left shifted by 5 first but then it was right shifted by 7 resulting in the loss of the last two bits which were 01 in binary and equivalent to 1 in decimal and hex. Finally when the number was left shifted by 2, two 0s were inserted in place of 01.
Code of Exercise-2:
.text .globl main main: addi $t0, $zero, 333 sll $t0, $t0, 5 srl $t0, $t0, 7 sll $t0, $t0, 2
Exercise 3:
Write a program to load 796 in register $s0. Mask $s0 using and operation to obtain 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. Run the program .
What is the Hex value of 796 loaded in $s0: 0000031c
What is the Hex value in $s1 after the masking operation? 0000001c
What is the Hex value of $t0 after the operation 8*$s1? 000000e0
What is the Hex value of $t1 after the operation $s1/4? 00000007
What is the Hex value of the final sum in $t2? 000000e7
Code for Exercise-3:
.text .globl main main: addi $s0, $zero, 796 andi $s1, $s0, 31 sll $t0, $s1, 3 srl $t1, $s1, 2 add $t2, $t0, $t1
Exercise 4:
Recall that immediate field in addi can hold 16 bits. We now learn how to load a 32-bit value in a register. Let us try that. Say, we would like to load 0x12345678 in 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. Run the program .
Code for Exercise-4: .text .globl main main: addi $t0, $zero, 0x1234 sll $t0, $t0, 16 addi $t0, $t0, 0x5678
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 see how these instructions are converted into MIPS processor assembly by observing the third column of the text segment.