I'm really struggling with mips it seems, I've read multiple tutorials on how to make arrays and access them, but whenever I try doing the listed methods, my program does nothing.
currently I have this code:
.data
array: .word 1:32 # array of 32 integers
line: .asciiz "\n"
main:
li $t0, 0 # $t0 is the loop induction variable
li $t1, 32 # $t1 is the sentinal value for the loop
la $t2, array # $9 starts as the base address of the array
# and is the address of each element
li $t3, 1 # $12 is the value 18, to be put in desired element
for:
bge $t0, $t1, end_for
sw $t3, ($t2)
li $v0, 4
la $a0, line
syscall
li $v0, 1
move $a0, t3
syscall
add $t2, $t2, 4 # get address of next array element
add $t0, $0, 1 # increment loop induction variable
b valfor
valfor:
addi $t3, $t3, 1
b for
end_for:
li $v0, 10
syscall
When trying to run this, my code immediately finishes. It doesn't list any errors or do anything funny, it just says -- program is finished running (dropped off bottom) --
If someone could point me in the right direction as far as creating, accessing and printing an array of integers I would appreciate it a huge amount.
sites I thought I interpreted accurately to come up with my code:
http://pages.cs.wisc.edu/~cs354-2/onyourown/arrays.html
http://courses.cs.vt.edu/~cs2505/fall2010/Notes/pdf/T23.MIPSArrays.pdf
Have you actually tried to run the code that you put in your question? It contains the line move $a0, t3, which won't assemble in SPIM because of the missing $ sign (t3 should be $t3).
Apart from that I see at least two problems with your code:
You have an infinite loop because of this line:
add $t0, $0, 1 # increment loop induction variable
That just does $t0 = 1. It should be changed to add $t0, $t0, 1.
The other problem is that you've put your code in the data section. The code should be in the text section, i.e. right before main: you should have:
.text
.globl main
Related
So the assignment is to make a 'calculator' that can store 10 inputs into an array, sort them from smallest to largest value and then add them all together, but no matter how i try the output doesn't print out the numbers and the sum. I'm not sure where I went wrong so if anyone could take a look at it it would be very much appreciated.
.data
array: .space 40 #space for array
msg1: .asciiz "Welcome to sorting calculator!\n"
msg2: .asciiz "Please enter 10 random numbers:\n"
msg3: .asciiz "Sorting your inputs...\n"
msg4: .asciiz "Numbers in ascending order\n"
msg5: .asciiz "Total sum of your input:"
.text
.globl main
main:
#Print string msg1
li $v0,4 # print_string syscall code = 4
la $a0, msg1 # load the address of msg1
syscall
#Print string msg2
li $v0,4 # print_string syscall code = 4
la $a0, msg2 # load the address of msg2
syscall
li $t0, 0 #counter for i
loop1: #First loop
beq $t0, 10, sort #end loop when equal to 10
li $v0, 5 #get input of integer from user
syscall
sw $v0, array($t1) #Store the result in array
addi $t0, $t0, 1 #++i
j loop1
sort:
#Print string msg3
li $v0,4 # print_string syscall code = 4
la $a0, msg3 # load the address of msg3
syscall
li $t0, 0 #counter for i
loop2: #for(int i = 0; i < 10;i++)
li $t1, 1 #counter for k
beq $t0, 10, end_loop2 #end loop when equal to 10
loop3: #for(k=i+1; k<11; k++)
beq $t1, 11, end_loop3 #end loop when equal to 11 (10+1)
lb $t6, array($t0) #load numbers[i] into t6
lb $t7, array($t1) #load numbers[k] into t7
bgt $t6,$t7,if #jump to if when $t6>$t7
addi $t1, $t1, 1 #increment k by 1
j loop3 #jump back to loop3
if:
lb $t2, array($t0) #store numbers[i]
lb $t3, array($t1) #store numbers[k]
sb $t3, array($t0) #numbers[i] = numbers[k]
sb $t2, array($t1) #numbers[k] = temp
j loop3 #jump back to loop3
end_loop3:
addi $t0, $t0, 1 #increment i by 1
end_loop2:
#Print string msg4
li $v0,4 # print_string syscall code = 4
la $a0, msg4 # load the address of msg4
syscall
li $t0,0 #initialize i
loop4:
beq $t0, 10, sec5 #end loop when equal to 10
lb $t5, array($t0) #load numbers[i]
li $v0,1 #print_integer syscall code = 1
addi $a0, $5,0
addi $t0, $t0, 1 #increment t0 by 1
j loop4
sec5:
#Print string msg5
li $v0,4 # print_string syscall code = 4
la $a0, msg5 # load the address of msg5
syscall
li $t0, 0 #counter for i
loopsum: #loop to calculate sum
beq $t0, 10, printsum #end loop when equal to 10
lb $t8, array($t0) #load numbers[i]
add $s7, $s7, $t8 #sum+=numbers[i]
addi $t0, $t0, 1 #increment t0 by 1
j loopsum
printsum:
li $v0,1 # print_integer syscall code = 1
addi $a0, $t4,0
syscall
end:
li $v0, 10
syscall
Basic Debugging Skills
Static Debugging Skills
Write pseudo code in C and make sure it works. It sounds like work but is actually a simplification — it is very hard to find algorithmic & design flaws in assembly language when you're first learning assembly. Small design fixes in pseudo code can also result in larger change in assembly.
Translate your pseudo code into assembly with rigor. Don't "optimize" during translation to assembly — if you want to optimize, do that in the pseudo code. Here I'm talking about, for example, converting the algorithm from using indexing into pointers (do that translation in the pseudo code in C and make sure it works), or, changing a while loop into a repeat until.
Read the assembly code and look for flaws. Compare register sources and targets with variable names from your pseudo code — it is surprisingly easy to have a typo. Run parts of the code in your head. Look for off-by-one errors; make sure loops have proper exit conditions, and maintain proper state for each iteration. Compare with your pseudo code and make sure each piece is present and in the right place.
Dynamic Debugging Skills
Anyone writing assembly language should be able to single step and watch/verify their code execute.
Single step and verify that each instruction does what you expect. Most instructions have a main effect: change the value of a register, or change the value of memory. And all instructions tell the processor what instruction to run next. So, we need to verify the main effect and the control flow (what instruction comes next). (syscalls can change multiple memory locations and offer a return result as well.)
When you're debugging fresh code that's never been tested, use the smallest possible input to make debugging simple. Expect typos in your code, such as wrong register source, wrong register target, etc..
As you evolve your program, use breakpoints to skip over code that you already know is working, then single step the new code from there.
When you can, use the smallest possible input and try debugging with that first, then make it larger. In this case, you could change your 10 to a 1 or 2 to make it easier to single-step and find the most basic bugs.
I found your first bug after single-stepping of less than 30 instructions from the beginning. You should have been able to do this.
The user entered data is being stored in the first word of your array. Since you neither initialize nor increment the index $t1, all the words are stored in the same place, each one overwriting the prior. Maybe should have been $t0, but that would have to be scaled for word size. So, maybe you're missing an instruction to scale $t0 and put that value into $t1.
Running my code freezes Mars.
At first my error message was saying that my second while label was already declared, so I changed its name to while2.
I've changed my t registers in the second while loop from t0 to t1, created separate print integer procedures to display both arrays, changed my t6 register to t7 in the second array to load the element value for printing.
Here is what I have so far:
.data
#declaring array with 12 bytes to hold 3 integers
#myArray: .space 12 #uninitialized
#declaring and initializing a 3 element long array with 100 as value
#default value of each element is 100
myArray: .word 100:3 #3 elements long, each element is 100
myArray2: .word 24:5 #5 elements long, each element is 24
#print a new line
newLine: .asciiz "\n"
#main title
mainTitle: .asciiz "This program displays array elements that have already been initialized when the array was created.\n"
exitMessage: .asciiz "This is the end. "
.text
#main procedure
main:
#displaying main title
li $v0, 4
la $a0, mainTitle
syscall
#calling function to display 3 element array
jal displayMyArray
jal printNL
#calling function to display 5 element array
jal displayMyArray2
#closing statement for main procedure
li $v0, 10
syscall
#function to display integer for first array
printInt1:
li $v0, 1
addi $a0, $t6, 0
syscall
#closing statement
jr $ra
#function to display integer for second array
printInt2:
li $v0, 1
move $a0, $t7
syscall
#closing statement
jr $ra
#function to display new line
printNL:
li $v0, 4
la $a0, newLine
syscall
#closing statement
jr $ra
#function to display 3 element array of 100
displayMyArray:
#setting t0 register to value of 0
addi $t0, $zero, 0
#while loop to display all the elements of myArray
while:
#test condition
beq $t0, 12, exit #if t0 = 12, then break out of while loop
#load current element to register t0
lw $t6, myArray ($t0)
#updating offset
addi $t0, $t0, 4
#calling printInt to display current number
jal printInt1
#calling printNL to print new line
jal printNL
j while #iterator
exit:
li $v0, 4
la $a0, exitMessage
syscall
#closing statement
jr $ra
#function to display 5 element array
displayMyArray2:
#setting t0 register to value of 0
addi $t1, $zero, 0
#while loop to display all elements of myArray2
while2:
#test condition
beq $t1, 20, exit2 #if t0 = 20, then break out of while loop
#load current element to register t0
lw $t7, myArray2 ($t1)
#updating offset
addi $t1, $t1, 4
#printing current number
jal printInt2
#printing new line
jal printNL
j while #iterator
exit2:
li $v0, 4
la $a0, exitMessage
syscall
#closing statement
jr $ra
It isn't hanging the simulator, you have an infinite loop.
As you single step, you should notice that the control flow is messed up.
Several of your functions don't return to where they should (when they do jr $ra) because you've changed the $ra value by using jal without first preserving $ra.
When one function, f, calls another function, g, using the jal instruction, which is the right thing to use to call a function, that call/jal to g repurposes the $ra register, so if you were planning to return from the one function, f, back to its caller, you have to have preserved that value for later use.
I have to create a mips code which it has to tell me if a random number (given by the user) is in the array (1) or its not (0). I have two problems, the first one is that the random number that I´m trying to ask to the user (li $v0, 5 -- syscall -- move $t0, $v0) its not working, in fact it does nothing when I assemble it.
The second problem is weird, I have 2 loops (target) and (exit loop), the first one to check if a number is on any of the array position (10 positions) and the second to exit with a 0 if it didn't find the number.
Any ideas?
iterator = 4
N = 10
.data
vector: .word 2, 3, 5, 6, 8, 1, 3, 2, 5, 9
.text
main:
lw $t2, buscador
li $t1, iterator
la $s1, vector
move $s0, $zero
li $v0, 5
syscall
move $t0, $v0
target:
bgt $s0, N, exit_loop
mul $t3, $s0, $t1
addu $t3, $t3, $s1
lw $t3, 0($t3)
addi $s0, $s0, 1
bne $t0, $t3, target
li $s2, 1
move $a0, $s2
li $v0, 1
syscall
exit_loop:
li $s2, 0
move $a0, $s2
li $v0, 1
syscall
li $v0, 10
syscall
There appears to be nothing wrong with your program.
The symbol buscador was not defined, so the program may not have assembled correctly. I commented out the given line. This may have been the only problem.
I did some slight cosmetic cleanup and added some annotations. I also simplified the print integer syscalls [yours would have worked, as is].
I did add an extra jump to a new label exit_program to keep the pass/fail cases separate. Otherwise, you'd have a "fall through" from the pass case to the fail case and you'd get "10" instead of "1" for the pass case.
But, otherwise, I did not (i.e. did not need to) change your logic.
I tested the program and it works on both QtSpim and mars.
Anyway, just to be sure, here's a working version:
iterator = 4
N = 10
.data
vector: .word 2, 3, 5, 6, 8, 1, 3, 2, 5, 9
.text
main:
# NOTE: this symbol was _not_ defined, so spim may have silently not
# run the program
###lw $t2,buscador
li $t1,iterator # get sizeof(vector[0])
la $s1,vector # get vector base address
move $s0,$zero # set vector index to zero
# prompt user for number
li $v0,5
syscall
move $t0,$v0
target:
bgt $s0,N,exit_loop # vector end? if yes, fly
mul $t3,$s0,$t1 # offset = index * iterator
addu $t3,$t3,$s1 # current addr = base + offset
lw $t3,0($t3) # fetch word from vector
addi $s0,$s0,1 # increment the vector index
bne $t0,$t3,target # does value match? if no, loop
# value matches -- output a 1
li $a0,1
li $v0,1
syscall
j exit_program
# we did _not_ find a match -- output a 0
exit_loop:
li $a0,0
li $v0,1
syscall
exit_program:
li $v0,10
syscall
I am having an issue with my code. I am creating a program that will read in a string, save it into an array and then output the number of times each letter is used in the string. For right now I am having an issue with just the output of the string back to the screen. The string is outputted but the loop never exits, the $t2 value is maybe never set to a value?
.data
intro: .asciiz "Andrew Lofgren, Letter Checker Program"
question: .asciiz "\nPlease enter a string for evaluation: "
alphabet: .ascii "ABCDEFGHIJKLMONOPQRSTUVWXYZ"
results: .space 104
string: .space 1024
.text
main:
jal setup
jal analyze
#jal results
li $v0, 10
syscall
setup:
li $v0, 4 # outputing name and program information
la $a0, intro
syscall
li $v0, 4 # asksing for string input
la $a0, question
syscall
li $v0, 8
la $a0, string
li $a1, 1024
syscall
jr $ra # return
analyze:
la $t0, string # taking string and saving into a tmp
move $t2, $t0 # backup of orignal address
find:
beq $t1, 0, print
addi $t0, $t0, 1
j find
print:
blt $t0, $t2, end #PROBLEM HERE
li $v0, 11
lb $a0, 0($t0)
syscall
addi $t0, $t0, 1
j print
end:
jr $ra
$t0 will never be less than $t2, because $t0 continually increases while $t2 remains the same. To solve this, you need a third register, say $t7, which stores the final index of your string. To calculate the last index, simply add the base address of the string to length which you have defined as 1024. Once $t0 is no longer less than 1024 + string, there are no chars left in the string, and thus we branch to end:. This is done and explained further in the code segment below.
print:
li $t7 , 1024 # Load total byte length of the string
add $t7 , $t7 , $t2 # add it to the base address to get the end
slt $t6 , $t0 , $t7 # check to see if cur index < end
beq $t6 , $0 , end # if we hit the end, branch to end
...
For more information on MIPS instructions, visit this page.
I'm working on some MIPS code for my Computer Organizations class, and well I just can't seem to get the MIPS to work correctly and there's not that many MIPS resources online. I'm running the code on PCSPIM. The code is supposed to add 10 to the contents of array2 and store them in array1 and then print array 1. Reworked the code works properly now.
.text
main:
la $t0, array1
la $t1, array2
la $s0, valuec
li $s2, 6
add $t6, $zero, 1 #i = 1
Loop:
addi $t6, $t6, 1 #i++
lw $t2, ($t0)
lw $t5, ($t1)
lw $s1, ($s0)
addu $t2, $t5, $s1
sw $t2, ($t0)
add $t0, $t0, 4
add $t1, $t1, 4
li $v0, 1
move $a0, $t2
syscall
blt $t6, $s2, Loop
li $v0, 10
syscall
.data
array1: .space 20
array2: .word 1,2,3,5,9
valuec: .word 10
PCSPIM prints 0 5 times and returns Exception 7 [Bad data Address] occured and ignored
This is homework so I'm only going to give you clues for now and add to it as you go. A couple of things:
1/ You need to tell us what it's supposed to do. That's the most important thing.
2/ You store array1 address into t0 then reuse t0 within the first loop.
3/ You appear to be confused about addresses and the contents of those addresses ("la $s0, valuec" and "addu $t0, $t1, $s0").
UPDATE:
Actually I have to sign off for a while, so I'll post my solution so as to not leave you in the lurch.
The confusion I referred to before was the fact that you're loading up two addresses into $t1 and $s0, then adding them together to get another address - this is likely to be well beyond your data area (you should really be adding an address and an offset).
That's basically the problem you have with your code (both the zeros being printed and the crash). Your best bet would be to fix that and refer to my code below only as a last resort to see how I would have done it. Copying code will not help you in the long term and you would be wise to assume your educator is also checking all web sites for plagiarism.
This is the code I've come up with (quickly, so you'll need to test it - it may have bugs). I suggest you read the comments in great detail to understand what it's doing.
I'll be back in a few hours to see how you're doing. Cheers.
.text
main:
# Initialization of array pointers and loop
la $t0, array1 # address of array 1
la $t1, array2 # address of array 2
li $t2, 1 # element number
li $t3, 6 # upper limit of elements
# Process each word in array 2, adding 10 and placing
# into array 1.
Loop:
lw $t3, 0($t1) # get word from array 2
addi $t3, $t3, 10 # add 10 to word
sw $t3, 0($t0) # store word into array 1
addi $t0, $t0, 4 # move to next entry in array 1 and 2
addi $t1, $t1, 4
addi $t2, $t2, 1 # increment element number
blt $t2, $t3, Loop # loop until all elements done
# Initialize printing loop by going back to start of array 1
la $t0, array1 # address of array 1
li $t2, 1 # element number
# Loop through array 1, printing each element.
pLoop:
lw $t2, 0($t0) # get word from array 1
li $v0, 1 # 'print' command code
move $a0, $t2 # needs value in $a0
syscall # print it
addi $t0, $t0, 4 # move to next entry in array 1
addi $t2, $t2, 1 # increment element number
blt $t2, $t3, Loop # loop until all elements done
li $v0, 10 # 'terminate' command code
syscall # exit
# Data arrays for array 1 and 2
.data
array1: .word 0,0,0,0,0
array2: .word 1,2,3,4,5
There's a number of possible issues, but the most obvious/likely is that you aren't returning from main before the start of your data section.
jr ra