MIPS: Infinite loop with branches - mips

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

Related

MIPS getting an error when running my code

For our coursework we had to write code in MARS to calculate the memory address of a given coordinate.
.globl main
.data
amountOfRows: .word 16 # The mount of rows of pixels
amountOfColumns: .word 32 # The mount of columns of pixels
promptRows: .asciiz "Please enter the row number:\n"
promptCols: .asciiz "Please enter the column number:\n"
msgShowMemoryAddress: .asciiz "The memory address for the pixel is:\n"
msgErrorValues: .asciiz "The entered value for row/column is invalid, please enter a valid value:\n"
.text
###################################################################################
translate_coordinates:
sw $fp, 0($sp) # push old frame pointer (dynamic link)
move $fp, $sp # frame pointer now points to the top of the stack
subu $sp, $sp, 20 # allocate 16 bytes on the stack
sw $ra, -4($fp) # store the value of the return address
sw $s0, -8($fp) # save locally used registers
sw $s1, -12($fp)
sw $s2, -16($fp)
move $s0, $a0 # $s0 = x coordinate
move $s1, $a1 # $s1 = y coordinate
move $s2, $a2 # $s2 = width for calculations
sll $t3, $s1, 5 # shift y left by 5 which is equal to multiplication of 32
add $t4, $t3, $s0 # (y * 32) + x = index of pixel
sll $t5, $t4, 2 # shift index left by 2 which is equal to multiplication of 4
add $t6, $gp, $t5 # memory address = gp + offset
move $v0, $t6 # place result in return value location
lw $s2, -16($fp) # reset saved register $s2
lw $s1, -12($fp) # reset saved register $s1
lw $s0, -8($fp) # reset saved register $s0
lw $ra, -4($fp) # get return address from frame
move $sp, $fp # get old frame pointer from current fra
lw $fp, ($sp) # restore old frame pointer
jr $ra
###################################################################################
main:
li $v0, 4 # print string
la $a0, promptRows # message to ask the user for the row number
syscall
li $v0, 5 # read integer
syscall # ask the user for a row number
move $t0, $v0
li $v0, 4 # print string
la $a0, promptCols # message to ask the user for the column number
syscall
li $v0, 5 # read integer
syscall # ask the user for a column number
move $t1, $v0
lw $t2, amountOfColumns #load amountOfColumns into $t2
move $a0, $t0 # Put procedure arguments
move $a1, $t1 # Put procedure arguments
move $a2, $t2
jal translate_coordinates # Call procedure
move $t6, $v0 # Get procedure result
move $a0, $t6
li $v0, 1 # syscall code 1 is for print_int
syscall
exit:
li $v0, 10 # syscall to end the program
syscall
I wrote this code to calculate the memory address of a pixel but whenever I run it I get this error:
Error in : invalid program counter value: 0x00000000
We had to use a stackframe for this and I'm quite new to that.
Because I'm quite new to it, it might be that I made some mistakes when it comes to that.
By default, MARS starts running the code at the start of .text, and since in your code the function comes before main, it is running the function without calling it properly.
There are three options:
add j main immediately after .text
use MARS option Settings -> Initialize Program Counter to global main if defined (off by default)
change the order so that main comes immediately after .text

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 $

How to i fix my error when trying to calculate the sum using mips?

goodday, so currently my code prompts the user to enter a sum. my program then takes these stored values and outputs the sum of them. However, currently my code is not outputting the correct total and i am unsure where the problem lies.
i have attached my code below:
.text
main:
#Prompt
la $a0, prompt
li $v0, 4
syscall
# Get input string
li $v0, 8
la $a0, string_input
li $a1, 1024
move $t0, $a0
syscall
# initialise sum
lb $t2, ($t0) # Initialise the sum as the first value
addi $t2, $t2, -48 # Convert to decimal value
addu $t0, $t0, 1
b loop
loop:
lb $t3, ($t0) # Store the sign
lb $t1, 1($t0) # Store the value
addu $t0, $t0, 2 # increment the counter
beq $t1, 10, end_loop # If reached the end of the string
# Manipulate sign value to 1 if '+'
add $t3, $t3, 4
add $t2, $t2, $t1 # Add the value to the sum
b loop # re-iterate
end_loop:
# Printing the total sum
move $a0, $t2
li $v0, 1
syscall
# Exiting program
li $v0, 10
syscall
.data
string_input: .space 1024
prompt: .asciiz "Enter a sum:\n"
the current output should be 11 but this is what is outputted instead:
Enter a sum:
2+3+6
727

How to count the number of words and print the result in mips?

So I am fairly new to mips and am trying to do a hmwk.
The exercise is to create a block of words with 0 as the last word , to count them knowing we don't consider the last element 0 and print out the result.
Here is my code for the moment
.data
blockOfWords: .word 12,43,549,7,60,0
.text
la $a0, blockOfWords #putting address of blockOfWords in $a0
loopStart: sll $t1, $s3,2 #iterates thru blockOfWords by jumping by 4 bytes, $t1=4*i
add $t1,$t1,$a0 #we increment the address by four so as to advance in the array after every iteration
lw $a1, 0($t1) #$a1=blockOfWOrds[i]
beq $a1,$zero, Exit #if the value in $a1[i]==0, exit the loop
addi $s0,$s0,1 #else, increment by one the cnt=$s0
j loopStart #and continue looping thru blockOfWords
Exit:
#how do i print the result?
So instead of doing a shift left logical it is a lot easier to up the memory address in the array
In this way the lw $a1, 0($a0) is just grabbing the beginning of the word
it is then incremented by 4 after a check for the 0. This makes the function much simpler and easier to read.
.data
blockOfWords: .word 12,43,549,7,60,0
.text
main:
la $a0, blockOfWords # Load beginning address into $a0
loopStart:
lw $a1, 0($a0) # load the value at the beginning of $a0 into $a1
beq $a1,$zero, exit # Check if $a1 is 0, if so jump to exit
addi $s0,$s0,1 # Add one to the count
addi $a0, $a0, 4 # Up the intial index of the array by 4, up one word
j loopStart # Re-loop
exit:
li $v0, 1 # Load the value of 1 into the $v0 register
la $a0, ($s0) # Load the counter into the $a0 address
syscall
li $v0, 10 # A value 10 syscall to indicate end of program
syscall

How do you properly read an integer input in 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