MIPS getting an error when running my code - mips

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

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

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.