2021/August 2021

COMPSYS 304 Assembly language (MIPS)

hajinny 2021. 8. 7. 23:28

MIPS is a register-register (load/save based) architecture instruction set. MIPS is very similar to other architectures like x86 and ARM, but different in that it follows RISC (fixed instruction bit encoding length). These instructions are simply 32-bits encoded bit-string that can be read by the CPU directly. If you've taken COMPSYS 201 (Introduction to Computer Engineering), you would know how register based operations can be done by Arithmetic Logic Unit in one cycle (you know, that quartz sending signal). You would also know that multiplexor can be used to make bytes-string to direct ALU to do certain operation with registers.

 

What happens within CPU is exactly that. CPU fetches byte-encoded instruction, and this gets fed into the multiplexor that selects an operation to perform. ALU within CPU will do that operation. This happens in one cycle for simple addition, subtraction, logical operations.

 

Anyways, I won't go into further explanations, because the reason why I sat down to write this post is not to explain the whole course of computer architecture, but to present practical approach to writing in assembly language. This post will hopefully be maintained, as I learn more about MIPS.

 

Basic structure of .asm code

#0 make sure you don't use $<number>
I had plenty of bugs because I used $3 where it should have been $t3. Remember to constrain yourself to temporary registers when you know that you have to use temporary registers. It's so easy to get memory out of bound errors because of using $<number>, which might contain some unexpected values, instead of the labelled ones.

Printing

Printing a simple string 

You declare a string (str1) in static .data section. la loads address of str1 to a0, which is necessary for print_string system call.

#1 
Syscall
 'print_string' requires address of string in a0

Printing a string of string array

Imagine you have an array of strings, and you want to print one string out of them. This is how you might do it:

str_table is an array of '.word'. Word is 32-bits, and by storing labels (str0, str1, str2,...) to each element in the array of words, each element in str_table stores addresses (each address being 32-bits).

 

Now, recall #1, where we determined that we simply need an address value of the string we want to print out to print it out. 

 

Above code finds 9th address stored in str_table, and prints it out. The following is the logic:

 

1. Load address of str_table into $t1. (using la)

2. Find address of 9th element in str_table

- this is simply $t1 + 4*9 (why 4? because 4 addresses make up one word)

- store that address into $t1

3. We want to load the 32-bit word stored in that address, which is the address to the str9.

- this is 'loading word' (lw)

- lw $t1 0($t1) does this.

 

Remembering #1 proves to be crucial here. Word is 32 bits. Each address addresses 8 bits. So word is 4 addresses.

 

Printing integer

 

#2 printing integer
How do we print a number?
Unlike with strings (#1), system call for printing integer will print the value of the integer stored in a0.
This is a very important distinction!

 

Looping

Looping through an integer array and printing each integer

Imagine we want to iterate through an array of 32 integers.

One thing to be cautious about here is this syntax:

This is one-dimensional array named 'array1'

This is not array of arrays.

 

Before we get started, note that the following is how I intend to go about this problem.

Here, we separated address index for the array from the loop index.

#3 Index convention to print each integer in the array
The following is the easiest convention to follow (for me) that allows for easy writing of the loop to print each integer in the array. 
t0: overall result (temp)
t1: static array index
t2: storing f(t1)
t3: loop index
t4: loop max

 

While loop index

To do something 32 times (as we have an array whose length is 32), we need an index variable and the upper bound to loop. (we want to do something like int i = 0, while(i<32){})

Index in this case is $t3, and the upper bound is $t4. 

 

To define "int i = 0, while(i<32){}" kind of structure, we need a body that will be looped.

This is the body to be looped. We immediately check if the exit condition is met (i == 32), in which case it should exit. This means that i from 0 to 31 will allow l1 to be executed, which is what we want.

 

Printing integer

Integer is 32 bits. So array of words (each word = 32 bits) is an array of ints. This array is 'array1' in our case.

What we want to do is to do array1[offset], where offset will grow from 0, to 4, 8, 12, .... 

 

Instead of defining offset to be offset = base + 4*i (as we did when we indexed into nth string of string array), we can choose to just load the base address and increment it by 4.

 

That's exactly what we are doing here. We firstly load the address of array1 into $t1:

Then we access the word at that address:

Then we print that:

Then we increment it every loop by adding 4 to $t1:

Well, that's not exactly in the order it's written in the code, but it's the same thing really.