I am having trouble writing a delay loop that will return a constant 0x80000. The output should be like Hello, world! 0
Hello, world! 1
Hello, world! 2
...
but when I run my program, the terminal doesn't show anything even though I believe one Hello, world! should be showing up. I tried to figure out what is wrong by debugging the code, but that does not seem to be helping me. Any suggestions on how to fix this?
.ent getDelay
.text
.global getDelay
getDelay:
addi $sp, $sp, -1
sw $ra, 0($sp)
la $a0, helloStr
lw $a1, counter
jal printf
nop
lw $ra, 0($sp)
addi $sp, $sp, -1
lw $t0, ($a1)
addiu $t0, $t0,1
la $t1, counter
sw $t1, ($a1)
$v0 = 0x80000
jr $ra
.end getDelay
.data
helloStr: .asciiz "Hello, world %d\n"
counter: .word 100
You should only ever adjust $sp in multiples of 4 (the word size).
You should use addiu $sp, $sp, -4 and addiu $sp, $sp, 4.
You are incrementing $t0 but then storing $t1. You don't need
the la $t1, counter and instead of sw $t1, ($a1) you should use
sw $t0, ($a1).
$v0 = 0x80000 is not an instruction, you probably want li $v0,
0x80000.
If this function itself is supposed to be some delay, then you need
a loop in it.
Related
I am currently trying to figure out why my mars program for creating an array is getting stuck in an infinite loop. I am trying to create an array using different functions and in the create array function the program is supposed to jump into a get number function and return the value to store it into the array but the counter seems to not be decrementing and it just keeps asking for an element for the array. Here is the code:
.data
str5: .asciiz "Please enter a number of elements for the array between 0 and 20: "
str6: .asciiz "Please enter an element: "
array: .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.text
main:
begin:
li $v0, 4
la $a0, str5
syscall
jal readnum
add $a0, $v0, $0
jal verify
add $a0, $v0, $0
jal createarray
la $s1, array
jal printarray
li $v0, 10
syscall
printarray:
createarray:
add $t0, $ra, $0
add $s0, $a0, $0
add $t9, $0, $0
la $s1, array
loop:
beq $s0, 0, done
li $v0, 4
la $a0, str6
syscall
jal readnum
add $t1, $v0, $0
sw $t1, 0($s1)
addi $s1, $s1, 4
addi $s0, $s0, -1
addi $t9, $t9, 1
j loop
done:
add $ra, $t0, $0
jr $ra
verify:
add $s0, $a0, $0
bge $s0, 20, begin
ble $s0, 0, begin
add $v0, $s0, $0
jr $ra
readnum:
li $v0, 5
syscall
jr $ra
EDIT: After re-reading the code, what is causing the error is actually the following code:
jal printarray
You never did the following code in printarray:
jr $ra
So, it would go back down to the other functions.
Use the $sp (the proper way to handle the $ra when calling functions within functions)
The following segment is the cause of the problem:
syscall
jal readnum
add $t1, $v0, $0
Moreso specifically the jal call. Calling a function within a function requires some more steps to be taken place.
First, understand what the jal instruction is doing. The jal instruction, put simply, marks where you currently are and stores it in the $ra register. Then, it will jump to that function.
But there's a problem: you are already wishing for the $ra register to remember where you once were because you, in fact, called createarray!
So, you called createarray, making $ra store where you once were, then within that function you called readnum, making $ra store where you are in createarray. **But now, you have lost where you once were before called createarray. So, it will keep looping back to what $ra used to be, which is inside your createarray function.
Fortunately, the $sp register is just what you need
How to use the $sp register
To store where we are, we push to the stack:
addi $sp, $sp, -4 # by convention, we use negative numbers when pushing
sw $ra, ($sp)
To get where we once were after we called the function (which replaced our $ra in the first place), we pop the stack:
lw $ra, ($sp)
addi $sp, $sp, 4 # by convention, we use positive numbers when popping
So in the grand scope of things, here is what you do:
# push to the stack
addi $sp, $sp, -4
sw $ra, ($sp)
jal theFunctionWeWantToCallInOurFunction
# pop the stack, get back our $ra
lw $ra, ($sp)
addi $sp, $sp, 4
Let's apply this solution to your codebase:
.data
str5: .asciiz "Please enter a number of elements for the array between 0 and 20: "
str6: .asciiz "Please enter an element: "
array: .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.text
main:
begin:
li $v0, 4
la $a0, str5
syscall
jal readnum
add $a0, $v0, $0
jal verify
add $a0, $v0, $0
jal createarray
la $s1, array
jal printarray # comment off this line and you won't have an infinite loop
li $v0, 10
syscall
printarray:
createarray:
add $t0, $ra, $0
add $s0, $a0, $0
add $t9, $0, $0
la $s1, array
loop:
beq $s0, 0, done
li $v0, 4
la $a0, str6
syscall
# store where we wish to come back to so that $ra can be overriden without losing data.
addi $sp, $sp, -4
sw $ra, ($sp)
# call the function. jal will replace our current $ra
jal readnum
# retrieve what our $ra once was
lw $ra, ($sp)
addi $sp, $sp, 4
add $t1, $v0, $0
sw $t1, 0($s1)
addi $s1, $s1, 4
addi $s0, $s0, -1
addi $t9, $t9, 1
j loop
done:
add $ra, $t0, $0
jr $ra
verify:
add $s0, $a0, $0
bge $s0, 20, begin
ble $s0, 0, begin
add $v0, $s0, $0
jr $ra
readnum:
li $v0, 5
syscall
jr $ra
I'm trying to read multiple strings from a file and store them all together. The way the input is designed, the following preconditions are guaranteed:
The number of string I have to read in is pre-determined
The length of all strings (including a newline and a NUL-byte) is the same
I have the following code, however I've been running into an unaligned memory word reference error the second time the loop is entered.
.data
.align 4
aLine:
.space 128
arr:
.space 1024
.text
//...
//...
build:
addi $sp,$sp,-24
sw $ra, 20($sp)
sw $s4, 16($sp)
sw $s3, 12($sp)
sw $s2, 8($sp)
sw $s1, 4($sp)
sw $s0, 0($sp)
li $t0,0 #incrementing value for index
move $s0,$a0 #$a0 is the number of strings
addi $s1,$a1,2 #$a1 is the length of each string, $s1 makes room for the newline character and the null
la $a2,arr
build_loop:
beq $t0,$s0,build_done
li $v0, READ_STRING #READ_STRING is set to 8 earlier in the program
la $a0,aLine
move $a1,$s1
syscall
mul $t1,$t0,$s1
add $t2,$t1,$a2
sw $v0,($t2)
addi $t0,$t0,1
jal build_loop
build_done:
lw $ra, 20($sp)
lw $s4, 16($sp)
lw $s3, 12($sp)
lw $s2, 8($sp)
lw $s1, 4($sp)
lw $s0, 0($sp)
addi $sp,$sp,24
jr $ra
I got this mostly from an online resource on creating an array of integers, tweaking the values to work with strings of a constant length.
What exactly am I missing here?
You are using jal build_loop, which is effectively recursion, not iteration.Unfortunately, jal build_loop stores the return address to a register, (load-store-architecture, remember?) which happens to be $ra (GPR 31). This clashes badly with the rest of build_loop, which neglects to save $ra on the stack.The result is, of course, that $ra is clobbered.
I am making a program for a user to input a range of numbers, and calculate the min, max and median. Right now, I am only trying to collect the numbers and echo them back to make sure I am getting them. Here is the problem:
I input numbers like this:
1
2
3
4
5
And when the array is printed out I get:
15345
It does not matter what numbers are used, the 2nd element in the array is always replace by the last element.
Here is my mips code, I know it is kind of long, but it is the shortest workable example I can make.
Note: you must enter 9999 for the program to exit the loop.
.data
welcomeString: .asciiz "Please input one number at a time, and then press enter.\n"
intArray: .word 4000
size: .word 0
.text
main:
li $v0, 4
la $a0, welcomeString
syscall
la $a0, intArray
jal gather_numbers
la $a0, intArray
jal print_array
####################################################################################
gather_numbers:
addi $sp, $sp, -12
sw $a0, 0($sp)
sw $s0, 4($sp)
sw $s1, 8($sp)
sw $t1, 12($sp)
move $s0, $a0 #the address of the array
lw $s1, size # load the size
li $t1, 0 # so it enters the loop
start_gather_numbers: beq $t1, 9999, exit_gather_numbers
li $v0, 5 # read the integer
syscall
sw $v0, 0($s0)
move $t1, $v0 # put the value into t1 to be tested
addi $s0, $s0, 4 #increment the address
addi $s1, $s1, 1 # increment the size
j start_gather_numbers
exit_gather_numbers: addi $s1, $s1, -1 # fix the size
sw $s1, size # store the size
lw $a0, 0($sp) # pop the stack
lw $s0, 4($sp)
lw $s1, 8($sp)
lw $t1, 12($sp)
addi $sp, $sp, 12
####################################################################################
####################################################################################
print_array:
addi $sp, $sp, -16
sw $a0, 0($sp)
sw $s0, 4($sp)
sw $s1, 8($sp)
sw $t0, 12($sp)
sw $t1, 16($sp)
move $s0, $a0 # the address of the array
lw $s1, size # load the size of the array
li $t0, 0 # i = 0
start_print_array: bge $t0, $s1, exit_print_array
lw $t1, 0($s0) # load the int to print
li $v0, 1 # print the integer
move $a0, $t1
syscall
addi $s0, $s0, 4
addi $t0, $t0, 1
j start_print_array
exit_print_array: lw $a0, 0($sp)
lw $s0, 4($sp)
lw $s1, 8($sp)
lw $t0, 12($sp)
lw $t1, 16($sp)
addi $sp, $sp, 16
There are a few things going wrong here.
Firstly all of your functions are missing the terminating jr $ra.
Also, your stack manipulation is wrong. You are consistently allocating 4 less bytes than you use. If you want to put 5 words on the stack you should expand the stack by 20 not 16.
Most importantly though here is your intArray directive. You have used .word 4000 I'm guessing to allocate an array of ints, but rather you have allocated space for 1 word with the value 4000.
To instead allocate an array of 1000 ints you could use .space 4000 or equally .word 0:1000.
When I made these changes your program began to function as desired.
So I have been working on this for a few days now, and I have managed to get through all of it except one part is getting me.
int mystery(int a0)
{
if (a0 == 0)
{
return 0;
}
else
{
return mystery(a0 - 1) + a0;
}
}
I have this recursive function and I have some MIPS code. The C code works but I have a problem somewhere in my MIPS code that is making it not come out correctly beyond putting in 2.
.text
main:
li $a0, 2
jal mystery
move $a0, $v0
jal putDec
li $a0, '\n'
li $v0, 11
syscall
li $a0, 3
jal mystery
move $a0, $v0
jal putDec
li $a0, '\n'
li $v0, 11
syscall
li $v0, 10
syscall
putDec:
li $v0, 1
syscall
jr $ra
mystery:
bne $0, $a0, recur
li $v0, 0
jr $ra
recur:
sub $sp, $sp, 8
sw $ra, 4($sp)
sub $a0, $a0, 1
jal mystery
sw $v0, 0($sp)
jal mystery
lw $t0, 0($sp)
addu $v0, $v0, $t0
addu $v0, $v0, 1
add $a0, $a0, 1
lw $ra, 4($sp)
add $sp, $sp, 8
jr $ra
Everything up to the label 'mystery' is fine it is just there as a formality to actually put in arguments and print after. The problem I am having is getting values above 3 to print out the right numbers. Help would be greatly appreciated if someone could see where I am making my mistake. Thank you
Try taking a step back, and comparing the structure of the C and assembly code, without worrying too much about the details.
In the C code, there is a conditional, leading to either a base case (which just returns a value) or the recursive case. The recursive case performs a subtraction, the recursive call to mystery, and an addition.
Now look at the assembly version: this, too, has a conditional leading to either a base case or a recursive case. But look at the structure of the recursive case: there are two recursive calls to mystery there! That's a strong hint that it's unlikely to be doing the same thing...
Whoo after extensive work and tracking the code one step at a time I think I finally got it, had to do quite a bit of changing but actually seems easier now. Here is the code in case you want to look over it again, if you can see a problem that could arise with any certain values I did not test. Thanks for the help all.
New recursive mystery function:
mystery:
bne $0, $a0, recur
li $v0, 0
jr $ra
recur:
sub $sp, $sp, 8
sw $ra, 4($sp)
sw $a0, 0($sp)
sub $a0, $a0, 1
jal mystery
lw $t0, 0($sp) #
addu $v0, $v0, $t0
lw $ra, 4($sp)
add $sp, $sp, 8
jr $ra
Thanks again. :)
you're suppose to return the ASCII symbol, change "li $v0, 1" in putDec to "li $v0, 11" (that was not a mistake)
How to find length of an array in mips,spim?
I wrote this for practice. I tested it, and it works well. You probably already figured this out, but if not, there it is.
.data
array1: .word 1,2,3,4,5,6,7,8,9
.text
main:
la $a0,array1
jal lenArray
move $a0,$v0
syscall $print_int
exit:
li $a0,10
syscall
lenArray: #Fn returns the number of elements in an array
addi $sp,$sp,-8
sw $ra,0($sp)
sw $a0,4($sp)
li $t1,0
laWhile:
lw $t2,0($a0)
beq $t2,$0,endLaWh
addi $t1,$t1,1
addi $a0,$a0,4
j laWhile
endLaWh:
move $v0,$t1
lw $ra,0($sp)
lw $a0,4($sp)
addi $sp,$sp,8
jr $ra