How do you properly read an integer input in MIPS? - mips

The following program 1. Prints out the array 2. Given a lower and upper bound input by user, determines the min and min index within that range
It runs the print array function.
However, I tried tracing the registers in QTSPIM, it does not correctly assign the lower bound and upper bound to $a0 and $a1 respectively. In fact, $v0 does not seem to even scan anything. To move the scanned input from $v0 to $t0, tried using "move $t0, $v0" instead. The problem still occurs.
# Ask the user for two indices
li $v0, 5 # System call code for read_int
syscall
add $t0, $v0, $zero # store input in $t0
sll $t0, $t0, 2 # relative address position (lower bound)
add $a0, $t9, $t0 # array pointer (lower bound)
li $v0, 5 # System call code for read_int
syscall
add $t0, $v0, $zero # store input in $t0
sll $t0, $t0, 2 # relative address position (upper bound)
add $a1, $t9, $t0 # array pointer (upper bound)
The full code is below. Can anyone enlighten me if there's anything wrong?
# arrayFunction.asm
.data
array: .word 8, 2, 1, 6, 9, 7, 3, 5, 0, 4
newl: .asciiz "\n"
.text
main:
# Print the original content of array
# setup the parameter(s)
la $a0, array # base address of array
add $t9, $a0, $zero # store base address
la $a1, 10 # number of elements in array
# call the printArray function
jal printArray # call function
# Ask the user for two indices
li $v0, 5 # System call code for read_int
syscall
add $t0, $v0, $zero # store input in $t0
sll $t0, $t0, 2 # relative address position (lower bound)
add $a0, $t9, $t0 # array pointer (lower bound)
li $v0, 5 # System call code for read_int
syscall
add $t0, $v0, $zero # store input in $t0
sll $t0, $t0, 2 # relative address position (upper bound)
add $a1, $t9, $t0 # array pointer (upper bound)
# Call the findMin function
# setup the parameter(s)
# call the function
jal findMin # call function
# Print the min item
# place the min item in $t3 for printing
addi $t3, $t1, 0
# Print an integer followed by a newline
li $v0, 1 # system call code for print_int
addi $a0, $t3, 0 # print $t3
syscall # make system call
li $v0, 4 # system call code for print_string
la $a0, newl
syscall # print newline
#Calculate and print the index of min item
la $a0, array
add $t3, $v0, $a0
srl $t3, $t3, 2
# Place the min index in $t3 for printing
# Print the min index
# Print an integer followed by a newline
li $v0, 1 # system call code for print_int
addi $a0, $t3, 0 # print $t3
syscall # make system call
li $v0, 4 # system call code for print_string
la $a0, newl #
syscall # print newline
# End of main, make a syscall to "exit"
li $v0, 10 # system call code for exit
syscall # terminate program
#######################################################################
### Function printArray ###
#Input: Array Address in $a0, Number of elements in $a1
#Output: None
#Purpose: Print array elements
#Registers used: $t0, $t1, $t2, $t3
#Assumption: Array element is word size (4-byte)
printArray:
addi $t1, $a0, 0 #$t1 is the pointer to the item
sll $t2, $a1, 2 #$t2 is the offset beyond the last item
add $t2, $a0, $t2 #$t2 is pointing beyond the last item
l1:
beq $t1, $t2, e1
lw $t3, 0($t1) #$t3 is the current item
li $v0, 1 # system call code for print_int
addi $a0, $t3, 0 # integer to print
syscall # print it
addi $t1, $t1, 4
j l1 # Another iteration
e1:
li $v0, 4 # system call code for print_string
la $a0, newl #
syscall # print newline
jr $ra # return from this function
#######################################################################
### Student Function findMin ###
#Input: Lower Array Pointer in $a0, Higher Array Pointer in $a1
#Output: $v0 contains the address of min item
#Purpose: Find and return the minimum item
# between $a0 and $a1 (inclusive)
#Registers used: $t0 (counter), $t1 (max add), $t2 (min), $v0 (min pos), $t3 (current item)
#Assumption: Array element is word size (4-byte), $a0 <= $a1
findMin:
lw, $t2, 0($a0) # initialise min (value) to the lower bound
addi $t0, $a0, 0 # initialise $t0 (current pointer) to lower bound
addi $t1, $a1, 0 # initialise $t1 (add of end of array) to upper bound
Loop: slt $t4, $t1, $t0
bne $t4, $zero, End # branch to end if upper < lower
lw, $t3, 0($a0) # store the content of the lower array pointer
slt $t4, $t3, $t2 # if current ($t3) < min ($t2), store 1 in $t4
beq $t4, $zero, LoopEnd # if it is 0, go to LoopEnd
addi $t2, $t3, 0 # store content ($t3) as minimum ($t2)
addi $v0, $t0, 0 # store the address of min
LoopEnd: addi, $t0, 4 # increments current pointer lower bound
j Loop # Jump to loop
End:
jr $ra # return from this function

You read in the integers properly. The problems are elsewhere
In findMin function you use lw, $t3, 0($a0), but you should use it with $t0 instead of $a0.
After you return from this function you accidentally save $t1 as min value rather then $t2 which actually holds it.
Also you do not save $v0 which holds the pointer for the min value, so you use some garbage data later on, not the intended one.
When you calculate the index of the min from the pointer you use add, but it should be sub.
Also as it was mentioned in the comments at LoopEnd the add is syntactically wrong. It should be addi $t0, $t0, 4. But this maybe just some copy paste error.
Here is the fixed code. Changed lined marked with ERROR.
# arrayFunction.asm
.data
array: .word 8, 2, 1, 6, 9, 7, 3, 5, 0, 4
newl: .asciiz "\n"
.text
main:
# Print the original content of array
# setup the parameter(s)
la $a0, array # base address of array
add $t9, $a0, $zero # store base address
la $a1, 10 # number of elements in array
# call the printArray function
jal printArray # call function
# Ask the user for two indices
li $v0, 5 # System call code for read_int
syscall
add $t0, $v0, $zero # store input in $t0
sll $t0, $t0, 2 # relative address position (lower bound)
add $a0, $t9, $t0 # array pointer (lower bound)
li $v0, 5 # System call code for read_int
syscall
add $t0, $v0, $zero # store input in $t0
sll $t0, $t0, 2 # relative address position (upper bound)
add $a1, $t9, $t0 # array pointer (upper bound)
# Call the findMin function
# setup the parameter(s)
# call the function
jal findMin # call function
# Print the min item
# place the min item in $t3 for printing
addi $t3, $t2, 0 # ERROR: min is in $t2 not $t1
addi $t4, $v0, 0 # ERROR: not saving the pointer to the min element
# Print an integer followed by a newline
li $v0, 1 # system call code for print_int
addi $a0, $t3, 0 # print $t3
syscall # make system call
li $v0, 4 # system call code for print_string
la $a0, newl
syscall # print newline
#Calculate and print the index of min item
la $a0, array
sub $t3, $t4, $a0 # ERROR: sub should used not add
srl $t3, $t3, 2
# Place the min index in $t3 for printing
# Print the min index
# Print an integer followed by a newline
li $v0, 1 # system call code for print_int
addi $a0, $t3, 0 # print $t3
syscall # make system call
li $v0, 4 # system call code for print_string
la $a0, newl #
syscall # print newline
# End of main, make a syscall to "exit"
li $v0, 10 # system call code for exit
syscall # terminate program
#######################################################################
### Function printArray ###
#Input: Array Address in $a0, Number of elements in $a1
#Output: None
#Purpose: Print array elements
#Registers used: $t0, $t1, $t2, $t3
#Assumption: Array element is word size (4-byte)
printArray:
addi $t1, $a0, 0 #$t1 is the pointer to the item
sll $t2, $a1, 2 #$t2 is the offset beyond the last item
add $t2, $a0, $t2 #$t2 is pointing beyond the last item
l1:
beq $t1, $t2, e1
lw $t3, 0($t1) #$t3 is the current item
li $v0, 1 # system call code for print_int
addi $a0, $t3, 0 # integer to print
syscall # print it
addi $t1, $t1, 4
j l1 # Another iteration
e1:
li $v0, 4 # system call code for print_string
la $a0, newl #
syscall # print newline
jr $ra # return from this function
#######################################################################
### Student Function findMin ###
#Input: Lower Array Pointer in $a0, Higher Array Pointer in $a1
#Output: $v0 contains the address of min item
#Purpose: Find and return the minimum item
# between $a0 and $a1 (inclusive)
#Registers used: $t0 (counter), $t1 (max add), $t2 (min), $v0 (min pos), $t3 (current item)
#Assumption: Array element is word size (4-byte), $a0 <= $a1
findMin:
lw, $t2, 0($a0) # initialise min (value) to the lower bound
addi $t0, $a0, 0 # initialise $t0 (current pointer) to lower bound
addi $t1, $a1, 0 # initialise $t1 (add of end of array) to upper bound
Loop:
slt $t4, $t1, $t0
bne $t4, $zero, End # branch to end if upper < lower
lw, $t3, 0($t0) # store the content of the lower array pointer, ERROR: t0 should be used not a0
slt $t4, $t3, $t2 # if current ($t3) < min ($t2), store 1 in $t4
beq $t4, $zero, LoopEnd # if it is 0, go to LoopEnd
addi $t2, $t3, 0 # store content ($t3) as minimum ($t2)
addi $v0, $t0, 0 # store the address of min
LoopEnd:
addi $t0, $t0, 4 # increments current pointer lower bound
j Loop # Jump to loop
End:
jr $ra # return from this function

Related

Program is finished running dropped off

When i run my code i got this
-- program is finished running (dropped off bottom) --
This is my code
.data
array: .space 12 # Reserve 12 bytes of memory for the array
.text
la $t0, array # Load the address of the array into $t0
li $v0, 4 # System call code for printing a string
la $a0, prompt # Load the address of the prompt string
syscall # Print the prompt
.data
prompt: .asciiz "Enter three integers: "
li $v0, 5 # System call code for reading an integer
syscall # Read the first integer
sw $v0, 0($t0) # Store the first integer in the first word of the array
li $v0, 5 # Read the second integer
syscall
sw $v0, 4($t0) # Store the second integer in the second word of the array
li $v0, 5 # Read the third integer
syscall
sw $v0, 8($t0) # Store the third integer in the third word of the array
lw $t1, 0($t0) # Load the first integer into $t1
lw $t2, 4($t0) # Load the second integer into $t2
lw $t3, 8($t0) # Load the third integer into $t3
add $t4, $t1, $t2 # Add the first two integers and store the result in $t4
add $t4, $t4, $t3 # Add the third integer and store the result in $t4
sw $t4, sum # Store the sum in memory
.data
sum: .word 0
li $t5, 3 # Load the value 3 into $t5
div $t4, $t5 # Divide the sum by 3 to get the average
mflo $t4 # Store the result of the division in $t4
sw $t4, avg # Store the average in memory
.data
avg: .word 0
li $t0, 3 # Load the value 3 into $t0
li $t1, 0 # Load the value 0 into $t1
loop:
lw $t2, 0($t0) # Load the next integer from the array into $t2
add $t1, $t1, $t2 # Add the current integer to the sum
addi $t0, $t0, 4 # Move to the next word in the array
bne $

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

Printing an hourglass in mips32

I'm having problems solving this question. I want to print an hourglass using mips32. n is an integer given by user as input and the hourglass must be printed in n lines. For example, for n = 5 the output is:
*****
***
*
***
*****
Here is my code for the first part (the triangle top of the hourglass). The problem is that it prints only the first line of stars and then exits. By running my code line by line in Mars, I understood that the first line of the backToLoop1 label is run every time loop3 is run! So it causes the program to end after the first line. I really can't realize why this happens.
.data
newLine: .asciiz "\n"
.text
main:
li $v0, 5 # read n
syscall # call sysetem
addi $t2, $v0, 0 # moves n to $t2
li $t0, 1 # i= 1
loop1:
blt $t2, $t0, Exit # if n<i exit
la $a0, newLine # go to next line
addi $v0, $0, 4 # 4 represents printing string
syscall # call system
# loop2 bounds
li $t1, 1 # k= 1
subi $t3, $t0, 1 # $t3= i-1 upper bound for loop2
# loop3 bounds
li $t5, 1 # j= 1
addi $t6, $t2, 1 # t6= n+1
sub $t6, $t6, $t0 # $t6= n+1-i upper bound for loop3
loop2:
blt $t3, $t1, loop3
li $a0, ' ' # load space to $a0
la $v0, 11 # 11 represents printing character
syscall # call system
addi $t1, $t1, 1 # k++
ble $t1, $t3, loop2 # if <= i-1 loop2 again
loop3:
blt $t6, $t5, backToLoop1 # back to loop1
li $a0, '*' # load star to $a0
la $v0, 11 # 4 represents printing character
syscall # call system
addi $t5, $t5, 1 # j++
ble $t5, $t6, loop3 # if j <= n-i+1 loop3 again
backToLoop1:
addi $t0, $t0, 1 # i++
ble $t0, $t2, loop1 # if i<=n loop1 again
blt $t2, $t0, Exit
Exit: # Terminate the program
li $v0, 10 # 10 represents exit
syscall # call system
You're off to a good start. However, there doesn't appear to be a clear strategy for slanting the right side of the hourglass. Ideally we can write logic to handle drawing the bottom half without duplicating most of the logic.
My default approach for this sort of pattern is to use two pointers, a left starting at 0 and right starting at n - 1. These represent the index bounds for the asterisk characters for each row. Per row iteration, decrement the right pointer and increment the left pointer, essentially drawing an "X" pattern on the n by n grid.
This strategy gets us 95% of the way there. The last step is to temporarily swap the left and right pointers if left > right, which handles drawing the bottom half without too much spaghetti.
.data
prompt: .asciiz "enter a number: "
.text
main:
la $a0 prompt # collect n
li $v0 4
syscall
li $v0 5
syscall
move $s3 $v0 # n
li $s0 0 # left index
move $s1 $s3 # right index = n - 1
addi $s1 $s1 -1
row_loop:
bltz $s1 exit # while right-- >= 0
li $s2 0 # column index
col_loop:
beq $s2 $s3 row_loop_done # for 0..n
# if left > right, swap temporarily
move $t0 $s0
move $t1 $s1
blt $t0 $t1 pick_char
move $t2 $t0
move $t0 $t1
move $t1 $t2
pick_char:
# '*' if left <= i <= right else ' '
blt $s2 $t0 pick_space
bgt $s2 $t1 pick_space
li $a0 42 # print '*'
j print_char
pick_space:
li $a0 32 # print ' '
print_char:
li $v0 11
syscall
addi $s2 $s2 1 # column index++
j col_loop
row_loop_done:
li $a0 10 # print newline
li $v0 11
syscall
addi $s1 $s1 -1 # right--
addi $s0 $s0 1 # left++
j row_loop
exit:
li $v0 10
syscall

function to perform swapping in an array

The basic flow of the program is as follows:
1. Print the original content of array.
2. Ask the user for two indices X and Y.
3. Swap the two elements if Array[X] > Array[Y].
4. Print the modified array only if swapping occurs.
.data
array: .word 8, 2, 1, 6, 9, 7, 3, 5, 0, 4
newl: .asciiz "\n"
.text
la $a0, array
li $a1, 10
jal printArray
#Ask the user for two indices
li $v0, 5 #System call code for read_int
syscall
addi $t0, $v0, 0 # first user input in $t0
li $v0, 5 #System call code for read_int
syscall
addi $t1, $v0, 0 # second user input in $t1
swap : li $a1, 0 #inx1
li $a2, 0 #inx2
sll $t0, $a1, 2 # $t0 = inx1* 4
add $t0, $t0, $a0 # $t0 is the address of A[$a1]
sll $t3, $a2, 2 # $t3 = inx2* 4
add $t3, $t3, $a0 # $t3 is the address of A[$a2]
lw $t1, 0($t0) # $t1 = A[$a1]
lw $t2, 0($t3) # $t2 = A[$a2]
ble $t1, $t2, noPrint# if A[$a1] <=A[$a2] goto noPrint
sw $t1, 0($t3) # do the swap
sw $t2, 0($t0) # do the swap
syscall
jal printArray
printArray:
addi $t1, $a0, 0 #$t1 is the pointer to the item
sll $t2, $a1, 2 #$t2 is the offset beyond the last item
add $t2, $a0, $t2 #$t2 is pointing beyond the last item
loop: beq $t1, $t2, end
lw $t3, 0($t1) #$t3 is the current item
li $v0, 1 # system call code for print_int
addi $a0, $t3, 0 # integer to print
syscall # print it
addi $t1, $t1, 4
j loop # Another iteration
end:
li $v0, 4 # system call code for print_string
la $a0, newl #
syscall # print newline
jr $ra # return from this function
noPrint:
li $v0, 10 # system call code for exit
syscall # terminate program
I'm having problems with swap function. It doesn't print anything on console window(using QtSpim). Can you please recommend any suggestion?

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.