How to count the number of words and print the result in mips? - 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

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

MIPS Printing Values of a Given Array

I am trying to print on the console the values of the array, which are already given as intA in .data. I.e., trying to print values of an array without user's prompt.
My code:
.data
prompt: .asciiz "The values in the array are:\n"
finished: .asciiz "\nNo more values to present"
space: .asciiz " "
intA: .word 11, 2, 3, 4, 5, 34, 0
.text
.globl main
main:
#Prints the prompt string
li $v0, 4
la $a0, prompt
syscall
# initialization of a0, a1, and t3 (i, counter)
la $a0, intA # loading starting address (base) of array in register a0
addi $a1, $zero, 6 # array size - 1
addi $t3, $zero, 0 # i initialized to 0
j loop
loop:
lw $t1, 0($a0) # loading integer (value of array) in the current address to register t1, I use lw because integer is a word (4 bytes)
# printing current value of array
li $v0, 4
la $a2, ($t1)
syscall
# spacing between values
li $v0, 4
la $a2, space
syscall
# checking that next address is not outside of the array
addi $t3, $t3, 1
slti $t2, $t3, 6
bne $t2, 1, done
# accessing next integer and jumping back to print it
addi $a0, $a0, 4
j loop
done:
# indicating program is done
li $v0, 4
la $a0, finished
syscall
The output that I am getting: output
Any idea why it doesn't print the values of the array, and also what are these squares that are printed instead?
Edit:
I changed
# printing current value of array
li $v0, 4
la $a2, ($t1)
syscall
to
# printing current value of array
li $v0, 1
lw $a2, ($t1)
syscall
Because, from what I understand, I print an integer so $v0 should be fed 1, and I should lw and not la (because it is an integer, i.e, a word)
However, now I get a runtime error in line 31: lw $a2, ($t1) Telling me that
fetch address not aligned on word boundary 0x0000000b
Solution: Instead of lw $a0, ($t1) for printing the value of $t1, I need to do add $a0, $t1, $zero, because I am trying to use the value and not to access an address.

Learning MIPS: Creating a simple program to read numbers and print them

I'm struggling with learning MIPS right now, and I'm finding it isn't as easy as C++ was.
Right now, I'm to edit/write a program that will take ten number's from a user, then print those numbers out at the end with commas between them, and no comma after the last number. Example:
Enter a number 1
Enter a number 2
Enter a number 9
Enter a number 11
Enter a number 99
Enter a number 12
Enter a number 24
Enter a number 90
Enter a number 17
Enter a number 82
1, 2, 9, 11, 99, 12, 24, 90, 7, 82
This is the given code:
.data
.space 40 # set aside 40 bytes for 10 integers
prompt:
.asciiz "Enter a number " # address 0x10010028
comma:
.asciiz ", " # address 0x10010038
.globl main
.text
main:
lui $a0, 0x1001 # get start of data segment
jal getdata # call getdata function
lui $a0, 0x1001 # get start of data segment
jal print # call print function
ori $v0, $0, 10 # set command to exit
syscall # end program
getdata:
addi $sp, $sp, -4 # allocate space on stack
sw $ra, 0($sp) # save $ra
ori $t1, $a0, 0 # address of array
lui $t1, 0x1001 # start of data
ori $a0, $a0, 0x0028 # address of prompt
ori $t0, $0, 10 # counter
top:
beq $t0, $0, ret # while not 0
jal printstr # call function to print prompt
ori $v0, $0, 5 # set command to read integer
syscall # read int
sw $v0, 0($t1) # save int in memory
addi $t1, $t1, 4 # increment to next location
addi $t0, $t0, -1 # decrement counter
j top # repeat
ret:
lw $ra, 0($sp) # restore return address
addi $sp, $sp, 4 # clean up stack
jr $ra # return from call
# print
# parameter: $a0 holds address of list in memory
# purpose: print the list separated by commas
print:
#to be completed
jr $ra
# printstr
# paramters: $a0 holds address of string to print
# purpose: print the string parameter
printstr:
#to be completed
jr $ra
Where I believe I'm struggling at is the "print" portion. I have the
following for printstr: and for getdata:
printstr:
ori $v0, $0, 4 # command to print string at $a0
syscall
jr $ra # return from call
getdata:
addi $sp, $sp, -4 # allocate space on stack
sw $ra, 0($sp) # save $ra
ori $t1, $a0, 0 # address of array
lui $t1, 0x1001 # start of data
ori $a0, $a0, 0x0028 # address of prompt
ori $t0, $0, 10 # counter
And then this is the code I've been trying to use for the loop...
print:
addi $t2, $t2, 10
addi $t0, $t0, 1 # Enter into the loop by increment 1
ori $v0, $0, 4 # Print the 1st value and then loop
# start from the 2nd value
syscall
jal loop # Jump to loop
loop:
beq $t0, $t2, end # checks if t2=t0, if it does then ends the program
lui $t3, 0x1001 # loads the upper limit of t3 to 1001
or $a0, $0, $t3 # sets the upper limit of a0 to 1001
ori $v0, $0, 1 # sets v0 to print integer
syscall # prints integer
addi $t3, $t3, 4 # moves t3 to the next address
ori $a0, $a0, 0x0038 # sets a0 to the address of comma
ori $v0, $0, 4 # Print string at $a0
syscall
addi $t0, $t0, 1 # increases the value at t0 by 1
jr $ra
However, when I run the program it spits out "268500992, ,". So I'm not getting my input numbers or the correct number of commas even. I know that means that my loop isn't running all the way through. I'm not supposed to use and pseudo code, and only what I've learned so far - so array's are out of the question.
Can someone help me figure out what I'm missing? Does it have something to do with the stack values (which I don't completely understand)?
OK, I think your code for printstr is correct, and getdata also looks fine (a little odd, but you didn't write that, yes?) The bugs are all in print. I'm not going to spell it out for you, because this is homework, but the structure of the loop in print should be very similar to the structure of the loop in getdata:
# on entry, $a0 = address of integer array
print:
ori $t0, $0, 10 # counter
ori $t1, $a0, 0 # t1 points to current array element
print_loop:
### if this isn't the first iteration, print ", "
### load value at $t1 into $a0
### print the integer in $a0
addi $t1, $t1, 4 # advance to next array element
addi $t0, $t0, -1 # decrement counter
bne $t0, $0, print_loop
### print a carriage return
jr $ra # return from call
Each thing prefixed by ### is a placeholder for code you need to write.

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.

displaying the factorial of each value of the index of a loop does not work. MIPS

I am trying to display the factorial of the current value of the index of a loop in MIPS but, my loop does not work at all. It keeps freezing every time I run the code. Let say I have a for loop such that (i=1; i<=5; i++), for each value of i, I would like to display the current factorial(i). The number 5, is actually provided by the user, in other words, the number can change(1-10). I have tried to figure out why my loop causes the code to freeze, but I have no clues so far. Your help will be very appreciated. The code is bellow.
.data # data declaration section; specifies values to be stored
# in memory and labels whereby the values are accessed
Prompt: .asciiz "\nEnter the number to compute the factorial:\n"
message: .asciiz "\nResult of computation is:\n"
result: .word 0
#--------------------------------
# main function |
#--------------------------------
.text # Start of code section
.globl main
main: # Execution begins at label "main". The prompt is displayed.
li $v0, 4 # system call code for printing string = 4
la $a0, Prompt # load address of string to be printed into $a0
syscall # call operating system to perform operation;
# $v0 specifies the system function called;
# syscall takes $v0 (and opt arguments)
# Read integer N
li $v0, 5
syscall
move $t0, $v0 #copy integer N into $t0
li $t1, 1 #initialize i=1
loop:
blt $t0, $t1, exit_loop # if number<1, exit...
move $a0, $t0 # copy N into $ao
jal fact #else call fact
sw $v0, result
li $v0, 4 #Display message
la $a0, message
syscall
li $v0, 1 #print result
lw $a0, result
syscall
sub $t0, $t0, 1 #Decrement N by one, N--
j loop
exit_loop:
jr $ra #return address
exit: #exit the program
li $v0, 10
syscall
.globl fact
.ent fact
fact:
subu $sp, $sp, 8
sw $ra, ($sp)
sw $s0, 4($sp)
li $v0, 1 #check base case
beq $a0, 0, end_fact
move $s0, $a0 #fact(n-1)
sub $a0, $a0, 1
jal fact
mul $v0, $s0, $v0 #n*fact(n-1)
end_fact:
lw $ra ($sp)
lw $s0, 4($sp)
addu $sp,$sp, 8
jr $ra
#end of factorial function
Your problem is in the instruction at exit_loop label:
exit_loop:
jr $ra #return address
You are jumping again into the loop because you haven't saved $ra at the start of your main function and you are also not restoring it before issuing that jr
In fact, your code, as is, should just terminate (syscall 10) and not issue a jump because you are implementing the main function and not a function to be called from elsewhere.
So, i'd change that code to:
exit_loop:
li $v0, 10
syscall
Looking a bit more into your code, you already have that code (on label exit), so you might just remove your exit_loop code and branch to exit instead of exit_loop in the branch that goes just after loop label.