ShadowCaster Possibly Insane
Registered 02/01/2002
Points 2203
|
25th June, 2004 at 05:13:58 -
Hi All
I've been studying for my NETS exam, and part of the exam will be writing several short MIPS programs, so I've been practicing and decided to share how to do this with you.
First, you need to download an interpreter (or compiler). A free Windows program called PCSPIM can be downloaded from http://www.cs.wisc.edu/~larus/SPIM/pcspim.zip and a free unix/Linux program called XSPIM can be downloaded from http://www.cs.wisc.edu/~larus/SPIM/spim.tar.gz
I'm not going to explain everything about assembler, that would take forever because you need to know about the various types of registers (hi/lo/pc/etc) and the commands arent exactly user friendly (what did you expect?) So I'm just going to explain a few things to get you started and show a few example apps. Below each code in assembler is the equivilent code in C++. I find this helps people to understand what's going on.
If you have any questions, feel free to ask. I wont be able to answer until after my exams, so you might need to wait a while for a response.
Example 1: Addition of 2 Hard Coded Integers
This example adds 2 integers (hard-coded) and prints the result. In this example, the integers are 2 and 3.
.globl main
.text
main:
li $t0, 2
li $t1, 3
add $a0, $t0, $t1
li $v0, 1
syscall
li $v0, 10
syscall
# void main()
# {
# int t0 = 2;
# int t1 = 3;
#
# std::cout << t0 + t1;
# } - The first two lines are required, and I'm not going to explain them here. Just take them as given until you want to start programming larger things.
- The line "main:" is simply the name of the main function (where the program starts).
- "li" ("Load Integer") sets a register to a value. On the first line, it loads the integer 2 into temporary register 0. The second loads the integer 3 into temporary register 1.
- "add" adds two integers and puts the result into another register. In this example, it adds the values from temporary registers 0 and 1 and puts the result in the argument register 0.
- The next line loads another integer into a variable register. $v0 in MIPS is reserved for system call arguments and return values. A system call takes an integer and interprets it as a function on the system. In this example, the number 1 causes the system to print the integer in the $a0 argument register (which was previously set to the addition of $t0 and $t1).
- "syscall" executes the above syscall code set within the $v0 register.
- Now the $v0 register is set to 10. This is the exit code used to make the program quit, and is finished off with the "syscall" command to execute it.
Other SYSCALL commands
print_int: 1
Print the integer in $a0
print_float: 2
Print the float in $f12
print_double: 3
Print the double in $f12
print_string: 4
Print the string in $a0
read_int: 5
Read an int into $v0
read_float: 6
Read a float into $f0
read_double: 7
Read a double into $f0
read_string: 8
Read a string into $a0 and string length into $a1
sbrk: 9
Use amount from $a0 and return address to $v0
exit: 10
No arguments or return values
Example 2: Addition of 2 Variable Integers
This example reads 2 integers from standard input, adds them, and prints the result of the equation.
.data
input: .asciiz "Please enter an integer: "
plus: .asciiz " + "
equals: .asciiz " = "
.globl main
.text
main:
# PRINT INPUT LINE
la $a0, input
li $v0, 4
syscall
# GET INTEGER
li $v0, 5
syscall
move $s0, $v0
# PRINT INPUT LINE
la $a0, input
li $v0, 4
syscall
# GET INTEGER
li $v0, 5
syscall
move $s1, $v0
# ADD 2 INTEGERS
add $s2, $s0, $s1
# PRINT FIRST INTEGER
move $a0, $s0
li $v0, 1
syscall
# PRINT PLUS SIGN
la $a0, plus
li $v0, 4
syscall
# PRINT SECOND INTEGER
move $a0, $s1
li $v0, 1
syscall
# PRINT EQUALS SIGN
la $a0, equals
li $v0, 4
syscall
# PRINT RESULT
move $a0, $s2
li $v0, 1
syscall
# EXIT
li $v0, 10
syscall
# #define input "Please enter an integer: "
# #define plus " + "
# #define equals " = "
#
# void main()
# {
# std::cout << input;
# std::cin >> int s0; // Not valid C++, but closest representation
# std::cout << input;
# std::cin >> int s1; // Not valid C++, but closest representation
#
# int s2 = s0 + s1;
#
# std::cout << s0;
# std::cout << plus;
# std::cout << s1;
# std::cout << equals;
# std::cout << s2;
# } - You will notice the addition of a "data" section, where you can pre-define strings and other types. Here 3 strings have been pre-defined to make the code easier.
- Using syscall 4 we are able to print a string loaded into $a0 using the "la" ("Load Asciiz") command.
- Because the return integer from a syscall is always placed in $v0, we need to move the values out of the register and into a safe register. In this example the safe registers $s0 and $s1 are used to store the values, and $s2 is used to store the addition. You do not need to store the addition value, it could be done as in the first example. It's up to your own preference. The "move" command moves the value of the second register into the first register.
Example 3: Addition of Variable Number of Integers
This can seem pretty complex to someone who hasnt used assembler before, but it works pretty much the same as any language, just it looks nastier
.data
number: .asciiz "Number of integers: "
input: .asciiz "Please enter an integer: "
toolow: .asciiz "A number greater than 0 is required."
plus: .asciiz "Result: "
.globl main
.text
# $s0: Number of Loops
# $s1: Current Value
main:
# CLEAR REGISTERS
li $s0, 0
li $s1, 0
# PROMPT NUMBER OF LOOPS
la $a0, number
li $v0, 4
syscall
# INPUT NUMBER OF LOOPS
li $v0, 5
syscall
move $s0, $v0
# CHECK NUMBER GREATER THAN ZERO
bgtz $s0, loop
# PRINT ERROR
la $a0, toolow
li $v0, 4
syscall
# EXIT
li $v0, 10
syscall
loop:
# PROMPT INTEGER
la $a0, input
li $v0, 4
syscall
# INPUT INTEGER
li $v0, 5
syscall
add $s1, $s1, $v0
# DECRIMENT LOOP
sub $s0, $s0, 1
# CHECK LOOP REMAINING
bgtz $s0, loop
# PROMPT RESULT
la $a0, plus
li $v0, 4
syscall
# PRINT RESULT
move $a0, $s1
li $v0, 1
syscall
# EXIT
li $v0, 10
syscall
# #define number "Number of integers: "
# #define input "Please enter an integer: "
# #define toolow "A number greater than 0 is required."
# #define plus "Result: "
#
# int s0;
# int s1;
#
# void main()
# {
# s0 = 0;
# s1 = 0;
#
# std::cout << number;
# std::cin >> s0;
#
# if(s0 > 0)
# loop();
#
# std::cout << toolow;
# }
#
# void loop()
# {
# std::cout << input;
# s1 = s1 + std::cin; // Not valid C++, but closest representation
#
# s0 = s0 - 1;
#
# if(s0 > 0)
# loop();
#
# exit();
# } - The safe variables need to be reset as they retain their values from one execution to the next (note: this is a feature of X/PCSPIM and does not occur in compiled applications). Thus, if you execute the program once and the resultant value in $v1 is 15, then run the program again with 2 integers of the values 3 and 4, then rather than the result being 7, it will be 22 (15 + 7). You do not need to reset the $v0 variable, but it was done here as a matter of completeness.
- The two safe variables were defined outside the main function in the C++ example. This is because the registers used by a program are available globally, whereas in C++ if they were defined inside the main function they would not be available in the loop function. As a result this isnt an exact translation of the MIPS code (in this one respect) but there is no other way to do it that translates any better.
- It works in exactly the same way except for the recursion. Note that in C++ you would do this using a loop (for example, for(int $i = 0; $i < $s0; $i++)).
- "sub" works in the same way as "add" by taking the subtraction of the third variable from the second and placing the result in the first.
- "bgtz" ("Branch If Greater Than Zero") will execute a function if a register is greater than 0. In this example it checks $s0 (which is set to the number of integers we would like to input). If this is equal to or less than zero in the first case, then an error is displayed and the program exits. If it's equal to zero in the second case, the resulting addition is printed and the program exits.
That's it! Like I said, these are extremely basic examples for people who are interested in learning a bit of assembly programming, and have some concept of registers and of the CPU. Post any questions, but please be patient for a reply while I'm doing my exams
Mike ¿
"Now I guess we're... 'Path-E-Tech Management'" -Dilbert
|