MIPS 101
Tags: Computer Architecture, MIPS, Programming
To truly understand how a computer (or rather, the processor) does what it does, I highly recommend trying out an assembly language. You might never need it in your professional life (unless you're an embedded coder, or when you're working with portable devices and need to use ARM NEON for example), but understanding assembly can give you more insight into the inner workings of a computer system and help you design better code in other programming languages.
Of course, it helps to have some nice tool which can help you visualise the computer registers and memory regions - enter SPIM.
SPIM is a MIPS architecture simulator. If there is one assembly language you should pick out of all of them, MIPS is probably the one. It is a simple to understand and concise assembly language, and SPIM gives you the ability to easily try it out on Windows, MacOS or Linux especially now that there is a Qt version.
So, when you're still reading this, let me give you a couple examples which can help you along exploring MIPS assembly - I've added the matching C code. Let's start with 'Hello World':
# # MIPS implementation of "Hello, World!" # # int main() { # printf("Hello, World!\n"); # return 0; # } # .text # the code section # # The main program. Execution starts here. # main: la $4 hello # get address of "Hello, World!" string li $2 4 # tell syscall that you want printf "%s" syscall li $2 10 syscall # exit # # Data for the main program - stored in the data segment (0x10000000). # .data # the data section hello: .asciiz "Hello, World!" # NUL-terminated ascii string
As you can see, the code consists out of two main sections, denoted by '.text' and '.data'. Programming logic goes into the '.text' section while the '.data' section is there for placing constants such as the null terminated string hello in the example. Everything after a '#' is a comment. The rest of the code consists of processor specific instructions such as 'la' (load address) and 'li' (load immediate) to put numbers and addresses into the CPU registers after which calculations can be done. In the example above, the number 4 in 'li $2 4' instructs the processor to put the number 4 into register 2 (indicated with a '$'). The number 4 in this case is an instruction used by SPIM internally to indicate that you want to print out a string.
The address of the string is loaded into register 4 using 'la $4 hello'. Register 4 should contain the address of the data you want to print out. Finally, calling 'syscall' will do just that: take the string pointed to by 'hello' and print it to a console. The number 10 that gets loaded in register 2 at the end, followed syscall, is to tell the simulator our program is over.
Go ahead, install SPIM and test it out! You don't have to compile anything for SPIM, just save the above in a textfile, open it up in SPIM and step through your code. Watch what happens in the register view!
The next one is a little longer. Again, I added the C code as reference.
# # MIPS implementation of: # # int main() { # int max, i; # # printf("Type in a small number: "); # scanf("%d" &max); # printf("Ok ... watch me count!\n"); # for (i = 1; i <= max; ++i){ # printf("%d " i); # printf("\n"); # } # return 0; # } # # Register allocations: max == $16 i == $17 # .text # the code section main: la $4 prompt li $2 4 # printf("Type in a small number: "); syscall li $2 5 syscall # scanf("%d" &max); move $16 $2 la $4 message li $2 4 # printf("Ok ... watch me count!\n"); syscall li $17 1 # i = 1; loop: # for(;;) { bgt $17 $16 done # if (i > max) break; move $4 $17 li $2 1 # printf("%d", i); syscall la $4 space li $2 4 # printf(" "); syscall add $17 $17 1 # i = i + 1; j loop # } done: la $4 newline li $2 4 # printf("\n"); syscall li $2 10 syscall # exit .data # the data section prompt: .asciiz "Type in a small number: " message: .asciiz "Ok ... watch me count!\n" space: .asciiz " " newline: .asciiz "\n"
You can find plenty of resources online on MIPS assembly, and don't forget the SPIM Manual.
Have fun!