What is a function/How to distinguish a function in MIPS? - function

Extremely new to MIPs assembly language -- I haven't been able to find a link that specifically tells you what a function is distinguished as in MIPS, examples of how we use jal, jr, etc..
It's very difficult to find out how these actions work -- My text book for this section of the course is very broad and assumes I already know the language and just outlines a code (under the assumption that I know exactly what the code means)
Hence, the book isn't helping me so I'm trying to practice on my own..
Anywho, in my class we wrote a simple array code which supposedly has a "function" in it.
My question is -- how do I know what is the "function"
Below is a code we did in class -- it's supposed to output an array from 1 to 10.. I understand where it increments and such (addi) and why it's a 1 and 4 but I don't understand
what $ra, jal , jr mean... but I'm assuming that these have something to do with what a "function" is
#Load an array and display
.data
.align 2
a1: .space 40
.text
.globl main
main:
la $s0, a1
jal loadArray
la $s0, a1# <- return here after function return
jal displayArray
# <- return here after 2nd function
exit:
li $v0, 10
syscall
displayArray:
#$ra = the address of line 14
li $t0, 1 #int i = 0
displayLoop: blt $t0, 11, display
#else
jr $ra
display:
lw $t0, ($s0) # a1[i] = i;
li $v0, 1
move $a0, $t0
syscall
#incremment i and array pointer
addi $t0, $t0, 1
addi $s0, $s0, 4
j displayLoop
loadArray:
#$ra = the address of line 14
li $t0, 1 #int i = 0
loadLoop: blt $t0, 11, load
#else
jr $ra
load:
sw $t0, ($s0) # a1[i] = i;
#incremment i and array pointer
addi $t0, $t0, 1
addi $s0, $s0, 4
j loadLoop
So this is the sample code but the only difference between this code and a usual code with just labels is the jump register and jump and link...
Does that distinguish what is a function???
Sorry for the long wall of text -- TL;DR In MIPS, how do you know what is a "function" I know what a label is (obv.) but not a function...
This isn't as straight forward to me as it is in cpp or java lol.

A function (or subroutine) is really just any piece of code that you can call (with jal) and expect to return to you (with jr $ra). It is also generally expected to keep your stack and registers intact across the call.
The term function is used more often by high-level languages like C, whereas subroutine is more common at the assembly-language level.
jal means "Jump And Link" - I would expect this to be covered in your textbook. This instruction 1) stores the return address (the address of the instruction after the jal) in $ra, the link register (or return address register) and then 2) jumps to the target address. This is how you call a function.
When the function is finished, it returns to the caller by jumping to the address in the return address register, with the jr $ra instruction (Jump to Register $ra).
Your comments imply that you already understand this:
jal loadArray
la $s0, a1# <- return here after function return
jal displayArray
# <- return here after 2nd function
So loadArray can be considered a function, as can displayArray.
Read more:
Subroutines/Functions in MIPS
MIPS Quick Tutorial
MIPS Instruction Reference
MIPS Assembly/Control Flow Instructions
jal and jr

Related

Can anyone tell what mistake i'm doing in this MIPS code?

.data
array: .space 10
prompt: .asciiz "Enter an integer (0 to quit) :"
text: .asciiz "After sorting, the list of integers is:"
.text
.globl main
main:
la $a1, array
read_numbers:
# Rest of code omitted for brevity...
beqz $v0, sort
j read_numbers
sort:
la $a1, $array
li $v0, 4
la $a0, text
syscall
loop:
lw $t0, 0($a1)
addiu $a1, $a1, 4
beqz $t0, done
li $v0, 1
move $a0, $t0
syscall
j loop
Assuming that the code above is formatted correctly in the file rather than all on one line, and ignoring that you are missing code at
# Rest of code omitted for brevity
And ignoring that you haven't said what it is supposed to do, or what it does do ….
The first thing I see if that you are branching in main:
read_numbers: # Rest of code omitted for brevity...
beqz $v0, sort
j read_numbers
But since you didn't set v0 to anything, it is set to whatever value it was set to before your code (and when I go to run it, non zero)
So, it never branched to the sort routine, and jumps to read_numbers and does an endless loop.
If it was in the 'sort', it will grab the first number from array, which is 0 (unless you had populated the array somehow), see that it was 0 and attempt to branch to 'done' which also isn't in your code.

Self-Modifying MIPS Code

I'm trying to write a program in MIPS that continuously prompts for two integers and prints the sum until the sum is 0. The trick is that if the sum is 13, I need to call a method to change the assembled MIPS code so that
add $t2, $t0, $t1
becomes
and $t2, $t0, $t1
and all subsequent runs of the loop use the and instruction.
I have the summation loop working so that when 13 is the sum the method instMod is called which I want to modify the instruction. Unfortunately, I have no idea where to start and can't find any examples of this online. I assume I need to somehow get the hex code of the add out of the assembled code and replace it with the hex code for the and but I do not know how to do that or if that is the right course of action to take.
# Nick Gilbert
# MIPS Program to demonstrate self-modifying code
.data
num1Prompt: .asciiz "Enter num1: "
num2Prompt: .asciiz "Enter num2: "
num1: .word 0
num2: .word 0
addOut: .asciiz "ADD: "
andOut: .asciiz "AND: "
.text
main:
sumLoop:
la $a0, num1Prompt #Asking user for num1
li $v0, 4 #Call code to print string
syscall
li $v0, 5 #Call code to read an int
syscall
move $t0, $v0 #Moving read int to $t1
la $a0, num2Prompt #Asking user for num2
li $v0, 4 #Call code to print string
syscall
li $v0, 5 #Call code to read an int
syscall
move $t1, $v0 #Moving read int to $t2
add $t2, $t0, $t1 #Adding num1 and num2 together
la $a0, addOut
li $v0, 4
syscall
move $a0, $t2
li $v0, 1
syscall
beq $t2, 13, instMod #Calling method to modify add instruction if sum = 13
bne $t2, 0, sumLoop #If result is not yet 0, ask for new sum
endSumLoop:
li $v0, 10
syscall
instMod: #Method to change add instruction to an and instruction
Add a label at the instruction you want to replace, e.g:
instruction_to_be_replaced:
add $t2, $t0, $t1 #Adding num1 and num2 together
then in your routine instMod
instMod: #Method to change add instruction to an and instruction
lw $t1, instruction_to_replace
sw $t1, instruction_to_be_replaced
j sumLoop # go back to your sumLooop
instruction_to_replace:
and $t2, $t0, $t1
The code loads in temporary register $t1 the contents of the instruction you want to replace, and then stores it in the location labelled instruction_to_be_replaced.
The "source" of the instruction goes labelled in instruction_to_replace.
To do this, you need to be able to write on the code section which I assume you have otherwise you would not be asking this question.
Try this:
Assemble the instruction that you need to an object file
Extract the hexadecimal of the equivalent machine code
Place a label in front of the code you need to change
mov the hexidecimal from step 2 into the location from step 3 in your instMod section
For this to function the two instructions with operands must be of identical length. If they are not, pad the original or the replacement with nop as appropriate.

How do I return a value from the main function in MIPS?

Say I want to write the following C program in MIPS:
int main () {
return 5;
}
When I try the following MIPS code in MARS:
main: ADDI $v0, $zero, 5 # $v0 = 5
JR $ra # return from main()
I get a 'invalid program counter' error. This is apparently because you cannot jump out of the main function in MARS. So I tried rewriting it like so:
main: ADDI $v0, $zero, 5 # $v0 = 5
li $v0, 10 # load 10(exit) for syscall
syscall # exit
After executing this, the $v0 register contains the value 10, not 5. Which is understandable since I had to overwrite the $v0 register in order for syscall to work. My question, then, is where would I save the value 5 in order for it to be returned to the caller of this application correctly?
Use syscall 17:
exit2 (terminate with value)
----------------------------
$v0 = 17
$a0 = termination result
Note that "If the MIPS program is run under control of the MARS graphical interface (GUI), the exit code in $a0 is ignored."

displaying the factorial of each value of the index of a loop does not work. MIPS

I am trying to display the factorial of the current value of the index of a loop in MIPS but, my loop does not work at all. It keeps freezing every time I run the code. Let say I have a for loop such that (i=1; i<=5; i++), for each value of i, I would like to display the current factorial(i). The number 5, is actually provided by the user, in other words, the number can change(1-10). I have tried to figure out why my loop causes the code to freeze, but I have no clues so far. Your help will be very appreciated. The code is bellow.
.data # data declaration section; specifies values to be stored
# in memory and labels whereby the values are accessed
Prompt: .asciiz "\nEnter the number to compute the factorial:\n"
message: .asciiz "\nResult of computation is:\n"
result: .word 0
#--------------------------------
# main function |
#--------------------------------
.text # Start of code section
.globl main
main: # Execution begins at label "main". The prompt is displayed.
li $v0, 4 # system call code for printing string = 4
la $a0, Prompt # load address of string to be printed into $a0
syscall # call operating system to perform operation;
# $v0 specifies the system function called;
# syscall takes $v0 (and opt arguments)
# Read integer N
li $v0, 5
syscall
move $t0, $v0 #copy integer N into $t0
li $t1, 1 #initialize i=1
loop:
blt $t0, $t1, exit_loop # if number<1, exit...
move $a0, $t0 # copy N into $ao
jal fact #else call fact
sw $v0, result
li $v0, 4 #Display message
la $a0, message
syscall
li $v0, 1 #print result
lw $a0, result
syscall
sub $t0, $t0, 1 #Decrement N by one, N--
j loop
exit_loop:
jr $ra #return address
exit: #exit the program
li $v0, 10
syscall
.globl fact
.ent fact
fact:
subu $sp, $sp, 8
sw $ra, ($sp)
sw $s0, 4($sp)
li $v0, 1 #check base case
beq $a0, 0, end_fact
move $s0, $a0 #fact(n-1)
sub $a0, $a0, 1
jal fact
mul $v0, $s0, $v0 #n*fact(n-1)
end_fact:
lw $ra ($sp)
lw $s0, 4($sp)
addu $sp,$sp, 8
jr $ra
#end of factorial function
Your problem is in the instruction at exit_loop label:
exit_loop:
jr $ra #return address
You are jumping again into the loop because you haven't saved $ra at the start of your main function and you are also not restoring it before issuing that jr
In fact, your code, as is, should just terminate (syscall 10) and not issue a jump because you are implementing the main function and not a function to be called from elsewhere.
So, i'd change that code to:
exit_loop:
li $v0, 10
syscall
Looking a bit more into your code, you already have that code (on label exit), so you might just remove your exit_loop code and branch to exit instead of exit_loop in the branch that goes just after loop label.

Restoring registers in MIPS

In the following section of MIPS code, I have to say what registers must be saved during the prologue, and then restored later. I found some including:
$ra, $a0, and $v0
But does anything thats non-obvious also have to be saved/restored, such as $sp or $fp? Thanks.
func: #insert function prologue here
bne $a0, $0, else
addi $v0, $0, 1
j ret
else:
srl $a0, $a0, 1
jal func
addi $v0, $v0, 1
ret: #insert function epilogue here
jr $ra
I'm assuming that $a0 is an input argument to the function and that $v0 is the function's return value.
These registers don't need to be saved and restored, because they will be used/modified.
Your function is recursive so you'll want to save and restore the return address $ra. You don't have to save and restore any registers that you either don't modify or that you leave the function with them in the same state as when the function is entered. In this case, $sp will probably be modified (by you), but you'll restore its previous value before returning.