Counting number of elements in an array of words using MIPS - mips

I am trying to code MIPS to count the number of elements in an array of words that are greater than x and less than y, but the code does not seem to branch properly and I keep getting "count = 9" which is, in this case, the number of elements in my list.
.text
.globl __start
__start: # execution starts here */
la $a0, ans # load str "count ="
li $v0, 4
syscall
la $t0,nums # load array into address
li $t1,0 # setting counter to 0
addi $s0, $zero, 50 # adding constant of 50
addi $s1, $zero, 100 #adding constant of 100
lw $t5,count # loading word "9"
again : lw $t4 ($t0) # load first element of array into t4
bgt $t4,$s0,passif50 #comparing if first element is greater than 50
passif50 : blt $t4,$s1,passif100 #comparing if first element is less than 100
passif100 : add $t1, $t1,1 #incrementing counter by 1
add $t0, $t0,4 #increment current array element pointer
sub $t5,$t5,1 #deincrement "count" word by 1
beqz $t5,done #when "count" word is equal to 0, exit loop
done : move $a0,$t1
li $v0,1
syscall # print the count
li $v0, 10
syscall # end program
.data
nums: .word 55,68,2,60,2000,51,99,1,67
count: .word 9
ans: .asciiz "count = "
endl: .asciiz "\n"

Related

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

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 to find min and max in an array MIPS

i can find the max perfectly fine but when it comes to finding the min, im having some trouble, my max finds the max number good but my min always prints out 0 no matter what, i cant seem to find out what is wrong with my code, does anyone see the flaw in my code?
For exmaple:
i enter in 5 integers
5 10 15 20 25
Array: 5,10,15,20,25
Min: 0
Max: 25
.text
.globl main
main:
la $a0, ask #ask user for integer thats going to be the size of the array
li $v0, 4
syscall
li $v0, 5 #store that int
syscall
move $t1,$v0 #size of my array stored in $t1
la $t0, array #load address of our array
li $t2, 0 #counter = 0
lw $t3,($t0) #initialize min = array[0]
lw $t4,($t0) #initialize max = array[0]
while:
la $a0, intask #ask user for integer
li $v0, 4
syscall
li $v0, 5 #store that int
syscall
sw $v0, ($t0) #store that int in the array
end: add $t0, $t0, 4 #increment the array to the next index
add $t2, $t2, 1 #increment the counter by 1
blt $t2, $t1,while #branch to while if counter < size of array
endw:
la $a0,display # Display "Array is: "
li $v0,4
syscall
li $t0, 0 # initilize array index value back to 0
li $t2, 0 # initial size counter back to zero
la $t0, array # load address of array back into $t0
sprint:
lw $t6,($t0) #load word into temp $t2
move $a0, $t6 #store it to a safer place
li $v0, 1 #print it out
syscall
la $a0,space # Display " "
li $v0,4
syscall
add $t0, $t0, 4 #increment the array to the next index
add $t2, $t2, 1 #increment the counter by 1
blt $t2, $t1,sprint #branch to while if counter < size of array
li $t2, 0 # initial size counter back to zero
la $t0, array # load address of array back into $t0
add $t0, $t0, 4 #increment the array to the next index
add $t2, $t2, 1 #increment the counter by 1
loop: lw $t8,($t0) # t8 = next element in array
bge $t8, $t3, notMin #if array element is >= min goto notMin
move $t3,$t8 #min = array[i]
j notMax
notMin: ble $t8,$t4, notMax #if array element is <= max goto notMax
move $t4,$t8 #max = array[i]
notMax: add $t2,$t2,1 #incr counter
add $t0,$t0, 4 #go up in index
blt $t2, $t1,loop #if counter < size, go to loop
eprint:
la $a0,nextline # Display "\n"
li $v0,4
syscall
la $a0,min # Display "min number is "
li $v0,4
syscall
move $a0, $t3 #displays min number in array
li $v0,1
syscall
la $a0,nextline # Display "\n"
li $v0,4
syscall
la $a0,max # Display "max number is "
li $v0,4
syscall
move $a0, $t4 #displays max number in array
li $v0,1
syscall
li $v0,10 # End Of Program
syscall
.data
array: .space 100
ask: .asciiz "How many numbers will be entered? no more than 15 numbers!: "
intask: .asciiz "Enter an Integer: "
min: .asciiz "The minimum number is: "
max: .asciiz "The maximum number is: "
display: .asciiz "Array: "
space: .asciiz " "
nextline: .asciiz "\n"
You are initializing $t3 (which is used for storing min) to array[0] before any values are stored in array, so $t3 ends up being initialized to 0.
It should be fine if you initialize $t3 to array[0] after values have been entered into array.

creating a check for a loop in driver

I created code for a procedure that outputs the factoral of a number given. But it needs to ask the user for a number until they enter a negative before it exits.
So that it looks something like this
Enter a value for n (or a negative value to exit): 6
6! is 720
Enter a value for n (or a negative value to exit): 9
9! is 362880
Enter a value for n (or a negative value to exit): 11
11! is 39916800
Enter a value for n (or a negative value to exit): 20
20! is -2102132736
Enter a value for n (or a negative value to exit): 100
100! is 0
Enter a value for n (or a negative value to exit): -1
Thanks for Testing!
Instead of something like this.
Enter the value of a number (or negative to exit): 5
Value returned is 120
Thanks for testing!
fact:
slti $t0, $a0, 1 # test for n < 1
beq $t0, $zero, L1 # if n >= 1, go to L1
li $v0, 1 # return 1
jr $ra # return to instruction after jal
L1:
addi $sp, $sp, -8 # adjust stack for 2 items
sw $ra, 4($sp) # save the return address
sw $a0, 0($sp) # save the argument n
addi $a0, $a0, -1 # n >= 1; argument gets (n – 1)
jal fact # call fact with (n – 1)
lw $a0, 0($sp) # return from jal: restore argument n
lw $ra, 4($sp) # restore the return address
addi $sp, $sp, 8 # adjust stack pointer to pop 2 items
mul $v0, $a0, $v0 # return n * fact (n – 1)
jr $ra # return to the caller
main:
la $a0, nreq # get value of n
li $v0, 4
syscall
li $v0, 5 # read value of n
syscall
move $a0, $v0 # place value n in $a0
jal fact # invoke fact
move $s0, $v0 #save value returned by facts
la $a0, ans # display
li $v0, 4
syscall
move $a0, $s0
li $v0, 1
syscall
la $a0, cr #display closing
li $v0, 4
syscall
li $v0, 10 # exit
syscall
.data
nreq: .asciiz "Enter a value for n (or negative to exit): "
ans: .asciiz "Value returned is "
cr: .asciiz "\nThanks for testing!\n"
Overall, pretty close. However, one or two things.
I'd move main to the top, above fact, as some simulators start at the lowest .text address rather than the given symbol main. For example, in mars, this didn't seem to work until I reversed the order.
main was missing the test for negative input and didn't loop on itself.
Here's a version that seems to work [please pardon the gratuitous style cleanup]:
.text
.globl main
main:
la $a0,nreq # get value of n
li $v0,4
syscall
li $v0,5 # read value of n
syscall
# NOTE/BUG: add this
bltz $v0,exit # exit program on negative
move $a0,$v0 # place value n in $a0
jal fact # invoke fact
move $s0,$v0 # save value returned by facts
la $a0,ans # display
li $v0,4
syscall
move $a0,$s0
li $v0,1
syscall
# NOTE: add this
li $v0,4
la $a0,nl
syscall
j main
exit:
la $a0,cr # display closing
li $v0,4
syscall
li $v0,10 # exit
syscall
fact:
slti $t0,$a0,1 # test for n < 1
beq $t0,$zero,L1 # if n >= 1, go to L1
li $v0,1 # return 1
jr $ra # return to instruction after jal
L1:
addi $sp,$sp,-8 # adjust stack for 2 items
sw $ra,4($sp) # save the return address
sw $a0,0($sp) # save the argument n
addi $a0,$a0,-1 # n >= 1; argument gets (n – 1)
jal fact # call fact with (n – 1)
lw $a0,0($sp) # return from jal: restore argument n
lw $ra,4($sp) # restore the return address
addi $sp,$sp,8 # adjust stack pointer to pop 2 items
mul $v0,$a0,$v0 # return n * fact (n – 1)
jr $ra # return to the caller
.data
nreq: .asciiz "Enter a value for n (or negative to exit): "
ans: .asciiz "Value returned is "
nl: .asciiz "\n"
cr: .asciiz "\nThanks for testing!\n"

MIPS Output Error

I have an unknown output error after entering 2nd value which is after entering base number.
Hopefully,some of you could identify my error:
ERROR:Instruction references undefined symbol at 0x00400060
[0x00400060] 0x102a0000 beq $1, $10, 0 [hex-0x0040005c]
PROGRESS:Currently stucked at Step 2.
What i want to do is,
1)User enter a decimal value
2)User enter type of conversion
3)Go to desired subroutine depending on type of conversion chosen earlier
4)Display output
.data
prompt: .asciiz "Enter the decimal number to convert: "
base: .asciiz "Select type of base (2 for binary,16 for hexadecimal or 8 for octal): "
ans1: .asciiz "\nBinary Output is equivalent:"
ans2: .asciiz "\nOctal Output is equivalent:"
ans3: .asciiz "\nHexadecimal Output equivalent:0x"
result1: .space 8
.text
.globl main
main:
la $a0, prompt #Display message
li $v0, 4
syscall
li $v0, 5
syscall
beq $v0, $zero, Exit #Exit if 0 decimal is entered
move $t0, $v0 #Else copy value entered into temporaries
askbase:
li $v0, 4
la $a0, base #Display message
syscall
li $v0, 5
syscall
add $t1,$zero,$v0 #Add desired value/base entered into t1
beq $t2,16,hex #if base 16 is entered,goto hex subroutine
beq $t2,8,oct
beq $t2,2,bin
la $a0, ans3
li $v0, 4
syscall
li $t0, 8 # counter
la $t3, result1 # where answer will be stored
Hex:
beqz $t0, Exit # branch to exit if counter is equal to zero
rol $t2, $t2, 4 # rotate 4 bits to the left
and $t4, $t2, 0xf # mask with 1111
ble $t4, 9, Sum # if less than or equal to nine, branch to sum
addi $t4, $t4, 55 # if greater than nine, add 55
b End
Sum:
addi $t4, $t4, 48 # add 48 to result
End:
sb $t4, 0($t3) # store hex digit into result
addi $t3, $t3, 1 # increment address counter
addi $t0, $t0, -1 # decrement loop counter
j Loop
Exit: la $a0, result1
li $v0, 4
syscall
la $v0, 10
syscall
It looks like you have a typo at line 29 beq $t2,16,hex should be beq $t2,16,Hex. Note the capital letter on Hex. You also have a number of undefined labels: Loop, oct, bin... Without those labels you are going to have issues. It is a good idea to just set some up as place holders (until you have their subroutines defined). Maybe have them all branch to Exit:. The assembler cannot resolve your branch instructions without having the actual labels to go to.
You haven't stored anything in $t7, so there's no particular reason to expect that $t7 would equal 16.
What you probably wanted to write is:
beq $t1,16,hex
Since $t1 is the register that you stored the base in.
However, I really don't see why you would want that jump with the way the code currently is structured. The hex subroutine relies on a few registers (like $t0 and $t3) to have been initialized to certain values, and that initialization would be skipped if that beq is taken.