.data
spaceChar: .asciiz " "
#array of 26 elements 1,0,0,0,0 elements = 5*5
array: .word 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9
size: .word 25
endl: .asciiz "\n"
.text
main:
lw $t3, size
la $t1, array # get array address
li $t2, 0 # set loop counter
print_loop:
beq $t2, $t3, print_loop_end # check for array end
li $t5,4 #at 4th element I want next line
beq $t5,$t2,newline #checking..
lw $a0, ($t1) # print value at the array pointer
li $v0, 1
syscall
la $a0, spaceChar # Display a space character between elements
li $v0, 4
syscall
addi $t2, $t2, 1 # advance loop counter
addi $t1, $t1, 4 # advance array pointer
j print_loop # repeat the loop
print_loop_end:
li $v0,10
syscall
newline:
la $a0,endl
li $v0,4
syscall
j print_loop
Im trying to print a 5*5 matrix in MIPS This is a 1 dimensional array in mips of 25 elements, Im traversing through the elements in print_loop and when it hits the 4th element I want to do next line but when I run this (MARS 4.5) is freezing I dont know what Im doing please help
Short answer:
You're infinitely looping on newline.
Long answer:
The problem is
beq $t5, $t2, newline #checking
Once your counter gets 4, it keeps going to newline
newline:
la $a0, endl
li $v0, 4
syscall
j print_loop
Then it goes back to print_loop
print_loop:
beq $t2, $t3, print_loop_end #check for array end
li $t5, 4 #at 4th element I want next line
beq $t5, $t2, newline #checking
Uh-oh. We're back to our beq again! If you use the step-by-step debugger (the green arrow with a 1 next to the green arrow that runs), you'll see that you print the first row and then infinitely print newlines. Looks to me like you could just add another label in there after that beq.
In the future, I'd suggest commenting every single line and dividing code into chunks that complete objectives. For example:
# print value at the array pointer
lw $a0, ($t1) # print array[index]
li $v0, 1 # syscall: print integer
syscall
# print space
la $a0, spaceChar # print character " "
li $v0, 4 # syscall: print string
syscall
It's tedious, but it'll helps you sniff out bugs when everything is written in pseudocode. (plus, when someone asks a MIPS question on stackoverflow that you want to answer in a couple years, it helps you remember what the commands do! :P)
Oh, and you can just do
beq $t2, 4, newline
instead of
li $t5, 4
beq $t5, $t2
MIPS can be tricky. Just take it slow and document EVERYTHING. Good luck!
Related
I've just started to learn MIPS, and as part of our assignment, I'm trying to save a counter value that runs inside a loop.
So, I was able to exit the loop, thanks to Michael. But now the counter will not increase, I noticed that it won't enter the incount label.
.text
.globl main
main:
# get string from user
la $a0, str1 # load the addr of the given string into $a0.
li $v0, 4 # 4 is the print_string syscall.
syscall # do the syscall.
li $v0, 8 # take in input
la $a0, buffer # load byte space into addr
li $a1, 10 # allot the byte space for the string
move $t0, $a0 # save the string into $to
syscall
# get char from user
la $a0, char1 # load the addr of the given char into $a0.
li $v0, 4 # 4 is the print_string syscall.
syscall # do the syscall.
li $v0, 8 # take in input
la $a0, buffer # load byte space into addr
li $a1, 10 # allot the byte space for the char
move $t1, $a0 # save the char into $t1
syscall
addi $s2, $zero,0 # s2 holds the counter
loop:
lb $t3, ($t0)
beq $t3, $t1, incount # go to incount if char was found
beqz $t3, exit # go to exit if we arrived to the end of the string
addi $t0, $t0, 1 # incrase t3 by 1
j loop # go to loop
incount:
addi $s2, $s2, 1 # increase the counter by 1
addi $t0, $t0, 1 # incrase char pos by 1
j loop # go back to loop
exit:
la $a0, ($s2) # counter to be printed
li $v0, 1 # 1 is the print_int syscall.
syscall
li $v0, 10 # return control to SPIM OS
syscall
.data
buffer: .space 10
str1: .asciiz "Please enter your string: "
char1: .asciiz "Now, please enter your char of choice: "
# end countchar.s
Thanks in advance
You've placed your exit routine in the .data section, which is why you're getting the "invalid program counter value" error message. All code needs to be in the .text section.
.data
prompt1: .asciiz "\n\n Enter an integer please:"
array: .space 24
linefeed: .asciiz "\n"
enterkey: .asciiz "Press any key to end program."
.text
main:
li $s0, 0
for:
bge $s0, 6, end_for
li $v0, 4 #syscall to print string
la $a0, prompt1 #address of string to print
syscall
li $v0, 5 #syscall to read an integer
syscall
move $t1,$v0
sw $t1,array($t0) #save the number to read into array
addi $t0,$t0,4
addi $s0,$s0,1
j for
end_for:
# print out a line feed
li $v0,4 # code for print_string
la $a0,linefeed # point $a0 to linefeed string
syscall # print linefeed
# wait for the enter key to be pressed to end program
li $v0,4 # code for print_string
la $a0,enterkey # point $a0 to enterkey string
syscall # print enterkey
# wait for input by getting an integer from the user (integer is ignored)
li $v0,5 # code for read_int
syscall #get int from user --> returned in $v0
# All done, thank you!
li $v0,10 # code for exit
syscall # exit program
this is my code.I am trying to store 6 integers in an array and then read again the array of integers and sum them and then printing the sum.I apologize for my bad english
It would be basically the same loop you have just written, but instead of writing the number to the array you would have to read it from the array and sum the values.
E.g.:
li $s0, 0
li $a0, 0
li $t0, 0
forsum:
bge $s0, 6, end_forsum
lw $t1,array($t0) # Load the number from array
addu $a0, $a0, $t1 # Compute the sum
addi $t0,$t0,4
addi $s0,$s0,1
j forsum
end_forsum:
li $v0,1
syscall # Print sum
You can also compute the sum while reading the values from the user input...
.data
array: .word 0:5
prompt1: .asciiz "enter number: "
newline: .asciiz "\n"
.text
add $t2,$zero,$zero # initializes counter to 0
la $s0, array # stores the beginning of array into $s0
secretcode:
li $v0, 4 # prints "enter number: "
la $a0, prompt1
syscall
li $v0, 5 # reads in user input
syscall
sw $v0, ($s0) # saves user input into address at $s0
addi $s0, $s0, 4 # increments address at $s0 by 4 bytes
addi $t2, $t2, 1 # increments counter by 1
bne $t2, 5, secretcode # stops loop when loop executes 5 times
printsecretcode:
lw $a0, ($s0) # print first element
li $v0, 1
syscall
li $v0, 10 # system code halt
syscall
The program is supposed to store 5 user inputted numbers into an array. I tried to print the first value but it comes up as a large number which I assume is an address. How would I print the actual value of the number so that I know it saved correctly?
By the time you reach your printing code $s0 contains the address array + 4*5, so what you end up printing is the 32-bit number formed by the first four characters of the "enter number: " string.
To fix this, add an la $s0, array before you try to print the first element.
I am trying to make a loop that will add user inputted integers into an array until it fills the array. Every time I typed in a value, QTSPIM spits out 268501016 which I assume to be some random value stored in an register.
To test if my program was going through the whole loop, I added a call to an ascii line when the program reached the branch portion of my beq. The program seemed to be branching even if the values were not (at least to my understanding) equal.
.data
array1: .space 24
str1: .ascii "Type in numbers:"
str2: .ascii "Reached Terminate"
.text
main:
li $t2, 5
li $t3, 0
loop1:
beq $t3, $t2, terminate #branch if equal
la $a0, str1
syscall
ori $v0, $0, 5 #instruction to store user input in v0
syscall #get user input and store it in v0
la $t4, array1 #load the address of the array
addu $t0, $0, $v0 #add v0 (our user input) to $t0
sw 0($t4), t0 #stores the value in $t4 to our array
addi $t3, $t3, 1 #add 1 to t3 (incrementing the counter)
addi $t4, $t4, 4 $add 4 to increment the array 4 bits to the next array slot
jal loop1
terminate:
la $a2, str2 #load the string to check when the program reaches terminate
syscall
ori $v0, $0, 10 # end the program
syscall
The only thing I can think is that my jump call is not going back to loop1, but if this is the case I am unaware how to fix that.
This is 32 bit MIPS code.
You're not setting up the registers properly before the syscalls.
Here there should be an li $v0, 4 before syscall:
la $a0, str1
syscall
If we assume that you're trying to print str2 here, there should be an li $v0, 4 before the syscall, and $a0 should be used instead of $a2:
la $a2, str2 #load the string to check when the program reaches terminate
syscall
This should be sw $t0, 0($t4), not the other way around:
sw 0($t4), t0
This should be j, not jal (jal is used for function calls):
jal loop1
I can understand and use Java/c++ to a good extent, but for the life of me assembly just confuses me there are 2 functions I'm having trouble with. First:
One function that receives a string and prints it on the terminal
And another one that receives a string and converts it to integers (Strings given all made of numbers).
Any idea on where to start?
Update
On the second function, so far I got this:
main:
atoi:
li $v0, 8
la $a0, tstr
li $a1, 64
syscall
sub $sp, $sp,4
sw $ra, 0($sp)
move $t0, $a0
li $v0, 0
next:
lb $t1, ($t0)
beqz $t1, endloop
mul $v0, $v0, 10
add $v0, $v0, $t1
sub $v0, $v0, 48
add $t0, $t0, 1
b next
endloop:
lw $ra, 0($sp)
add $sp, $sp, 4
Updated code, still getting the error on 10 being an invalid operand. And about sub $v0, $v0, 48 should I just do it as sub $t1, $t1, 48?
For input-output stuff, you have to use system calls. For writing (zero-terminated) strings you'll use syscall #4, which wants the address of the buffer in $a0. Now just place the umber of the syscall in $v0 and execute it. For example, this snippet reads a string:
li $v0, 8 # syscall number
la $a0, theString # buffer
li $a1, 64 # length of buffer
syscall # read!
Here you can find some syscalls numbers.
For the second exercise, here's the C++ code, try to translate it :P
int result = 0;
while (*digit >= '0' && *digit <='9') { // digit is char *
result = (result * 10) + (*digit - '0');
digit++;
}
EDIT:
Ok, there are a couple of errors. First, you're not checking whether you've reached the end of the string (simply compare $t1 with 0 at the beginning). And you should first subtract '0' from $t1, then add it to $v0.
next:
lb $t1, ($t0)
# are there other character or this is the last one?
mul $v0, $v0, 10
add $v0, $v0, $t1
sub $v0, $v0, 48 # subtract 48 only from $t1, not from whole result
add $t0, $t0, 1
b next