I'm trying to create a iterative binary search in mips, below is my code. It works when searching for the middle value, otherwise it doesnt but i'm not sure why. I'm new to MIPs and trying to get better so any critique is appreciated
.data
myArray: .word 1 4 5 7 9 12 15 17 18 20 21 30
last: #the address that comes after the array
arraySize: .word 11
.globl main
.text
main:
la $s0, myArray # array address
lw $s1, arraySize # arraysize
li $s2, 30 # address of last array entry
jal Binsearch # perform binary search
li $v0, 10
syscall
Binsearch:
li $t0,0 #first = 0
subu $t1, $s1, 1 #last = array size -1
Loop: bge $t0, $t1, DONE # if ! (first < last)
add $t2,$t0,$t1 #first + last
li $t3,2
div $t2, $t3 #$LO = middle index
mflo $t3 #$t3 = middle index
li $s3,4 #load the value 4 into s3
multu $s3, $t3 #multiply middle by 4 to get the offset
mflo $t4 #store the result in t4
add $t4, $s0, $t4 #t4 points to array[mid]
lw $t5, ($t4) #load the value at array[mid] into t5
beq $t5, $s2, return_mid # if t5 == s2 then return the index
blt $t5, $s2, move_right # if t5 < s2 then move right
subu $t1, $t3, 1 #if this line is reached that means that none of the above
j Loop #conditions are true, so t5 > s2, last = mid -1
return_mid:
li $v0, 1
add $a0, $t3, $zero # add the middle index to a0
syscall #print the index
move_right:
addi $t0, $t3, 1 # first = mid + 1
j Loop # jump to Loop
DONE:
li $v0, 1
li $a0, -1
syscall
j $ra #return to the caller
I figured it out, had to test for some corner cases and change the LOOP condition
.data
myArray: .word 1 4 5 7 9 12 15 17 18 20 21 30
last: #the address that comes after the array
arraySize: .word 11
.globl main
.text
main:
la $s0, myArray # array address
lw $s1, arraySize # arraysize
li $s2, 20 #value youre searching for
jal Binsearch # perform binary search
li $v0, 10
syscall
Binsearch:
li $t0,0 #first = 0
move $t1, $s1 #last = array size -1
li $t6,1
li $t7,4 #checks for the last element in the array being the correct value
multu $t7,$t1
mflo $t7
add $t7,$s0,$t7
lw $t5, ($t7)
beq $t5, $s2, last_num # if == then
subu $t1, $s1, 1
Loop: bge $t0, $t1, DONE # if ! (first < last)
add $t2,$t0,$t1 #first + last
li $t3,2
div $t2, $t3 #$LO = middle index
mflo $t3 #$t3 = middle index
beq $t2,$t6, special_case #if first+last = 1 you want totake HI not LO
li $t7,4 #load the value 4 into t7
multu $t7, $t3 #multiply middle by 4 to get the offset
mflo $t4 #store the result in t4
add $t4, $s0, $t4 #t4 points to array[mid]
lw $t5, ($t4) #load the value at array[mid] into t5
beq $t5, $s2, return_mid # if t5 == s2 then return the index
blt $t5, $s2, move_right # if t5 < s2 then move right
subu $t1, $t3, 1 #if this line is reached that means that none of the above
j Loop #conditions are true, so t5 > s2, last = mid -1
special_case:
mfhi $t3 #get the 1 value from hi
li $t7,4 #load the value 4 into t7
multu $t7, $t3 #multiply middle by 4 to get the offset
mflo $t4 #store the result in t4
add $t4, $s0, $t4 #t4 points to array[mid]
lw $t5, ($t4) #load the value at array[mid] into t5
beq $t5, $s2, return_mid # if t5 == s2 then return the index
return_mid:
li $v0, 1
add $a0, $t3, $zero # add the middle index to a0
syscall #print the index
j $ra
move_right:
addi $t0, $t3, 1 # first = mid + 1
j Loop # jump to Loop
last_num:
li $v0, 1
add $a0, $t1, $zero
syscall
j $ra
DONE:
li $v0, 1
li $a0, -1
syscall
j $ra #return to the caller
Related
I am trying an array to save i * j values and print the values from array.
I have two loops loop1, loop2, where loop1 takes i and loop2 takes on j.
I am trying to save the i * j in a myarray which is space datatype.
I am getting exception Memory address out of bounds and unable to find whats the error.
.data
myarray: .space 10000
n: .word 1
space_line: .asciiz " "
new_line: .asciiz "\n"
.text
.globl main
main:
lw $a0, n
la $a1, myarray
li $a2, -1 #row
li $t0, 0
li $t2, 0
loop1:
addi $a2, $a2,1
bge $a2, $a0, print_loop
li $a3, 0 #column
j loop2
loop2:
bge $a3, $a0, loop1
#multiply a2 and a3
mul $t1, $a2, $a3
sw $t1, 0($a1)
addu $a1, $a1,4
addi $a3, $a3,1
j loop2
print_loop:
mul $t3, $a0, $a0
bge $t0, $t3, exit
li $v0, 4
lw $a0, myarray($t2)
syscall
li $v0, 4
lw $a0, space_line
syscall
rem $t4, $t3, $a0
beqz $t4, newline
addu $t2, $t2, 4
addi $t0, $t0, 1
j print_loop
newline:
li $v0, 4
lw $a0, myarray($t2)
syscall
exit:
# Done, terminate program.
li $v0, 10
syscall # all done!
.end main
For n =4,i am expecting the output in console as
0 0 0 0
0 1 2 3
0 2 4 6
0 4 8 12
You can find this problem by single stepping in the debugger. Start with the smallest possible input, like n=1 as you're showing. After each instruction, verify that it did what you want, and that it didn't do anything else except what you wanted.
Here's a hint: Pay attention to the difference between la and lw. Also, If you want to put syscalls in the middle of your code or loops, then avoid the $a0 and $v0 registers for your own variables — just makes things easier/better.
I'm currently working on a palindrome function in MIPS that takes a char array and returns 0 if it is not a palindrome, else 1. I've got everything seemingly working except for the part where I find data at index i and array.length-i-1. If someone could lead me in the right direction I'd really appreciate it.
Here's the java code I'm going off of:
int Palindrome(char[] s) {
for(int i = 0; i < (s.length / 2); i++) {
if(s[i] != s[s.length - 1 - i])
return 0;
}
return 1;
}
Here's the Palindrome function:
palindrome:
# Get length of array and store it in $t1
addi $sp, $sp, -8
sw $ra, 0($sp)
sw $a0, 4($sp)
li $t1, 0
lengthWhile:
lw $t2, 0($a0)
beq $t2, $zero, startPalindrome
addi $t1, $t1, 1
addi $a0, $a0, 4
j lengthWhile
startPalindrome:
div $t2, $t1, 2 # Stores a.length / 2 into $t2
add $t3, $t3, $zero # i value (0 - (a.length/2 - 1))
add $t4, $t4, $t1
subi $t4, $t4, 1 # a.length-1
# $t1 = a.length
# $t2 = a.length / 2
# $t3 = i
# $t4 = a.length - 1
palLoop:
bge $t3, $t2, exitLoop
sub $t4, $t4, $t3 # Puts a.length-1-i into $t4
sll $t5, $t3, 2
add $t6, $a0, $t5
lw $s1, 0($t6)
sll $s3, $t4, 2
add $t7, $a0, $s3
lw $s2, 0($t7)
bne $s1, $s2, return0
# Increase i and start loop again
addi $t3, $t3, 1
j palLoop
return0:
li $v0, 0
jr $ra
exitLoop:
li $v0, 1
jr $ra
Here's the main:
.data
charArray: .word 'a', 'b', 'c', 'd', 'c', 'w', 'a'
.text
main:
# Palindrom Function
la $a0, charArray
jal palindrome
move $a0, $v0
li $v0, 1
syscall
# Exit Program
li $v0, 10
syscall
Thank you in advance for any help. (To specify, palLoop is where I'm having trouble).
Not directly part of your question, but charArray: .word 'a', 'b', 'c', 'd', 'c', 'w', 'a' is really a word array containing a chatarter value, not a character array.
It looks like that will wok as you are using word array everywhere, however wont wok if you use a proper character array.
add $t3, $t3, $zero is t3 = t3 + 0 - what is t3 prior to that?
add $t4, $t4, $t1 - same comment
sub $t4, $t4, $t3 # Puts a.length-1-i into $t4 - will overwrite a.length-1 (t4) so is going not be right on the 2nd time through the loop.
This is the C code that i have been converted so far. it gives me some error that i have been included in the following code. i don't understand which part is wrong in this c to mips conversion?
char ch[10];
int i;
for (i = 0; i != 10; i++)
ch[i] = ch[i] – 32
.data
.text
li $v0 4
syscall
#$s1 = i, $s0 base address of ch
addi $s1, $0, 0 #i =0
addi $t0, $0, 10 #t0 = 10
loop: beq $t0, $s1, end
add $t1, $s1, $s0
lw $t2, 0($t1)
addi $t2, $t2, -32
sw $t2, 0($t1)
addi $s1, $s1, 1
j loop
end:
My output:
Runtime exception at 0x00400018: address out of range 0x00000000
From the C code you are converting a char type array and in MIPS you should use lb instead of lw.
In order to print out you need a main: label and also you should declare an array like .byte or .space
You should usesyscall 11 to print a character or syscall 4 to print
string.
I have added some of these mentioned above to your code hope it helps.
.data
#ch: .byte 'a','b','c','d','e'
ch: .space 10
.text
main:
li $v0, 8 #read character
li $a1, 10 #load the space
la $a0, ch
syscall
li $v0,11 #print character
syscall
li $v0,10 # exit program
syscall
addi $s1, $0, 0 #i = 0
addi $t0, $0, 10 # $t0 = 10
loop: beq $t0, $s1, end
add $t1, $s1, $s0
lb $t2, ch($t1)
addi $t2, $t2, -32
sb $t2, ch($t1)
addi $s1, $s1, 1
j loop
end:
I am trying to add numbers that are in base 5.
Im supposed to prompt the user for 2 separate base 5 number in the form XXXXXX.XXXXX, and then add them.
My current problem is that I am getting an error when I am loading the last digit into a register, so I can start the calculation.
please help! Thanks
.data
str: .space 13 # XXXXXX.XXXXX hold 12 chars + 0x00
str2: .space 13
sum: .space 14
printstr: .space 13
printstr2: .space 13
printsum: .space 14
message1: .asciiz "Enter a base 5 number A: "
message2: .asciiz "Enter a base 5 number B: "
message3: .asciiz "Sum of A and B: "
newline: .asciiz "\n"
.text
main:
#get number A
li $v0, 4
la $a0, message1
syscall
li $v0, 8
li $a1, 13
la $a0, str
syscall
li $v0, 4
la $a0, newline
syscall
#get number B
li $v0, 4
la $a0, message2
syscall
li $v0, 8
li $a1, 13
la $a0, str2
syscall
li $v0, 4
la $a0, newline
syscall
#pointer to input string A
la $s1, str
addi $s1, $s1, 12
#pointer to input string A
la $s2, str2
addi $s2, $s2, 12
#pointer to sum
la $s3, sum
addi $s3, $s3, 13
#other variables
li $t0, 0 # inital carry is 0
li $t1, 1 # counter for looping through string
li $t2, 5 # base 5
loop:
lb $t3, ($s1) ############################# PROBLEM HERE######
lb $t4, ($s2)
beq $t3, '.', next
beq $t4, '.', next
subi $t3, $t3, 0x30
subi $t4, $t4, 0x30
add $t5, $t3, $t4
add $t5, $t5, $t0
div $t5, $t2
mflo $t0
mfhi $t5
addi $t5, $t5, 0x30
sb $t5, ($s3)
subi $s1, $s1, 1
subi $s2, $s2, 1
subi $s3, $s3, 1
addi $t1, $t1, 1
ble $t1, 13, loop
addi $t0, $t0, 0x30
sb $t0, ($s3)
next:
subi $s1, $s1, 1
subi $s2, $s2, 1
#subi $s3, $s3, 1
addi $t1, $t1, 1
j loop
PRINT: #print the sum
exit:
li $v0, 10
syscall
You set up $s1 to point past str and decrement it backwards. Your loop: termination is the ble $t1,13,loop. When that completes, $s1 is pointing to the start of the .data section (i.e. 0x10010000).
But, then, you "fall through" to next: [probably wrong] and decrement $s1 so it has the value 0x1000ffff. Then, you do j loop so the fetch is now coming from an address one byte below the start of the .data segment (i.e. memory that does not exist)
That's the source of the crash. You probably need a jump inst after the ble to continue on to some other code.
But, also, when you do beq $t3,'.',next you go to next: and decrement both pointers. Unless you restrict your input there is no guarantee that both $s1 and $s2 both point to '.' at the same time, so you only want to decrement one of them. (e.g. suppose you had str: 12.3 and str2: 123.41)
So, you may need some code to align the two numbers with respect to their decimal points beforehand.
I have a trouble. I tried to make a binary search algorithm using recursion in mips assembly, but I have some errors that I don't understand how to solve them.
I have an array of 10 integers and I assume that the array is sorted.
this is my code, I appreciate any help and thanks in advance..
.data
arr: .word 40
arrMsg: .asciiz "Enter the array : \n"
posMsg: .asciiz "This value exist in the array and its position is "
pos: .word 0
newline: .asciiz "\n"
valMsg: .asciiz "Enter the value you search for : \n"
val: .word 0
notfound:.asciiz "the value doesn't exist in the array !! \n"
.text
main:
# print the array message
li $v0, 4
la $a0, arrMsg
syscall
# read the array from the user
# put $s0 = i
add $s0, $zero, $zero # i = 0
for:
beq $s0, 40, end
li $v0, 5
syscall
sw $v0, arr($s0) # input arr[i]
addi $s0, $s0, 4 # i = i + 4
j for
end:
# print value message
li $v0, 4
la $a0, valMsg
syscall
# read the value from the user
li $v0, 5
syscall
# store the value in the val variable
sw $v0, val
################################################
## put $s0 = start , $s1 = middle , $s2 = end ##
################################################
li $s0, 0
li $s2, 9
jal BinarySearch
li $v0, 10
syscall
############################################################################################################
BinarySearch:
# middle = (start + end ) / 2
add $t0, $s0, $s2 # $t0 = start + end
sra $s1, $t0, 1 # $s1 = $t0 / 2
# save $ra in the stack
addi $sp, $sp, -4
sw $ra, 0($sp)
# base case
ble $s2, $s0, returnNegative1 # if (end <= start)
lw $t1, arr($s1) # $t1 = arr[middle]
lw $t2, val # $t2 = val
beq $t1, $t2, returnMiddle # if (arr[middle] == val)
blt $t2, $t1, returnFirstPart # if (val < arr[middle])
bgt $t2, $t1, returnLastPart # if (val > arr[middle])
returnNegative1:
li $v0, -1
j Exit
returnMiddle:
move $v0, $s1 # return middle
j Exit
returnFirstPart:
move $t3, $s1 # temp = middle
addi $t3, $t3, -1 # temp --
move $s2, $t3 # end = temp
jal BinarySearch
j Exit
returnLastPart:
move $t3, $s1 # temp = middle
addi $t3, $t3, 1 # temp++
move $s0, $t3 # start = temp
jal BinarySearch
j Exit
Exit:
lw $ra, 0($sp)
addi $sp, $sp, 4`
jr $ra
lw $t1, arr($s1) # $t1 = arr[middle]
this is the problem as it is not really the right index as integer takes 4 bytes
so the middle you get from
add $t0, $s0, $s2 # $t0 = start + end
sra $s1, $t0, 1 # $s1 = $t0 / 2
is just the logical address not the real one you will need to multiply it with 4
mul $s4, $s1,4
and then use $s4 as an address
lw $t1, arr($s4) # $t1 = arr[middle]
also there is a mistake with the stopping condition it should be
if (end < start) not (<=)
and sorry for my English