I have been trying to implement a floating-point function in Assembly MIPS 32-bits, and I have not been able to pinpoint the exact fault. It seems to be in the mul.s $fd, $fsrc1, $fsrc2 command, since the contents of the specific floating-point register remain unchanged (I have checked this with syscalls as well, printing the contents in each case) but I seem to be unable to find the fix. Anyone got any ideas? Full code below:
.align 2
.data
number: .float 0.5
.text
.globl main
main:
li $a0, 3
l.s $f12, number
jal power
li $v0, 2
mtc1 $a0, $f0
syscall
li $v0, 17
syscall
power:
#Build stack
subu $sp,$sp,56 # Stack frame is 56 bytes long
sw $a0, 12($sp) # Save Argument 0 ($a0)
swc1 $f12, 8($sp) # Save Argument 1 ($a1) (integer arg)
sw $s0, 56($sp) # Save $s0
sw $s1, 52($sp) # Save $s1
swc1 $f20, 48($sp) # Save $f20
swc1 $f21, 44($sp) # Save $f21
sw $ra, 16($sp) # Save return address
sw $fp, 20($sp) # Save frame pointer
addiu $fp, $sp, 52
#-----------------------------------------------------------------------#
move $s0, $a0 #stores value of n
mov.s $f22, $f12 #stores value of x
li $s1, 0 #initialize counter with 0
powerLoop:
mul.s $f20, $f20, $f20 #y=y*y
addi $s1, $s1, 1 #increase counter
bgtu $s0, $s1, powerLoop #continue loop as long as counter<n
mov.s $f0, $f20 #return the results
#-----------------------------------------------------------------------#
#Pop stack
lw $a0, 12($sp) #Load back $a0
lwc1 $f12, 8($sp) #Load back $f12
lw $s0, 56($sp) # Load $s0
lw $s1, 52($sp) # Load $s1
lwc1 $f20, 48($sp) # Load $f20
lwc1 $f21, 44($sp) # Load $f21
lw $ra, 16($sp) # Restore old value of $ra
lw $fp, 20($sp) # Restore old value of $fp
addiu $sp, $sp, 56 # Pop stack
jr $ra
SOLVED:
Despite some errors in registers, the main error is in the
li $v0, 2
mtc1 $a0, $f0
syscall
FIX:
li $v0, 2
mov.s $f12, $f0
syscall
REASON: $f12 IS ALWAYS, due to convention, the floating-point argument, even for syscalls. It will not print the contents of $a0 but rather $f12!
Related
I'm writing a function that should return the square root of a perfect square recursively as part of a longer assignment.
I was following this mathematical method before I reverted to an even simpler algorithm to see if the error would repeat itself and it did.
The following code:
.data
prompt: .asciiz "num2sqrt: "
.text
.globl main
sqrt:
# save return address & t0
addi $sp, $sp, -8
sw $ra, 0($sp)
sw $t0, 4($sp)
# t0 = n
move $t0, $a0
# a0 = n/2
srl $a0, $t0, 1
jal sqrtRecursor
#restore return address & t0
lw $t0, 4 ($sp)
lw $ra, 0 ($sp)
addi $sp, $sp, 8
jr $ra
sqrtRecursor:
# save return address & t1
addi $sp, $sp, -8
sw $ra, 0($sp)
sw $t1, 4($sp)
# square test
mult $a0, $a0
mflo $t1
beq $t1, $t0, returnAnswer
bne $t1, $t0, newGuess
#restore return address & t1
lw $t1, 4 ($sp)
lw $ra, 0 ($sp)
addi $sp, $sp, 8
jr $ra
returnAnswer:
move $v0, $a0
newGuess:
# t1 = (((x+1)*guess)/x)/2
# x+1
addi $t1, $t0, 1
# *guess
mult $a0, $t1
mflo $t1
# /x
div $t1, $t0
mflo $t1
# /2
srl $t1, $t1, 1
move $a0, $t1
jal sqrtRecursor
main:
#print "Enter num2sqrt: "
la $a0, prompt
li $v0, 4
syscall
#input num2sqrt
li $v0, 5
syscall
move $s1, $v0
move $a0, $s1
jal sqrt
# print result
move $a0, $v0
li $v0, 1
syscall
# end
li $v0, 10
syscall
returns the following error on QTSpim:
Can't expand stack segment by 12 bytes to 524288 bytes. Use -lstack # with # > 524288
which then hangs the app for a minute or so.
I've double checked that I'm saving and returning all my return addresses and used variables, and also attempted implementing the same algorithm in Java separately (which worked), but have yet been unable to figure out what I need to fix and where.
I've been able to implement a power function before this so I'm not a complete novice and am asking after putting in approximately 5 hours of research and debugging on this.
It could be a stack management problem or an if/else implementation error from the intuition I have about my own code.
.data
n1:.asciiz"Enter the first number:"
n2: .asciiz"Enter the second number:"
.text
.globl main
main:
li $v0,4
la $a0,n1
syscall
li $v0, 5 # get input from user
syscall
move $a0,$s0
li $v0,4
la $a0,n2
syscall
li $v0, 5 # get second input from user
syscall
move $a0,$s1
jal calcGCD # call function calcGCD
add $a0,$v0,$zero
li $v0,1
syscall # print result
li $v0, 10 # exit program
syscall
calcGCD:
#GCD(n1, n2)
# n1 = $a0
# n2 = $a1
addi $sp, $sp, -12
sw $ra, 0($sp) # save function into stack
sw $s0, 4($sp) # save value $s0 into stack
sw $s1, 8($sp) # save value $s1 into stack
add $s0, $a0, $zero # s0 = a0 ( value n1 )
add $s1, $a1, $zero # s1 = a1 ( value n2 )
addi $t1, $zero, 0 # $t1 = 0
beq $s1, $t1, return # if s1 == 0 return
add $a0, $zero, $s1 # make a0 = $s1
div $s0, $s1 # n1/n2
mfhi $a1 # reminder of n1/n2 which is equal to n1%n2
jal calcGCD
exitGCD:
lw $ra, 0 ($sp) # read registers from stack
lw $s0, 4 ($sp)
lw $s1, 8 ($sp)
addi $sp,$sp , 12 # bring back stack pointer
jr $ra
return:
add $v0, $zero, $s0 # return $v0 = $s0 ( n1)
j exitGCD
The main issue with your code is with the part where you store the user input in the registers. In move $a0,$s0, you are moving the value at $s0 into $a0 when the user input is stored in $v0, therefore, it should be move $a0,$v0, and from your function, you seem to have stored the second input in $a1 but in your code, both the inputs are being stored in the same register so the next command should be move $a1,$v0. Here is one version of your code.
.data
n1:.asciiz"Enter the first number:"
n2: .asciiz"Enter the second number:"
.text
.globl main
main:
li $v0,4
la $a0,n1
syscall
li $v0, 5 # get input from user
syscall
move $t0,$v0 #temporarily store the user input in another register because $a0 is having another value stored in it in the next command
li $v0,4
la $a0,n2
syscall
li $v0, 5 # get second input from user
syscall
move $a1,$v0
move $a0,$t0 #transfer the first user input into $a0 to be used in the function
jal calcGCD # call function calcGCD
add $a0,$v0,$zero
li $v0,1
syscall # print result
li $v0, 10 # exit program
syscall
calcGCD:
#GCD(n1, n2)
# n1 = $a0
# n2 = $a1
addi $sp, $sp, -12
sw $ra, 0($sp) # save function into stack
sw $s0, 4($sp) # save value $s0 into stack
sw $s1, 8($sp) # save value $s1 into stack
add $s0, $a0, $zero # s0 = a0 ( value n1 )
add $s1, $a1, $zero # s1 = a1 ( value n2 )
addi $t1, $zero, 0 # $t1 = 0
beq $s1, $t1, return # if s1 == 0 return
add $a0, $zero, $s1 # make a0 = $s1
div $s0, $s1 # n1/n2
mfhi $a1 # reminder of n1/n2 which is equal to n1%n2
jal calcGCD
exitGCD:
lw $ra, 0 ($sp) # read registers from stack
lw $s0, 4 ($sp)
lw $s1, 8 ($sp)
addi $sp,$sp , 12 # bring back stack pointer
jr $ra
return:
add $v0, $zero, $s0 # return $v0 = $s0 ( n1)
j exitGCD
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
Can anybody tell me what is wrong with my recursion code below. It is supposed to be a recursive function of a decimal to binary function. I just can not see what is wrong. I am new to MIPS so I do not fully understand everything but from my understanding this is what I got.
I hardcoded a number in and I am supposed to get the output 101000 but it would not load anything beyond the message.
.data
msg1:.asciiz "Output (40) = "
.text
.globl main
la $a0,msg1 # load string as parameter
li $v0, 4 # load operation "print string"
syscall # request "print string" for msg1
addi $t0, $zero, 40
move $a0, $t0
li $t2, 2
jal d2b
add $a0, $v0, $zero # load the value of $v0 into $a0
li $v0, 1 # load operation "print integer"
syscall # request "print integer"
d2b: li $t1, 0 # t1 = 0
bgt $a0, $t1, skip # if a0 > t1 no
li $v0, 0 # load v0 as 0
jr $ra # print this shit out
skip: subu $sp, $sp, 32 # sp down 32
sw $ra 20($sp) # save $ra
sw $fp, 16($sp) # save $fp
addiu $fp, $sp, 28 # set up $ fp
sw $a0, 0($fp) # save n
divu $a0, $t2 # divide n / 2
mflo $t3 # quota
mfhi $t4 # rem
move $a1, $t4 # rem keep
move $a2, $t3 # quota keep
addi $a1, 10 # adding rem + 10
jal d2b # call recursive —> d2b(n/2)
lw $a0, 0($fp) # restore n
multu $v0, $a2 # rem+10 *d2b(n/2)
lw $ra, 20($sp) # load $ra
lw $fp, 16($sp) # load $fp
addiu $sp, $sp, 32 # pop stack
jr $ra # return
I have a couple of questions about my group project. The first question is regarding playback of a MIDI file. Right now our program can playback a type 0 file with about 75% accuracy (if you can even gauge that). Basically, it get "most" of the song right (or really close). It's clearly not playing every sound and some of the ones it does play sound distorted. So if it's playing most of the notes correctly, what could cause it to miss or distort the others?
The second question is concerned with our interrupt handler. I'm trying to adjust the pointer so the program will skip X bytes forward/backward, but if I try the interrupt while the program is running it stalls and locks the program up. If I run through the interrupt step-by-step it won't stall. It seems like I'm either halfway there or totally off the mark (this was working on an earlier version, but probably b/c the playback function wasn't written correctly). If I had to guess I'd say the problem has something to do with the WITH_STATUS and WITHOUT_STATUS functions. Is that right?
Thank you in advance for any help.
PLAY_MIDI:
addi $s5, $0, 0 # temporaries to control speed and volume
addi $t6, $0, 100
addi $t9, $0, 0
addi $sp, $sp, -4 # add a byte to the stack pointer and store the return address there
sw $ra, 0($sp)
addi $t4, $0, 3
LOOP:
lh $t0, DAT_Format
bnez $t0, NO_SUPPORTED
addi $s3, $s3, 1
addi $s1, $s1, -1
lbu $t9, 0($s3) # look for status byte
blez $s1, OFF_LOOP
bltu $t9, 0x80, LOOP
bgeu $t9, 0xa0, LOOP
WITH_STATUS:
lbu $t9, 0($s3)
lb $t6, -1($s3) #sleep time
lb $a1, 1($s3) # load note
lb $a2, 2($s3) # load volume
addi $s3, $s3, 4
addi $s1, $s1, -4
move $s2, $s1 # *** copy $s1 to $s2 for pause/play
j SLEEP
WITHOUT_STATUS:
lb $t6, -1($s3) #sleep time
lb $a1, 0($s3) # load note
lb $a2, 1($s3) # load volume
addi $s3, $s3, 3 #increase stack
addi $s1, $s1, -3
move $s2, $s1 # ** copy $s1 to $s2 for pause/play
SLEEP:
mul $t6, $t6, $t4
li $v0, 32 # sleep until the next note should be played
addu $a0, $0, $t6 # sleep for $t6 ms
syscall
and $a0, $t9,0x0F # load channel
and $t9,$t9,0x000000F0 # load Command
######################################################
## copy $s1 to $s2 for use differentiating between ##
beq $t9, 0x90, PLAY_NOTE_ON ## stop and pause ##
beq $t9, 0x80, PLAY_NOTE_OFF ## $s2 will hold last position of $s1 ##
bgeu $t9, 0xa0, LOOP ######################################################
AFTER_PLAY:
blez $s1, OFF_LOOP
lbu $t0, 0($s3)
bgeu $t0, 0x80, WITH_STATUS
j WITHOUT_STATUS
OFF_LOOP:
bne $s1, $s2, PAUSE_LOOP # get the return address from the stack and decrease the pointer
lw $ra, 0($sp)
addi $sp, $sp, 4
jr $ra # jump to the address we just loaded
PLAY_NOTE_ON:
li $v0, 60 # add a byte to the stack pointer and store the return address there
syscall
j AFTER_PLAY
PLAY_NOTE_OFF:
li $v0, 61
syscall
j AFTER_PLAY
NO_SUPPORTED:
j EXIT
#### Below is part of the interrupt handler ####
SKIP_FORWARD: addi $s3, $s3, 1 # by adding to $s3 program will move pointer ahead
la $a0, skip_forward # changed from $s3 to $s1 ***
li $v0, 4
syscall
jr $ra
SKIP_BACKWARD: addi $s3, $s3, -1 # by subtracting from $s3 program will move pointer backwards
la $a0, skip_backward # changed $s3 to $s1
li $v0, 4
syscall
jr $ra