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
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
For some reason the integer values i'm putting into memory of the array of base $t0 cant be accessed later on even though when debugging i can clearly see that they are stored correctly in memory at 0($t0) and 4($t0) in the case of 2 integers. Its when i go into the passloop and attempt to load them into t6 or t7 that no value is being passed. Can someone explain why this is?
# bubble sort
.data
prompt1: .asciiz "Enter the array size \n"
prompt2: .asciiz "Enter integers to fill the array \n"
prompt3: .asciiz "Sorted Array: "
.text
.globl main
main:
la $a0, prompt1
li $v0, 4
syscall
li $v0, 5
syscall
add $t1, $zero, $v0
add $t2, $zero, $v0
sll $a0, $v0, 2
li $v0, 9
syscall
add $t0, $zero, $v0
loop:
la $a0, prompt2
li $v0, 4
syscall
li $v0, 5
syscall
beqz $t1, mainloop
sw $v0, ($t0)
addiu $t0, $t0, 4
subiu $t1, $t1, 1
bnez $t1, loop
mainloop:
subi $a1,$t2,1
blez $a1,done
li $t3,0
jal passloop
beqz $t3,done
subi $t2,$t2,1
j mainloop
#print sorted data, code still needed. Need to fix accessing issue first
done:
j end
passloop:
lw $t6,0($t0)
lw $t7,4($t0)
bgt $t6,$t7,swap
next:
addiu $t0,$t0,4
subiu $a1,$a1,1
bgtz $a1,passloop
jr $ra
swap:
sw $t6,4($t0)
sw $t7,0($t0)
li $t3,1
j next
end:
li $v0,10
syscall
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 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.
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.