How do I use multiple arguments in a mips assembly function? - function

I am reading in two integers, the first must be between 1 and 7. The second must be between 1 and 7, and not less than the first. To check these number I am using a function and then returning either 1 or 0, which will repeat the input in a loop until a valid input is given.
Here is my problem: The first number seems to go in well, and it loops until a valid input is given. However for my second function, it's pretty much the same but I am using two arguments ($a0 for the first number and $a1 for the second). Whenever I run the program on QTSpim, it freezes immediately after entering the second integer. Can anyone help me?
Here is my code:
main:
li $v0,5
syscall
move $a0,$v0
jal checkdiv
move $s0,$a0
slt $t0,$zero,$v1
beq $t0,$zero,NE
j main
NE:
li $v0,5
syscall
move $a0,$v0
move $a1,$s0
jal checknum
#These are the two check functions
checkdiv:
addiu $sp,$sp,-8
sw $ra,4($sp)
sw $a0,0($sp)
li $t0,1
slt $v1,$a0,$t0
beq $v1,$t0,D1
li $t0,7
slt $v1,$t0,$a0
D1:
lw $ra,4($sp)
lw $a0,0($sp)
addiu $sp,$sp,8
jr $ra
#Second check function
checknum:
addiu $sp,$sp,-16
sw $ra,8($sp)
sw $a0,4($sp)
sw $a1,0($sp)
slt $v1,$a0,$a1
li $t0,1
beq $v1,$t0,N1
li $t0,7
slt $v1,$t0,$a0
N1: lw $ra,8($sp)
lw $a0,4($sp)
lw $a1,0($sp)
addiu $sp,$sp,16
jr $ra

Related

MIPS "fetch address not aligned on word boundary" error on l.s instruction

I've read through some Q&As about this error on here, but I still don't understand what it means. I have a code in which I try to calculate p(n, r) and I keep getting this error: "line 26: Runtime exception at 0x00400044: fetch address not aligned on word boundary 0x00000006". I don't understand how it's not aligned since to my own knowledge, I haven't manipulated the address.
# n and r are assumed to be integers and n > r
.data
textN: .asciiz "enter n: "
textR: .asciiz "enter r: "
.text
main:
li $v0, 4
la $a0, textN
syscall
li $v0, 6
syscall
move $t0, $v0
li $v0, 4
la $a0, textR
syscall
li $v0, 5
syscall
move $t1, $v0
move $a0, $t0
jal Factorial
la $t7, ($v0)
l.s $f0, ($t7) #line 26
sub $a0, $t0, $t1
jal Factorial
la $t7, ($v0)
l.s $f1, ($t7)
div.s $f12, $f0, $f1
li $v0, 2
syscall
jr $ra
Factorial:
beq $a0, 1, Exception
subi $sp, $sp, 8
sw $t0, ($sp)
sw $t1, 4($sp)
move $t0, $a0
move $v0, $a0
Loop:
subi $t0, $t0, 1
beq $t0, $zero, Exit
sub $t1, $a0, $t0
mul $v0, $v0, $t1
Exit:
lw $t0, ($sp)
lw $t1, 4($sp)
addi $sp, $sp, 8
jr $ra
Exception:
addi $v0, $v0, 1
jr $ra
At first, I hadn't included the la instruction and line 26 was l.s $f0, ($v0). I assumed that the current update to line 26 and 27 was what was missing, but the error I'm receiving has remained unchanged.
I think you're a bit confused about what parentheses really mean.
li $t0,8
move $t1,$t0 ;copy the number 8 from $t0 into $t1.
lw $t2,($t0) ;load the four bytes at memory address 0x00000008 into $t2
Essentially, parentheses around a register are the pointer star * in C, and la $t0, myLabel is the same as typename* ptr = &myLabel;. (I used li in the example above because a memory address is a number itself, but that's not usually what you would do if you really were dereferencing a pointer.)
Your function factorial is intended to return an int, so you don't want to dereference that value. Assembly has no type safety at all, and lets you treat any register as a pointer to memory at any time.
The actual source of your error message, however, has to do with a limitation of the MIPS CPU. Your input value for the factorial function was 3, right? I could tell by the error message. Rather than trying to copy the number 6 to $f1 (which wouldn't work for other reasons) you were trying to load the 4 bytes at memory address 0x00000006. This won't work, because MIPS can't use lw or sw to read/write 32-bit values at memory addresses that aren't aligned, i.e. not a multiple of 4. Trying to do so will result in a runtime error. But it's clear that's not what you wanted to do anyway.

MIPS: Infinite loop with branches

So I have a program that takes an input from the user (integer above 0) and adds up all even numbers below it to achieve a return answer (Ex: input: 7; ans: 2 + 4 + 6 = 12).
The issue with this program is that it's meant to break out of the loop based on if my 'active even variable' ($t1) > the input. Although my program never seems to properly interpret the branch and loops indefinitely until $t1 overflows (I have checked the debugger and know that the program does run the branch line every time). Below is my code:
.data
N: .word 0
Result: .word 0
.text
.globl main
initialize:
li $v0, 5 #getting arg1 from user
syscall
la $t0, N
sw $v0, 0($t0)
li $t1, 2
li $t2, 0
main:
blt $t0, $t1, fin2
fori:
add $t2, $t2, $t1 #t2 += t1
add $t1, $t1, 2 #t1 += 2
slt $t5, $t1, $t0
bne $t5, $zero, fori
fin:
li $v0,1 #prints return value
move $a0, $t2
syscall
li $v0, 10
syscall
fin2:
li $v0,1 #prints return value
move $a0, $zero
syscall
li $v0, 10
syscall
So I don't know if you NEED to be using word storage and such, but really you were just over complicating it in doing so. All you needed was a simple loop which has a counter that increments by 2, checks if it is larger than the initial value, and then add that overall value to the result
.text
.globl main
initialize:
li $v0, 5 # Getting arg1 from user
syscall # System call
move $t0, $v0 # Store the input value in $t0
li $t1, 0 # Initializing the result register
li $t2, 0 # Initializing the addition/counter register
main:
loop:
add $t2, $t2, 2 # Increase the value to be added by 2 (next even value)
bge $t2, $t0, fin # Check if the increment is larger than or equal to the initial input, if so break to finish
add $t1, $t1, $t2 # Increment the result by adding the even value
j loop # jump bak to the top of the loop
fin:
li $v0,1 # let the system know an integer is going to be printed
move $a0, $t1 # Load the result into the $a0 register (the register that prints values)
syscall # System Call
li $v0, 10 # Let the system know the program is going to exit
syscall # System Call
So as you can see $t2 increments by 2 each time. After each increment it is compared to the input value. If the input ($t0) than $t2 then add the value of $t2 to the result ($t1). This way there is an increment counter which is also used to add the necessary even value to the result.
Edit:
Not sure if this is entirely what you meant but I just tossed in some loads and saves, using the s registers as those are the register that are supposed to be used when saving values.
.data
N: .word 0
Result: .word 0
.text
.globl main
initialize:
li $v0, 5 # Getting arg1 from user
syscall # System Call
la $s0, N # Load the address of N into $s0
sw $v0, 0($s0) # Store the input value in 0 index of N
li $t2, 0 # Initializing the addition/counter register
la $s1, Result # Load the address of Result into $s1
main:
sw $t2, 0($s1) # Setting the 0 index of Result to 0
loop:
add $t2, $t2, 2 # Increase the value to be added by 2 (next even value)
lw $t4, 0($s0) # Loading the input value into the $t4 register
bge $t2, $t4, fin # Check if the increment is larger than or equal to the initial input, if so break to finish
lw $t4, 0($s1) # Loading the current result into the $t4 register
add $t4, $t4, $t2 # Increment the result by adding the even value
sw $t4, 0($s1) # Saving the new current result into the $t4 register
j loop # jump bak to the top of the loop
fin:
li $v0,1 # let the system know an integer is going to be printed
lw $a0, 0($s1) # Load the result into the $a0 register (the register that prints values)
syscall # System Call
li $v0, 10 # Let the system know the program is going to exit
syscall # System Call

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.

jal mips not doing anything

my goal is to swap the values in the swap: function
however it's not doing anything.
i set the values of a0 and a1 to whatever and it doesn't overwrite their values.
i am not allowed to use t0, I have to use the stack.
still, why isn't it doing anything to a0 and a1, do I have to return something in v0?
.text
main:
la $a0,n1
la $a1,n2
jal swap
li $v0,1 # print n1 and n2; should be 27 and 14
lw $a0,n1
syscall
li $v0,11
li $a0,' '
syscall
li $v0,1
lw $a0,n2
syscall
li $v0,11
li $a0,'\n'
syscall
li $v0,10 # exit
syscall
swap:
addi $sp, $sp, -4
sw $a0, 0($sp)
addi $a0, $a1, 0
lw $a1, 0($sp)
addi $sp, $sp, 4
jr $ra
L1:
.data
n1: .word 14
n2: .word 27
You're swapping pointers, not the values they point to. And when you print the values you read them directly from n1 and n2 instead of through the pointers you swapped.
To fix this you could:
Load the values of n1 and n2 (rather than their addresses) before calling swap. Then print $a0 and $a1 afterwards, instead of re-loading the values from n1 and n2.
Dereference the pointers inside swap in order to actually swap the values.
Dereference the pointers before doing the print_int syscall, instead of reading the values to print directly from n1 and n2.
The first solution would be the easiest.

Mips translating problems

I am having trouble translating this pseudo code to mips assembly i have added the registers i am using to help understand what is going on
# if (n == 1)
# return 1
# else if (n == 2)
# return 6
# else
# return 2*hex(n-1) - hex(n-2) + 4
# (hex) Registers:
# $a0 - n, the argument
# $v0 - the result the n-th Hexamorphic number
# $t0 - holds hex(n-2)
# $t1 - holds constants 1
# $t2 - holds constant 2
here is where i am at in my code i feel confident about hex: and elseif: but the else: is where the problem starts
hex: bne $a0,$t1,elseif #if n==1
li $t1,1
li $t2,2
li $v0,1
jr $ra #retu
elseif: bne $a0, $t2,else
li $v0,6
jr $ra
else: addi $sp,$sp,-12
sw $ra,$ra 0($sp)
addi $t3,$a0,-1
sll $t3, $t2,1
sw $a0,$a0,4($sp)
sw $t3,8($sp)
lw $ra
lw $a0
addi $t3,4
sub $t4,$t3,$t0
lw $t4
sw $v0,$t4
lw $ra
lw $a0
j $ra
You have some instructions wrong (sw, lw, addi and j). The definitions of these intstructions can be found in the MIPS32 instruction set quick reference.
You're on the right track in the else block. What you want to do is save all the values (on the stack) that you want to be preserved throughout your recursive calls. jal to hex (n - 1), save it on the stack and jal to hex again (n - 2). Then load up all values, do the calculations on them and jr ra. Do not forget to restore $sp before returning. When using jal, remember the branch delay:
jal hex
The instruction here will be run "together" with jal, before taking the branch.
ra will point here
The jr $ra in elseif will run addi $sp,$sp,-12 due to branch delay. This is not good.