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
prompt2: .asciiz "please enter the elements one by one:"
prompt3: .asciiz "the array is ordered as follows: "
prompt4: .asciiz "-- Program is finished running --"
str1: .asciiz ","
newLine: .asciiz "\n"
.text
addi $sp,$sp,-24
sw $ra,0($sp)
sw $s4,4($sp)
sw $a2,8($sp)
sw $s3,12($sp)
sw $s0,16($sp)
sw $s2,20($sp)
main:
# read n from console
li $v0 5
syscall
move $a2 $v0 #tagghiir t0 be a2 (n)
# allocate dynamic memory
sll $a0 $v0 2 # sll performs $a0 = $v0 x 2^2
li $v0 9 #9 is the system code for service(sbrk) whoes work is
syscall #to allocate dynamic memory
move $a1 $v0 #t2 saved address of heap #taghiir t2 to a1
#saved for printing
li $v0, 4 # $system call code for print_str
la $a0, prompt2 # $address of string to print
syscall
move $t1 $zero
move $t4,$a1
inputLoop:
bge $t1 $a2 exit1
# read in and store int
li $v0 5
syscall
sw $v0 0($t4)
addi $t1 $t1 1
addi $t4 $t4 4
li $v0, 4 # $system call code for print_str
la $a0, newLine # $address of string to print
syscall
j inputLoop
exit1:
jal sort
li $v0, 4 # $system call code for print_str
la $a0, prompt3 # $address of string to print
syscall
move $t3,$zero
move $t4 ,$a1
outputLoop:
bge $t3 $a2 exit2
#inaro azoon yki copy krdm
lw $t6, 0($t4)
li $v0, 1
move $a0, $t6
syscall
# read in and store int
addi $t3 $t3 1
addi $t4 $t4 4
blt $t4,$a1 ,comma
# bne $t5,$zero,comma
comma:
li $v0, 4 # $system call code for print_str
la $a0, str1 # $address of string to print
syscall
j outputLoop
exit2:
li $v0, 10
syscall #for finishing the program
swap:
move $a3,$a3
move $a1,$s4
# move $t5,$zero # its for our temp variable in c code
move $t4 ,$a1 #t4 is now the base address of heap
sll $t6 , $a3,2 # s1 is the given k
add $t6,$t4,$t6 # heap address + k*4
lw $t3,0($t6) #khoone k e heap
lw $t5,4($t6) #khoone k+1 heap
sw $t5,0($t6)
sw $t3,4($t6)
jr $ra
sort:
# move $s0,$zero #i=t0
move $s4,$a1 #base address of heap
addi $t5,$a2,-1 # meghdare i
move $s2,$zero #its the flag
while:
addi $s2,$s2,1
move $a3,$zero #j #taghiir s1 be a3 (haman j va k
forLoop:
bge $a3,$t5,outOfLoop
sll $t6,$a3,2 #j
add $t1,$t6,$a1 #v+j
lw $t7,0($t1) #t7=heap[j]
lw $t8,4($t1) #t8=heap[j+1]
blt $t7,$t8,outOfIf
move $s4,$a1
move $s3,$a3
jal swap
addi $s2,$s2,-1
outOfIf:
addi $a3,$a3,1 #j++
outOfLoop:
addi $t5,$t5-1 #i--
bgt $s2,$zero,exit_outter #if a>=b break
ble $t5,$zero,exit_outter #if b=< c break
j while
exit_outter:
lw $ra,0($sp)
lw $s4,4($sp)
lw $a2,8($sp)
lw $s3,12($sp)
lw $s0,16($sp)
lw $s2,20($sp)
addi $sp,$sp,24
jr $ra
Where am I going wrong?
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.
I am trying to implement puts in MIPS. I have a procedure putchar which prints a char to the screen :
.text
putchar:
lui $t0, 0xffff # base address of memory map
XReady:
lw $t1, 8($t0) #read from transmitter control register
andi $t1, $t1, 0x1 # extract ready bit
beqz $t1, XReady # if 1, store char ; else, loop
sw $a0, 12($t0) # send character to display
jr $ra # return to place in program before function call
In my main subroutine, I set $a0 to the string I want to print and then I call puts :
la $a0, array # defined in .data as -- array: .space 2000 --
gal puts
I get an error fetch address not aligned on word boundary on line 242 of puts (marked with a *)
.text
puts:
addi $sp, $sp, -24 # make room for 6 registers
sw $ra, 20($sp) # save $ra on the stack
sw $s0, 16($sp) # save $s0 on the stack
sw, $s1, 12($sp) # save $s1 on the stack
sw, $s2, 8($sp) # save $s2 on the stack
sw, $s3, 4($sp) # save $s3 on the stack
sw, $s4, 0($sp) # save $s4 on the stack
move $s0, $a0 # copy parameter $a0 into $s0
move $s1, $a1 # copy parameter $a0 into $s1
move $s2, $a2 # copy parameter $a0 into $s2
move $s3, $a3 # copy parameter $a0 into $s3
move $s4, $zero # s4 is a character counter. $s4 = 0
getsLoop:
addi $t0, $zero, 0x00 # Put NULL ascii character inside $t0
sll $t1, $s4, 2 # create buffer storing address ($t1 = $s1 * 4)
add $t2, $s0, $t1 # register #t2 now holds buffer address
* lw $t3, ($s0) # load char into #t3
beq $t3, $t0, exitPuts # exit puts if the current character is the NULL character
move $a0, $t3 # put the character to print inside $a0, accessible by putchar
jal putchar # print char using putchar
addi $s0, $s0, 1 # character count += 1
j getsLoop # Loop to print next character
exitPuts:
lw $s4, 0($sp) # restore stack
lw $s3, 4($sp) # -
lw $s2, 8($sp) # -
lw $s1, 12($sp) # -
lw $s0, 16($sp) # -
lw $ra, 20($sp) # -
addi $sp, $sp, 20 # pop from stack
jr $ra # return
I don't why I'm getting this error... Isn't $s0 the address of array defined in main?
When you use lw you load an entire word (4 bytes, not to be confused with words in natural languages), and that word has to be aligned on a word boundary (the two least significant bits of the address have to be 0).
ASCII characters are typically stored using one byte per character, so you should use the lbu instruction to load them instead of lw.
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