MIPS Store keyboard input (ints) to array - mips

I am trying to take 4 numbers from the keyboard and store it to an array. I have come up with the following code however when I try and print the first number in the array it prints 0. Why is it not printing the first value in the array?
main:
li $v0, 5 # read integer
syscall
add $s0, $v0, $zero #store input1 to s0
li $v0, 5 # read integer
syscall
add $s1, $v0, $zero #store input2 to s0
li $v0, 5 # read integer
syscall
add $s2, $v0, $zero #store input3 to s0
li $v0, 5 # read integer
syscall
add $s3, $v0, $zero #store input4 to s0
.data
list: $s0, $s1, $s2, $s3 #set array from keyboard values
.text
#get the array into a register
la $t3, list # put address of list into $t3
lw $t4, 0($t3) # get the value from the array cell
li $v0, 1 # print integer
move $a0, $t4 # what to print is stored at $s1
syscall # make system call
exit:
li $v0, 10 # exit system call
syscall
Idea taken from:
http://www.cs.pitt.edu/~xujie/cs447/AccessingArray.htm
But they are using hard-coded ints instead of values saved to registers from keyboard.
Thanks for the help.

This:
.data
list: $s0, $s1, $s2, $s3 #set array from keyboard values
.text
does not work this way. You need sw to store the values of registers to memory.
So, at the start of the program, reserve some space to store the values:
.data
list: .space 16
.text
Then, after you read the values, store them with sw:
sw $s0, list
sw $s1, list + 4
sw $s2, list + 8
sw $s3, list + 12

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 $

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 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

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.

MIPS, Recursion

I trying to write a MIPS program that gets an unsigned integer as argument and returns the sum of all decimal digits in the integer recursively. For example if the argument is 75080 then the sum to be returned is 20 (7+5+0+8+0). Here is my code so far. Any help would be appreciated.
My way of thinking was to divide the number by 10 leaving me with the last integer in the number, add the reminder using mfhi.
.data
prompt: .asciiz "Enter a string of integer: "
output: .asciiz "\nThe total sum is: "
.text
.globl main
main:
la $a0, prompt
li $v0, 4
syscall
li $v0, 5
syscall
move $t2, $v0
la $a0, output
li $v0, 4
syscall
Loop:
div $t2, $t2, 10
mflo, $t1
mfhi, $t3
beqz $t1, Exit
add $t1, $t1, 0
b additive
additive:
add $t0, $t1, $t1
j Loop
Exit:
la $a0, output
li $v0, 4
syscall
la $v0, 10
syscall
What's this supposed to be doing? Adding 0 to the register won't change its value:
add $t1, $t1, 0
After dividing and copying to $t1 and $t3, the quotient is in $t1 and the remainder is in $t3. You're treating it the other way around when you add to the total.
This is actually going to give you $t0 = 2 * $t1: you're adding $t1 to itself and storing the result in $t0.
add $t0, $t1, $t1
You probably actually want:
add $t0, $t0, $t3
You're checking for $t1 == 0 before adding the remainder to the total, so the most significant digit will never get added. You don't really need a subroutine for adding to the total either. You can also use bnez Loop instead of beqz Exit -> b Loop. Lastly, you don't even need $t1, because the quotient is already in $t2.
Get rid of additive and replace Loop with this:
Loop:
div $t2, $t2, 10
mfhi, $t3
add $t0, $t0, $t3
bnez $t2, Loop
Your Exit is weird: you're printing the output string a second time instead of printing the integer.
Change it to this:
Exit:
move $a0, $t0
la $v0, 1
syscall
la $v0, 10
syscall
The approach is quite simple. You need recursive function, I named it SumDigits that will take the last digit and repeat procedure for all digits in the argument. After the recursive call returns you'll add digit to the previous result. The code is commented for easier understanding. The code follows:
.text
#calculates sum of digits recursively
SumDigits:
sub $sp, $sp, 12 #alloocate 12B on stack
sw $ra 0($sp) #save return address
sw $a0, 4($sp) #save argument
beq $a0, $0, exit_sumdigits #when there is no more digits return 0
rem $t0, $a0, 10 #get last digit
sw $t0, 8($sp) #save it on stack
div $a0, $a0, 10 #divide argument by 10
jal SumDigits #repeat procedure
lw $t0, 8($sp) #read digit from stack
add $v0, $v0, $t0 #add digit to previous result
lw $ra, 0($sp) #load return address
addi $sp, $sp, 12 #free stack
jr $ra #return
exit_sumdigits:
li $v0, 0 #there are no more digits, return 0
lw $ra, 0($sp) #load return address
addi $sp, $sp, 12 #free stack
jr $ra #return
main:
li $a0, 75080 #load number in $a0
jal SumDigits #call SumDigits
move $a0, $v0 #set a0 = result of SumDigits
li $v0, 1 #set $v0 for print int system call
syscall
li $v0, 10 #set $v0 for exit system call
syscall
.data