Refined bitwise division algorithm in MIPS - algorithm

Our assignment is to implement a refined bitwise division algorithm in MIPS.
Basically in the refined program, we load the dividend into the LO bits of the 64 bit register and the remainder will accumulate in the HI bits, which are originally all set to 0.
Then we simply test if HI (our remainder) > = divisor.
If our accumulating remainder is not currently > = divisor, we simply left shift the entire register and fill in with a 0. This is the beginning of our quotient. As the dividend bits move into HI, we will finally have a situation where HI > =
divisor. Then we will subtract the divisor from HI, shift the entire register left, and fill in with a 1.
In short, we can simply continue to shift all 64 bits left, filling in with a 0 when HI < divisor, subtracting the divisor from HI and filling in with a 1 when HI > = divisor.
In our homework, we are to write a program to accept two positive numbers (16 bit signed numbers) from the console, divide the former by the latter.
I put the divisor in $t0, the remainder in $t3, and the dividend in $t2. $t3 and $t2 are both 16 bits, and together they pair up to be a 32-bit register. Somehow, my program returns a really funky quotient: the least significant few bits are correct, but the most significant is always 1; somehow I can't get rid of the 1, no matter how many bits I shift left. For instance, if the dividend is 1000, by shifting left, instead of getting 0001 0000, I actually get 10000 - MSB is always 1. Could someone please take a look at my program and give me some suggestions? Thanks a lot!
.data
GETA: .asciiz "Enter Dividend: "
GETB: .asciiz "Enter Divisor: "
QT: .asciiz "Quotient = "
RM: .asciiz "Remainder = "
NL: .asciiz "\n"
.text
main:
li $v0, 4 #Prompt for a dividend
la $a0, GETA
syscall
li $v0, 5 #Read dividend from user
syscall
move $t2, $v0 #dividend in $t2
li $v0, 4 #Prompt for a divisor
la $a0, GETB
syscall
li $v0, 5 #Read divisor from user
syscall
move $t0, $v0 #divisor in $t0
addi $t4, $zero, 17 #counter
j Loop
Loop:
slt $t1, $t3, $t0 #if remainder < divisor, $t1=1
beq $t1, $zero, subroutine #remainder >= divisor, $t1=0
#if remainder < divisor
sll $t3, $t3, 1 #shift remainder by to left by 1
andi $t5, $t2, 32768 #get MSB of $t2
bne $zero, $t5, updateRemainder1 #MSB of $t2 is 1
#MSB of $t2 is 0
sll $t2, $t2, 1 #shift dividend to left by 1
addi $t4, $t4, -1 #decrease counter by 1
bne $zero, $t4, Loop
j Exit
subroutine:
sub $t3, $t3, $t0 #subtract divisor from remainder
sll $t3, $t3, 1 #shift remainder by to left by 1
andi $t5, $t2, 32768 #get MSB of $t2
bne $zero, $t5, updateRemainder2 #MSB of $t2 is 1
#MSB of $t2 is 0
sll $t2, $t2, 1 #shift dividend to left by 1
ori $t2, $t2, 1 #fill in LSB of $t2 with a 1
addi $t4, $t4, -1 #decrease counter by 1
bne $zero, $t4, Loop
j Exit
updateRemainder1:
ori $t3, $t3, 1 #set LSB of remainder to 1
sll $t2, $t2, 1 #shift dividend to left by 1
addi $t4, $t4, -1 #decrease counter by 1
bne $zero, $t4, Loop
j Exit
updateRemainder2:
ori $t3, $t3, 1 #set LSB of remainder to 1
sll $t2, $t2, 1 #shift dividend to left by 1
ori $t2, $t2, 1 #fill in LSB of $t2 with a 1
addi $t4, $t4, -1 #decrease counter by 1
bne $zero, $t4, Loop
j Exit
Exit:
sub $t2, $t2, 524288
li $v0, 4 #print out output line
la $a0, QT
syscall
li $v0, 1 #print out quotient
move $a0, $t2
syscall
li $v0, 4 #print out new line
la $a0, NL
syscall
li $v0, 4 #print out output line
la $a0, RM
syscall
li $v0, 1 #print out remainder
move $a0, $t3
syscall
li $v0, 10
syscall

Related

Trouble With Division Algorithm

I'm currently trying to code a function to divide integers in MIPS. I am supposed to use a division algorithm using this flowchart:
Here is the code that I have created:
.data
.text
main:
addi $a0, $0, 7
addi $a1, $0, 4
jal divide
addi $a0, $v1, 0
addi $v0, $0, 1
syscall
addi $v0, $0, 10
syscall
divide: # $a0/$s0 = Dividend-Remainder / $a1/$s1 = Divisor / $v1 = Quotient
# Initialize
addi $s0, $a0, 0
addi $s1, $a1, 0
addi $t0, $0, 0 # Counter = $t0
addi $t1, $0, 33 # Number of loops = $t1
# Start of loop
start:
# Step 1 : Subtract the divisor register from the remainder register and place in remainder register
sub $s0, $s0, $s1
# Step 2 : Test the remainder register. If < 0 go to part B, otherwise go to part A
addi $t3, $0, 0
slt $t2, $t3, $s0
beq $t2, $zero, partB
# Step 2A : Shift quotient register to the left, and make least significant bit 1
sll $v1, $v1, 1
ori $v1, $v1, 1
j after # Skip step 2B
# Step 2B : Add divisor to remainder and place sum in remainder register
partB:
add $s0, $s1, $s0
# Shift quotient register to left and make least significant bit 0
sll $v1, $v1, 1
after:
# Step 3 : Shift divisor right 1 bit
srl $s1, $s1, 1
# Increment counter
addi $t0, $t0, 1
# Test loop
bne $t0, $t1, start
jr $ra
I've been trying to catch my error but so far I have been unable to find it. When I run the code I get -1073741825 for the output.
Can someone check my logic and tell me what I'm doing wrong?

Asm program... something goes wrong

I load two arrays. I have to return a third array that contain the sum of the two and has the dimension of the smaller. Print the last one.
Example:
INPUT: Array1: [1 2 3 4 5] Array2: [2 6 1]
OUTPUT: Array3: [3 8 4]
Program runs... it give me the exact number of elements but every element is 0.
.data
vett1: .word 0:100
vett2: .word 0:100
vett3: .word 0:100
x: .word 0
space: .asciiz " "
.text
.globl main
main:
la $a0, vett1
la $a1, vett2
la $a2, vett3
la $a3, x
li $t0, 0
li $t1, 0
li $t2, 0
jal loadA1 #mi salvo 26 salto a caricavettore1
jal loadA2 #mi salvo 27 salto a caricavettore2
jal lenght #mi salvo 28 salto a controllalunghezza
lw $t2, ($a3)
lw $t3, ($a3)
la $a0, vett1
la $a1, vett2
la $a2, vett3
jal summ
jal print
li $v0, 10
syscall
loadA1:
li $v0, 5
syscall
beq $v0, -1, exit
sw $v0, ($a0)
addi $t0, $t0, 1
addi $a0, $a0, 4
j loadA1
exit: jr $ra
loadA2:
li $v0, 5
syscall
beq $v0, -1, exit2
addi $t1, $t1, 1
sw $v0, ($a1)
addi $a1, $a1, 4
j loadA2
exit2: jr $ra
lenght:
blt $t0, $t1, cond1
sw $t1, ($a3)
jr $ra
cond1: sw $t0, ($a3)
jr $ra
summ:
subi $sp, $sp, 4
sw $ra, 0($sp)
bnez $t2, rec
j exit3
rec: lw $s0, ($a0)
lw $s1, ($a1)
add $v0, $s0, $s1
sw $v0, ($a2)
addi $a0, $a0, 4
addi $a1, $a1, 4
addi $a2, $a2, 4
subi $t2, $t2, 1
jal summ
exit3:
lw $ra, 0($sp)
addi $sp, $sp, 4
jr $ra
print:
beqz $t3, exit4
lw $a0, ($a2)
li $v0, 1
syscall
la $a0, space
li $v0, 4
syscall
addi $a2, $a2, 4
subi $t3, $t3, 1
j print
exit4: jr $ra
When you sum the two arrays you add 4 to $a2 at the end of each iteration to point it to the next element of vett3. So after the summing is complete $a2 will point to the first memory location after the end of vett3.
Then you call print but don't reset $a2 to point at the start of vett3, so you end up printing garbage data (which could happen to be all zeroes - or mostly zeroes at least, since x and space will be there).

Sorting program with MIPS

I have some problem when I'm writing a sorting program in MIPS.
The function of this program is like this: Input 10 integers from keyboard and print them out, then sort them and print the sorted array again.
But the output is different from what I expect, some numbers are not sorted, would someone help me?
.data
str1: .asciiz "Please input integer numbers, maximum 10: \n"
str2: .asciiz "The 10 integer numbers you input are: \n"
str3: .asciiz "The numbers you entered are sorted as: \n"
array: .space 40
space: .asciiz " "
.text
.globl main
main:
la $t6, array #load the address of array into $t6
move $t7, $t6
addi $t7, $t7, 40 #point $t7 to the end of the array
jal readin
la $t6, array
la $a0, str2
li $v0, 4
syscall
jal print1 #print out the array before sort
la $t0, array #put the address of array into $t0
add $t0, $t0, 40 #put $t0 to the end of the array
move $t1, $zero #set $t1 as counter of the outerloop
li $t2, 10 #set $t2 as number of the outerloop
la $t3, array #put the address to $t3
jal innerloop
la $a0, str3
li $v0, 4
syscall
la $t3, array
#move $t7, $t3
#add $t7, $t7, 40
jal print2
li $v0, 10
syscall
innerloop:
lb $t4, 0($t3)
lb $t5, 4($t3)
bgt $t4, $t5, swap
addi $t3, $t3, 4
blt $t3, $t0, innerloop #if $t3 < $t0, keep in the innerloop to check two #neighbor numbers
jal outerloop #jump to outerloop if one round is finished
swap:
sb $t4, 4($t3)
sb $t5, 0($t3)
addi $t3, $t3, 4
#sll $t3, $t3, 2
blt $t3, $t0, innerloop #
jr $ra
outerloop:
la $t3, array
addi $t1, $t1, 1 #add the outerloop counter $t1 by one,
addi $t0, $t0, -1
blt $t1, $t2, innerloop #if $t1 < $t2, keep searching
jr $ra
readin:
la $a0, str1 #print str1
li $v0, 4
syscall
li $v0, 5 #read in the number
syscall
sb $v0, ($t6) #store the number in the array
add $t6, $t6, 4
blt $t6, $t7, readin
jr $ra
print1:
lb $a0, ($t6)
li $v0, 1
syscall
li $a0, 32
li $v0, 11 # syscall number for printing character
syscall
add $t6, $t6, 4
blt $t6, $t7, print1
jr $ra
print2:
lb $a0, ($t3)
li $v0, 1
syscall
li $a0, 32
li $v0, 11 # syscall number for printing character
syscall
add $t3, $t3, 4
blt $t3, $t0, print2
jr $ra
And the result in SPIM is like this:
Please input integer numbers, maximum 10:
44
Please input integer numbers, maximum 10:
11
Please input integer numbers, maximum 10:
33
Please input integer numbers, maximum 10:
22
Please input integer numbers, maximum 10:
66
Please input integer numbers, maximum 10:
55
Please input integer numbers, maximum 10:
99
Please input integer numbers, maximum 10:
77
Please input integer numbers, maximum 10:
88
Please input integer numbers, maximum 10:
24
The 10 integer numbers you input are:
44 11 33 22 66 55 99 77 88 24 The numbers you entered are sorted as:
11 33 22 44 55 66 77 88 24 32
Would someone please explain to me why there is a 32 in the end and why they are not sorted properly?

Printing to Screen in MARS for MIPS program

Hi I have to write a program in MIPS that does a bubble sort and then prints the sorted array and plays a note(s). I am having trouble getting it to execute in Mars and I am wondering what I need to add to my program:
.include "ec2_data.asm" # load values into array
add $s0, $zero, 0x10010000
add $t0, $zero, 0x10010000 #how many times to loop
addi $t1, $zero, 0 #initilize the counter
addi $t2, $zero ,0 #initilize position x
addi $t3, $zero, 4 #initilize position y
lw $s2, $t3($s0) #get second position of $s0=y
LOOP:
addi $t0, $t0, -1 #subtract one from the counter
slt $t4, $s1, $s2 #t4 set to 1 if x > y
beqz $t4, BREAK #if t0 is zero (x<y) we dont' have to sort, so go to break
# sort:
add $t5, $zero, $s1 #temp. stores the value of x in t5
add $s1, $zero, $s2 #moves the value of y into x
add $s2, $zero, $t5 #moves the value of x into y
sw $s1, $t2($s0) #save the new x to register
sw $s2, $t3($s0) #save the new y to register
j BREAK
BREAK:
#in here: check to see if we have reached the end
#if not, increment t2 and t3 by 4 to get the next values and jump back to loop to go again
beq $t0, $zero, END #if we are done with the array, go to end
addi $t2, $t2, 4
addi $t3, $t3, 4
j LOOP #jump back to loop again
END:
li $v0, 1 # print integer
syscall
addi $a0, $0, 0xA # load line code into register
addi $v0, $0, 0xB # print new line
syscall
addi $v0, $zero, 33 # midi out synchronous
addi $a0, $zero, 60 # Middle-C
addi $a1, $zero, 250 # ms
addi $a2, $zero, 120 # some instrument
addi $a3, $zero, 64 # some volume
add $a0, $t7, $zero # load value into $a0
syscall # play note!
addi $t6, $t6, 4 # shift memory location by 32 bits
addi $s1, $s1, 1 # increment counter ++
j loop # loop
Exit:
li $v0, 10 # load exit code
syscall # exit
If by "having trouble getting it to execute", you mean it acts strange with the .include file, then you might not have a required option checked in MARS. Go to the Settings menu and check the box for "Initialize Program Counter to global Main if defined". That seems to be something that has to be in effect for included files to work - and for some reason, it isn't turned on by default.

Case sorting in mips

I have a program that will capitalize all lowercase letters and lowercase all the uppercase letters entered in a string by the user. It does this by adding or subtracting 32 from the character value to get the desired character. My problem is that it doesn't change anything in the string. Any suggestions on what to change?
.data
prompt: .asciiz "\n\nEnter an string of characters: "
result: .asciiz "\n\nHere is the string you entered: "
after_sort: .asciiz "\n\nHere is the string after the case sorting: "
buffer: .space 80
.text
main:
#Prints the prompt string
li $v0, 4
la $a0, prompt
syscall
#reads string from user and saves in $a0
li $v0, 8
la $a0, buffer
li $a1, 80
syscall
#Prints the result string
li $v0, 4
la $a0, result
syscall
#Prints the string entered by the user
la $a0, buffer
li $v0, 4
syscall
li $t0, 0 # t0 = i = 0
for_loop:
slti $t1, $t0, 80 # t1 = 1 if and only if t0 < 80
beq $t1, $0, for_loop_done
slti $t2, $a0, 91
li $t3, 1
beq $t2, $t3, upper #if the character value is less than 91 branch to upper addition
bne $t2, $t3, lower
upper:
addi $a0, $a0, 32 #adds 32 to the character value to lowercase it
lower:
subi $a0, $a0, 32 #subtracts 32 from the character value to capitalize it
addi $t0, $t0, 1
j for_loop
for_loop_done:
#Prints the result string
li $v0, 4
la $a0, after_sort
syscall
#Prints the string entered by the user
la $a0, buffer
li $v0, 4
syscall
exitProgram: li $v0, 10 # system call to
syscall # terminate program
You are using $a0as a character, such as here:
slti $t2, $a0, 91
but it is never filled with the character. At the moment, it contains a memory address, not a character.
You should load the character using lb and store it back after making it upper/lowercase using sb.
Feel free to add a comment if you want a code example.
Edit: the changes in the relevant part of the code:
...
li $t0, 0 # t0 = i = 0
for_loop:
slti $t1, $t0, 80 # t1 = 1 if and only if t0 < 80
beq $t1, $0, for_loop_done
lb $t4, 0($a0)
beqz $t4, for_loop_done
beq $t4, 10, for_loop_done
slti $t2, $t4, 91
li $t3, 1
beq $t2, $t3, upper #if the character value is less than 91 branch to upper addition
bne $t2, $t3, lower
upper:
addi $t4, $t4, 32 #adds 32 to the character value to lowercase it
j done
lower:
addi $t4, $t4, -32 #subtracts 32 from the character value to capitalize it
done:
addi $t0, $t0, 1
sb $t4, 0($a0)
addi $a0, $a0, 1
j for_loop
for_loop_done:
#Prints the result string
...
It's easy to forget that in assembly, you can't do this:
if something
do this
else
do that
There is no "else", only shudder Goto.
So in this code:
slti $t2, $a0, 91
li $t3, 1
beq $t2, $t3, upper #if the character value is less than 91 branch to upper addition
bne $t2, $t3, lower
upper:
addi $a0, $a0, 32 #adds 32 to the character value to lowercase it
lower:
subi $a0, $a0, 32 #subtracts 32 from the character value to capitalize it
addi $t0, $t0, 1
When you branch to upper, it adds 32. Then it subtracts 32, because execution progressed to the next line. So your code capitalizes lower case, but does nothing to uppercase.
You need to add a jump to the first instruction after your if/then/else equivalent:
upper:
addi $a0, $a0, 32 #adds 32 to the character value to lowercase it
j done # No, I don't want to subtract it again!
lower:
subi $a0, $a0, 32 #subtracts 32 from the character value to capitalize it
done:
addi $t0, $t0, 1
In fact, you should probably get rid of the bne altogether - it's redundant. If beq doesn't branch, then it's not equal. So this would be the finished product:
slti $t2, $a0, 91
li $t3, 1
beq $t2, $t3, upper #if the character value is less than 91 branch to upper addition
# Otherwise, it's lower
subi $a0, $a0, 32 #subtracts 32 from the character value to capitalize it
j done
upper:
addi $a0, $a0, 32 #adds 32 to the character value to lowercase it
done:
addi $t0, $t0, 1
Hope that helps!
(Edit: #Patrik is right too, you need to "dereference" $a0. My example doesn't take that into account.)
here is my code:
it works perfectly
.data
theString:
.space 20
prompt: .asciiz "Enter a string of characters: "
.text
main:
li $v0, 4
la $a0, prompt
syscall
li $v0, 8
la $a0, theString
li $a1, 20
syscall
li $v0, 4
syscall
la $t1,theString
for: lb $a0, 0($t1)
beqz $a0,out #to find out end of string
beq $a0,10,out #to find out end of string
slti $t2, $a0,91 #if $a0<91 $t2=1
beq $t2,1,small
beq $t2,0,capital
capital:
subu $a0, $a0, 32
li $v0,11
syscall
addi $t1,$t1,1
j for
small:
addi $a0, $a0, 32
li $v0,11
syscall
addi $t1,$t1,1
j for
out:
li $v0, 10
syscall

Resources