Reputation: 403
I'm trying to figure out how to normalize a significand in MIPS when doing floating point addition.
Say you have 0.001*2^-1. In this instance, to normalize you would have to shift the significand left 3 and and decrement the exponent by 3.
How would I determine the the most significant bit is back in the normalized position (in my previous case, how do I know that i stop shifting after the third shift)?
Update: Here is the code that I am currently using. Given two inputs (floating point numbers), the program should do half-precision floating point addition which is why I convert from single to half-precision. The output should simply be the sum of the two floats
I believe that the problem lies within the normalizing.
.data
ask_user_a: .asciiz "Enter a decimal number (a): "
ask_user_b: .asciiz "Enter a decimal number (b): "
sum: .asciiz "a+b = "
error_out_of_range: .asciiz "Error: A number you entered is out of range! "
new_line: .asciiz "\n"
.text
main:
#Ask user for the input a
la $a0, ask_user_a # load the addr of ask_user_a into $a0.
li $v0, 4 # 4 is the print_string syscall.
syscall # do the syscall.
#put input a into $s0
li $v0, 6 #6 for getting floating point numbers
syscall # do the syscall
mfc1 $s0, $f0 #move floating point number to $s0
## ask user for the input b
la $a0, ask_user_b # load the addr of ask_user_b into $a0.
li $v0, 4 # 4 is the print_string syscall.
syscall # do the syscall.
#put input b into $s1
li $v0, 6 #6 for getting floating point numbers
syscall # do the syscall
mfc1 $s1, $f0 #move floating point number to $s1
#extract parts for A
srl $t0, $s0, 31 #$t0 = Sign Bit A
sll $t1, $s0, 1
srl $t1, $t1, 24
sub $t1, $t1, 127 #t1 = Exponent Bit A
sll $t2, $s0, 9
srl $t2, $t2, 9 #t2 = Mantissa A
srl $t2, $t2, 13 #Truncate Mantissa
ori $t2, $t2, 0x800000
srl $t2, $t2, 12
#extract parts for B
srl $t5, $s1, 31 #$t5 = Sign Bit B
sll $t6, $s1, 1
srl $t6, $t6, 24
sub $t6, $t6, 127 #t6 = Exponent Bit B
sll $t7, $s1, 9
srl $t7, $t7, 9 #t7 = Mantissa B
srl $t7, $t7, 13 #Truncate Mantissa
ori $t7, $t7, 0x800000
srl $t7, $t7, 12
##Check that exponent A is >16 and <-16, jump to error otherwise
blt $t1, -16, oor_error
bgt $t1, 16, oor_error
##Check that exponent B is >16 and <-16, jump to error otherwise
blt $t6, -16, oor_error
bgt $t6, 16, oor_error
j no_oor_error
#Throw error
oor_error:
la $a0, error_out_of_range # load the addr of ask_user_a into $a0.
li $v0, 4 # 4 is the print_string syscall.
syscall # do the syscall.
j exit
#There was no out of range error
no_oor_error:
#compare exponents
beq $t6, $t1, exponents_match
bgt $t6, $t1 expBgtexpA
sub $t8, $t6, $t1
srlv $t7, $t7, $t8
move $t6, $t1
j exponents_match
expBgtexpA:
sub $t8, $t1, $t6
srlv $t2, $t2, $t8
move $t1, $t6
exponents_match:
#If the signs are the same, add mants
#If the signs are diff, subtract mants
bne $t0, $t5, different_signs
add $t9, $t2, $t7
j significands_added
different_signs:
sub $t9, $t2, $t7
significands_added:
#normalize
#determine size
bne $t0, $t5, normalize_different_sign
normalize_same_sign:
andi $t8, $t9, 0x1000
beq $t8, $zero, done_normalize
srl $t9, $t9, 1
addi $t1, $t1, 1
j normalize_same_sign
normalize_different_sign:
andi $t8, $t9, 0x1000
beq $t8, $zero, done_normalize
sll $t9, $t9, 1
subi $t1, $t1, 1
j normalize_different_sign
done_normalize:
#Check for overflow
##Convert back to float
sll $t0, $t0, 31 ##move sign to 32nd bit
addi $t1, $t1, 127 ##Add bias
sll $t1, $t1, 23 #move exponent to bits 24-31
sll $t9, $t9, 11 #move over mant
andi $t9, $t9, 0x3FFFFF
sll $t9, $t9, 1
or $s2, $t0, $t1
or $s2, $s2, $t9
#Print the float
mtc1 $s2, $f12
li $v0, 2
syscall
exit:
#Exit Program
li $v0, 10 # syscall code 10 is for exit.
syscall # make the syscall.
Upvotes: 1
Views: 2607
Reputation: 222828
This code uses the two signs of the floating-point input numbers to select which code is used to normalize a significand. If the signs are the same (t0 equals t5), it attempts to normalize by shifting right until bit 12 (0x1000) of the result significand is set. If the signs are different, it attempts to normalize by shifting left until bit 12 is set.
This does not make any sense.
To normalize a significand, if it is too large to fit in the desired number of bits, you shift it right (and it should be rounded as desired too). If it is so small that it does not reach the desired bit, you shift it left. (One will probably want to work with a positive significand at this point. If the result of the arithmetic performed on the significand is a negative number, it complicates determining whether the significand has the desired bits sets.)
You might consider implementing the operation in C or a language with which you are familiar and comfortable working and debugging in, then converting to assembly.
Upvotes: 1