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

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.

Related

Why am I getting a "program is finished running (dropped off bottom) error?

I'm not sure why this is giving me a dropped off error here. Anyone know how to fix this?
I'm trying to create a program that can convert between decimal, hexadecimal, and binary in MIPS. I'm supposed to request the input data type and the input data, and then request the output data type, and output the data. Any and all help is appreciated, thanks!
Code:
#Provide data variable and data as an input and output
.Data
Input1: .asciiz "Kindly enter the input X:"
Input2: .asciiz "Please provide the number system Y details:"
Output: .asciiz "\nThe result will be R:"
#starts global main
.Globl main
main:
addi $A0, $zero, 2
addi $A1, $zero, 15
#get the input value dropped by the user
getX:
li $M0, 4
la $N0, Input1
syscall
li $M0, 5
syscall
blt $M0, $zero, getX
move $K0, $M0
#get the value of the number system dropped by the user
getY:
li $M0, 4
la $N0, Input2
syscall
li $M0, 5
syscall
blt $M0, $A0, getY
bgt $M0, $A1, getY
add $K1, $zero, $M0
li $M0, 4
la $N0, Output
syscall
add $N0, $zero, $K0
add $N1, $zero, $K1
jal convert
li $M0, 15
syscall
#perform conversion over the respective input and number system
convert:
addi $sp, $sp, -16
sw $A3, 12($sp)
#Applying counter that is used to check that how many
#times values will be popped up from the stack
sw $A0, 8($sp)
sw $A1, 4($sp)
sw $ra, 0($sp)
add $A0, $zero, $N0
add $A1, $zero, $N1
beqz $A0, end
div $K4, $A0, $A1
rem $K3, $A0, $A1
add $sp, $sp, -4
sw $K3, 0($sp)
add $N0, $zero, $K4
add $N1, $zero, $A1
addi $A3, $A3, 1
jal convert
end:
lw $ra, 0($sp)
lw $A1, 4($sp)
lw $A0, 8($sp)
lw $A3, 12($sp)
beqz $A3, done
lw $N0, 16($sp)
li $M0, 1
syscall
#operation performed
done:
addi $sp, $sp, 20
jr $ra
#return to the main
li $v0, 10
syscall
I don't see you calling this so at the end of your done branch it doesn't end the system. Opcode 10 will do this for you in MIPS.
jal convert
li $M0, 15
syscall
#perform conversion over the respective input and number system
#your problem is here
convert:
addi $sp, $sp, -16
This is actually a pretty common mistake (we've all been guilty of it so no judgment here.) In assembly, a label simply existing does not prevent code from being executed. In order to have this code run the way you want, you need to insert the following.
jal convert
li $M0, 15
syscall
li $v0,10 #linux/mars/spim exit code
syscall #this is how you properly exit main and return to the OS
#thanks to the above, execution will not fall through to here anymore
#perform conversion over the respective input and number system
convert:
addi $sp, $sp, -16

MIPS: how can I apply the integer which users input into arithmetic function?

This is my first time coding PCSPIM. I find that there is a little trouble with my code.
.data
user_input: .asciiz "\n\nEnter an Integer for the value of n: "
result_display: .asciiz "\nThe sum from 0 to n is "
Greeting: .asciiz "\n\nThank you!"
.text
main:
#user input
li $v0, 4
la $a0, user_input
syscall
#allow user input
li $v0, 5
syscall
#store the input value into t8
move $t8, $v0
#calculation
addi $s0, $zero, $t8
I wish to use the integer value ($t8) that users input into the #calculation section, but it ends up with error.
addi $t0, $zero, 0
loop1:
add $t0, $t0, $s0
addi $s0, $s0, -1
bne $s0, $zero, loop1
nop
nop
# Display the result
li $v0, 4
la $a0, result_display
syscall
# Print out the result
li $v0, 1
move $a0, $t0
syscall
# Greets the user
li $v0, 4
la $a0, Greeting
syscall
# Exit the program
li $v0, 10
syscall
Sorry for my broken English.
The error is in the way you are using the "addi" instruction. The instruction requires an immediate (number) value to be passed as the third operand and not an architectural register. If you update the "addi" instruction to "addu" the code should work.

Mips function arguments and return values

I'm trying to make a hash table using mips assembly. My InsertKey function is for some reason not working correctly.The console just freezes with no error message when I try to use it.
InsertK:
li $v0, 4
la $a0, enterIntPrompt
syscall
li $v0, 5
syscall
move $a0, $v0 # key in a0
li $t0, 0
la $a1, Hash # table address in a1
bgt $a0, $t0, JInsertKey
li $v0, 4
la $a0, notInsertKeyMes
syscall
j whileloop
JInsertKey:
jal InsertKey
j whileloop
I suspect that I mess up with my passing values somewhere but I can't find anything. The textbook says it's good practice to use $v0-$v2 registers for return values of function calls and $a0-$a3 for function arguments.
This is the code calling to the InsertKey function:
InsertKey:
jal FindKey
move $t0, $v0 # position in t0
li $t1, -1
bne  $t0, $t1, prints
bgt $s1, $s0, dostuff
li $v0, 4
la $a0, hashTableFullMes
syscall
jr $ra
dostuff:
jal HashFunction
move $t0, $v0
li $t3, 4
multu $t0, $t3
mflo $t3
la $a1, Hash
add $a1, $a1, $t3 # a1 adress hash[position]
sw $a0, ($a1)
addi $s0,1
jr $ra
prints:
li $v0, 4
la $a0, keyAlreadyInTableMes
syscall
jr $ra
FindKey and HashFunction are working properly. Can someone identify the problem with this code? I am really out of ideas..
Edit: Findkey returns the position of the key found else -1.
InsertKey:
jal FindKey
The above causes $ra for InsertKey to be overwritten with the address of InsertKey + 8, so when InsertKey returns, it returns to itself, instead of its caller.
You need to save return address and arguments for InsertKey before it calls any other functions.

A nested function in MIPS

My code has two parts; the first part is making a function that takes in two numbers and return their products. I believe I did this part right.
The second part is where I'm not sure what's the problem is. In this part I need to make a function that find the factorial number, and within this function, I have to use the multiplication function which I made in the first part. Please have a look at my code and tell me what am I doing wrong.
.data
Fa_message: .asciiz "\nFAIL TEST\n"
Pa_message: .asciiz "\nPASS TEST\n"
number1: .word 4
number2: .word 5
KnownAnswers: .word 20
START: .word 16
.text
main:
# taking in the numbers for calculation.
lw $a0, number1 # $a0 =4
lw $a1, number2 # $a1 =5
lw $t0, KnownAnswers # $t0 =20
jal func_multiply # calling the mulyiply function
move $t4,$v0 # store the product for any further comparisons
bne $t0, $t4, FailT # did it fail the test?
beq $t0, $t4, PassT # did it pass the test?
func_multiply: # the mulyiply function
mul $v0, $a0, $a1 # $v0 = number1 * number2
jr $ra
FailT: # print "\nFAIL TEST\n"
li $v0,4
la $a0, Fa_message
syscall
PassT: # print "\nPASS TEST\n"
li $v0,4
la $a0, Pa_message
syscall
###---------------------(PART-2)-------------------
lw $a0, number1 # load the number for the factorial procedure
beq $a0, $zero, factorialDone # (if the number = 0), !0 = 1
mul $a1, $a1, $zero # initializing $a1
mul $a2, $a1, $zero # initializing $a2
addi $a1, $a0, -1 # $a1 = (the entered number - 1)
addi $a2, $a0, 0 # $a2 = the entered number
jal findfactorial
###
#Stop
li $v0, 10
syscall
findfactorial:
jal func_multiply # calling the mulyiply function # mul $v0, $a0, $a1 # $v0 = number1 * number2
move $t4,$v0 # store the product in t4 for any further usage
addi $a0, $a0, -1 # $a1 = $a1-1
addi $a1, $a0, -1
bne $a1, $zero, findfactorial # enter a loop if $a1 does not equal 0
jr $ra
factorialDone:
addi $v0, $v0, 1
syscall
The jal instruction modifies the $ra register. So if function A calls a function B, then A has to save and restore the value that $ra had when entering A so that it can return to the correct place. This is typically done using the stack as temporary storage.
You can push a register on the stack (save it) like this:
addi $sp, $sp, -4
sw $ra, ($sp)
And pop a register off the stack (restore it) like this:
lw $ra, ($sp)
addi $sp, $sp, 4
Then there's your findfactorial loop. You're discarding the result of all the previous iterations, so your result will always be 1*2 == 2. The loop ought to look something like this:
findfactorial:
jal func_multiply
move $a0,$v0
addi $a1, $a1, -1
bne $a1, $zero, findfactorial
This way you first multiply 4 by 3, then 12 by 2, etc.
There are some other isues in your code. For example, if you jump to FailT you don't immediately exit the program after printing the message - you just keep executing the code after PassT.
Also I'm not sure what this is supposed to do:
factorialDone:
addi $v0, $v0, 1
syscall
If you wanted to execute syscall 1 (print_int), then this is incorrect because it doesn't set up $v0 properly (it should be li $v0,1). And if you wanted this to print the result of your factorial computation then that's not going to happen, because you have a jr $ra right before that, so the only time you end up at factorialDone is if number1 contained 0. Also, you'd have to set up $a0 with the value you want to print.

MIPS, Recursion

I trying to write a MIPS program that gets an unsigned integer as argument and returns the sum of all decimal digits in the integer recursively. For example if the argument is 75080 then the sum to be returned is 20 (7+5+0+8+0). Here is my code so far. Any help would be appreciated.
My way of thinking was to divide the number by 10 leaving me with the last integer in the number, add the reminder using mfhi.
.data
prompt: .asciiz "Enter a string of integer: "
output: .asciiz "\nThe total sum is: "
.text
.globl main
main:
la $a0, prompt
li $v0, 4
syscall
li $v0, 5
syscall
move $t2, $v0
la $a0, output
li $v0, 4
syscall
Loop:
div $t2, $t2, 10
mflo, $t1
mfhi, $t3
beqz $t1, Exit
add $t1, $t1, 0
b additive
additive:
add $t0, $t1, $t1
j Loop
Exit:
la $a0, output
li $v0, 4
syscall
la $v0, 10
syscall
What's this supposed to be doing? Adding 0 to the register won't change its value:
add $t1, $t1, 0
After dividing and copying to $t1 and $t3, the quotient is in $t1 and the remainder is in $t3. You're treating it the other way around when you add to the total.
This is actually going to give you $t0 = 2 * $t1: you're adding $t1 to itself and storing the result in $t0.
add $t0, $t1, $t1
You probably actually want:
add $t0, $t0, $t3
You're checking for $t1 == 0 before adding the remainder to the total, so the most significant digit will never get added. You don't really need a subroutine for adding to the total either. You can also use bnez Loop instead of beqz Exit -> b Loop. Lastly, you don't even need $t1, because the quotient is already in $t2.
Get rid of additive and replace Loop with this:
Loop:
div $t2, $t2, 10
mfhi, $t3
add $t0, $t0, $t3
bnez $t2, Loop
Your Exit is weird: you're printing the output string a second time instead of printing the integer.
Change it to this:
Exit:
move $a0, $t0
la $v0, 1
syscall
la $v0, 10
syscall
The approach is quite simple. You need recursive function, I named it SumDigits that will take the last digit and repeat procedure for all digits in the argument. After the recursive call returns you'll add digit to the previous result. The code is commented for easier understanding. The code follows:
.text
#calculates sum of digits recursively
SumDigits:
sub $sp, $sp, 12 #alloocate 12B on stack
sw $ra 0($sp) #save return address
sw $a0, 4($sp) #save argument
beq $a0, $0, exit_sumdigits #when there is no more digits return 0
rem $t0, $a0, 10 #get last digit
sw $t0, 8($sp) #save it on stack
div $a0, $a0, 10 #divide argument by 10
jal SumDigits #repeat procedure
lw $t0, 8($sp) #read digit from stack
add $v0, $v0, $t0 #add digit to previous result
lw $ra, 0($sp) #load return address
addi $sp, $sp, 12 #free stack
jr $ra #return
exit_sumdigits:
li $v0, 0 #there are no more digits, return 0
lw $ra, 0($sp) #load return address
addi $sp, $sp, 12 #free stack
jr $ra #return
main:
li $a0, 75080 #load number in $a0
jal SumDigits #call SumDigits
move $a0, $v0 #set a0 = result of SumDigits
li $v0, 1 #set $v0 for print int system call
syscall
li $v0, 10 #set $v0 for exit system call
syscall
.data