|  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
- 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..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 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
- 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.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;
 # }
 
 - 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
- 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.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 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 |