📄 softfp.s
字号:
/* * Both add and subtract functions come here. The difference is that * the FUNC field (t8) is zero for adds. */func_add: lw v1,add_fmt_tab(v0) j v1 .rdataadd_fmt_tab: .word add_s:1, add_d:1, add_e:1, add_q:1, illfpinst:1 .text/* * Add (and subtract) single RD = RS + RT (or RD = RS - RT). Again the FUNC * field (t8) is zero for adds. */.globl add_sadd_s: /* * Break out the operands into their fields (sign,exp,fraction) and * handle NaN operands by calling {rs,rt}breakout_s() . */ li t9,C1_FMT_SINGLE*4 li v1,1 jal rs_breakout_s jal rt_breakout_s beq t8,zero,1f # if doing a subtract then negate RT lui v0,SIGNBIT>>16 xor t4,v01: # Check for addition of infinities, and produce the correct action if so bne t1,SEXP_INF,5f # is RS an infinity? # RS is an infinity bne t5,SEXP_INF,4f # is RT also an infinity? # RT is an infinity beq t0,t4,3f # do the infinities have the same sign? /* * The infinities do NOT have the same sign thus this is an invalid * operation for addition so set the invalid exception in the fpc_csr * (a3) and setup the result depending if the enable for the invalid * exception is set. */ or a3,INVALID_EXC and v0,a3,INVALID_ENABLE beq v0,zero,2f /* * The invalid trap was enabled so signal a SIGFPE and leave the * result register unmodified. */ li v0,SIGFPE jal post_signal li v0,1 b store_fpc_csr /* * The invalid trap was NOT enabled so the result is a quiet NaN. * So use the default quiet NaN and exit softfp(). */2: li t2,SQUIETNAN_LEAST move v0,zero b rd_1w /* * This is just a normal infinity + infinity so the result is just * an infinity with the sign of the operands. */3: move t2,t0 sll t1,SEXP_SHIFT or t2,t1 move v0,zero b rd_1w /* * This is infinity + x , where RS is the infinity so the result is * just RS (the infinity). */4: move t2,t0 sll t1,SEXP_SHIFT or t2,t1 move v0,zero b rd_1w /* * Check RT for an infinity value. At this point it is know that RS * is not an infinity. If RT is an infinity it will be the result. */5: bne t5,SEXP_INF,6f move t2,t4 sll t5,SEXP_SHIFT or t2,t5 move v0,zero b rd_1w6: # Check for the addition of zeros and produce the correct action if so bne t1,zero,3f # check RS for a zero value (first the exp) bne t2,zero,3f # then the fraction # Now RS is known to be zero bne t5,zero,2f # check RT for a zero value (first the exp) bne t6,zero,2f # then the fraction /* * Now RS and RT are known to be zeroes so set the correct result * according to the rounding mode (in the fpc_csr) and exit. */ and v0,a3,CSR_RM_MASK # get the rounding mode bne v0,CSR_RM_RMI,1f # check for round to - infinity or t2,t0,t4 # set the result and exit, for round to move v0,zero # - infinity the zero result is the b rd_1w # and of the operand's signs1: and t2,t0,t4 # set the result and exit, for other move v0,zero # rounding modes the zero result is the b rd_1w # or of the operand's signs # RS is a zero and RT is non-zero so the result is RT2: move t2,t4 sll t5,SEXP_SHIFT or t2,t5 or t2,t6 move v0,zero b rd_1w # RS is now known not to be zero so check RT for a zero value.3: bne t5,zero,4f # check RT for a zero value (first the exp) bne t6,zero,4f # then the fraction or t2,t0 # RT is a zero so the result is RS sll t1,SEXP_SHIFT or t2,t1 move v0,zero b rd_1w4: /* * Now that all the NaN, infinity and zero cases have been taken care * of what is left are values that can be added. So get all values * into a format that can be added. For normalized numbers set the * implied one and remove the exponent bias. For denormalized numbers * convert to normalized numbers with the correct exponent. */ bne t1,zero,1f # check for RS being denormalized li t1,-SEXP_BIAS+1 # set denorm's exponent jal rs_renorm_s # normalize it b 2f1: subu t1,SEXP_BIAS # if RS is not denormalized then remove the or t2,SIMP_1BIT # exponent bias, and set the implied 1 bit2: bne t5,zero,3f # check for RT being denormalized li t5,-SEXP_BIAS+1 # set denorm's exponent jal rt_renorm_s # normalize it b 4f3: subu t5,SEXP_BIAS # if RT is not denormalized then remove the or t6,SIMP_1BIT # exponent bias, and set the implied 1 bit4: /* * If the two values are the same except the sign return the correct * zero according to the rounding mode. */ beq t0,t4,2f # if the sign's are the same continue bne t1,t5,2f # if the exp's are not the same continue bne t2,t6,2f # if the fraction's are not the # same continue and v0,a3,CSR_RM_MASK # get the rounding mode bne v0,CSR_RM_RMI,1f # check for round to - infinity or t2,t0,t4 # set the result and exit, for round to # - infinity the zero result is the move v0,zero # and of the operand's signs b rd_1w1: and t2,t0,t4 # set the result and exit, for other # rounding modes the zero result is the move v0,zero # or of the operand's signs b rd_1w2: subu v1,t1,t5 # find the difference of the exponents move v0,v1 # in (v1) and the absolute value of bge v1,zero,1f # the difference in (v0) negu v01: ble v0,SFRAC_BITS+2,2f # is the difference is greater than the # number of bits of precision? li t8,STKBIT # set the sticky register bge v1,zero,1f # result is RT added with a sticky bit (for RS) move t1,t5 # result exponent will be RT's exponent move t2,zero b 4f1: # the result is RS added with a sticky bit (for RT) move t6,zero b 4f2: move t8,zero # clear the sticky register /* * If the exponent difference is greater than zero shift the smaller * value right by the exponent difference to align the binary point * before the addition. Also select the exponent of the result to * be the largest exponent of the two values. The result exponent is * left in (t1) so only if RS is to be shifted does RT's exponent * need to be moved into (t1). */ beq v0,zero,4f # if the exp diff is zero then no shift bgt v1,zero,3f # if the exp diff > 0 shift RT move t1,t5 # result exponent will be RT's exponent # Shift the fraction value of RS by < 32 (the right shift amount (v0)) negu v1,v0 # the left shift amount which is 32 addu v1,32 # minus right shift amount (v1) srl t8,v0 # shift the sticky register sll t9,t2,v1 or t8,t9 srl t2,v0 # shift the fraction b 4f3: # Shift the fraction value of RT by < 32 (the right shift amount (v0)) negu v1,v0 # the left shift amount which is 32 addu v1,32 # minus right shift amount (v1) srl t8,v0 # shift the sticky register sll t9,t6,v1 or t8,t9 srl t6,v0 # shift the fraction4: /* * Now if the signs are the same add the two fractions, else if the * signs are different then subtract the smaller fraction from the * larger fraction and the result's sign will be the sign of the * larger fraction. */ bne t0,t4,1f # if the signs not the same subtract # Add the fractions addu t2,t6 # add fraction words b norm_s1: /* * Subtract the smaller fraction from the larger fraction and set the * sign of the result to the sign of the larger fraction. */ blt t2,t6,3f # determine the smaller fraction # Note the case where they were equal # has already been taken care of1: /* * RT is smaller so subtract RT from RS and use RS's sign as the sign * of the result (the sign is already in the correct place (t0)). */ sltu t9,zero,t8 # set barrow out for sticky register subu t8,zero,t8 # subtract least signifiant fraction words bne t9,zero,2f # see if there is a barrow in # no barrow in to be subtracted out subu t2,t2,t6 # subtract fractions b norm_s2: # barrow in to be subtracted out subu t2,t2,t6 # subtract least fractions subu t2,1 # subtract barrow in b norm_s3: /* * RS is smaller so subtract RS from RT and use RT's sign as the sign * of the result. */ move t0,t4 # use RT's sign as the sign of result sltu t9,zero,t8 # set barrow out for sticky register subu t8,zero,t8 # subtract least signifiant fraction words bne t9,zero,1f # see if there is a barrow in # no barrow in to be subtracted out subu t2,t6,t2 # subtract least fractions b norm_s1: # barrow in to be subtracted out subu t2,t6,t2 # subtract least fractions subu t2,1 # subtract barrow in b norm_s/* * Add (and subtract) double RD = RS + RT (or RD = RS - RT). Again the FUNC * field (t8) is zero for adds. */.globl add_dadd_d: /* * Break out the operands into their fields (sign,exp,fraction) and * handle NaN operands by calling {rs,rt}breakout_d() . */ li t9,C1_FMT_DOUBLE*4 li v1,1 jal rs_breakout_d jal rt_breakout_d beq t8,zero,1f # if doing a subtract then negate RT lui v0,SIGNBIT>>16 xor t4,v01: # Check for addition of infinities, and produce the correct action if so bne t1,DEXP_INF,5f # is RS an infinity? # RS is an infinity bne t5,DEXP_INF,4f # is RT also an infinity? # RT is an infinity beq t0,t4,3f # do the infinities have the same sign? /* * The infinities do NOT have the same sign thus this is an invalid * operation for addition so set the invalid exception in the fpc_csr * (a3) and setup the result depending if the enable for the invalid * exception is set. */ or a3,INVALID_EXC and v0,a3,INVALID_ENABLE beq v0,zero,2f /* * The invalid trap was enabled so signal a SIGFPE and leave the * result register unmodified. */ li v0,SIGFPE jal post_signal li v0,1 b store_fpc_csr /* * The invalid trap was NOT enabled so the result is a quiet NaN. * So use the default quiet NaN and exit softfp(). */2: li t2,DQUIETNAN_LESS li t3,DQUIETNAN_LEAST move v0,zero b rd_2w /* * This is just a normal infinity + infinity so the result is just * an infinity with the sign of the operands. */3: move t2,t0 sll t1,DEXP_SHIFT or t2,t1 move v0,zero b rd_2w /* * This is infinity + x , where RS is the infinity so the result is * just RS (the infinity). */4: move t2,t0 sll t1,DEXP_SHIFT or t2,t1 move v0,zero b rd_2w /* * Check RT for an infinity value. At this point it is know that RS * is not an infinity. If RT is an infinity it will be the result. */5: bne t5,DEXP_INF,6f move t2,t4 sll t5,DEXP_SHIFT or t2,t5 move t3,t7 move v0,zero b rd_2w6: # Check for the addition of zeros and produce the correct action if so bne t1,zero,3f # check RS for a zero value (first the exp) bne t2,zero,3f # then the high part of the fraction bne t3,zero,3f # then the low part of the fraction # Now RS is known to be zero bne t5,zero,2f # check RT for a zero value (first the exp) bne t6,zero,2f # then the high part of the fraction bne t7,zero,2f # then the low part of the fraction /* * Now RS and RT are known to be zeroes so set the correct result * according to the rounding mode (in the fpc_csr) and exit. */ and v0,a3,CSR_RM_MASK # get the rounding mode bne v0,CSR_RM_RMI,1f # check for round to - infinity or t2,t0,t4 # set the result and exit, for round to move v0,zero # - infinity the zero result is the b rd_2w # and of the operand's signs1: and t2,t0,t4 # set the result and exit, for other move v0,zero # rounding modes the zero result is the b rd_2w # or of the operand's signs # RS is a zero and RT is non-zero so the result is RT2: move t2,t4 sll t5,DEXP_SHIFT or t2,t5 or t2,t6 move t3,t7 move v0,zero b rd_2w # RS is now known not to be zero so check RT for a zero value.3: bne t5,zero,4f # check RT for a zero value (first the exp) bne t6,zero,4f # then the high part of the fraction bne t7,zero,4f # then the low part of the fraction or t2,t0 # RT is a zero so the result is RS sll t1,DEXP_SHIFT or t2,t1 move v0,zero b rd_2w4: /* * Now that all the NaN, infinity and zero cases have been taken care * of what is left are values that can be added. So get all values * into a format that can be added. For normalized numbers set the * implied one and remove the exponent bias. For denormalized numbers * convert to normalized numbers with the correct exponent. */ bne t1,zero,1f # check for RS being denormalized li t1,-DEXP_BIAS+1 # set denorm's exponent jal rs_renorm_d # normalize it b 2f1: subu t1,DEXP_BIAS # if RS is not denormalized then remove the or t2,DIMP_1BIT # exponent bias, and set the implied 1 bit2: bne t5,zero,3f # check for RT being denormalized li t5,-DEXP_BIAS+1 # set denorm's exponent jal rt_renorm_d # normalize it b 4f3: subu t5,DEXP_BIAS # if RT is not denormalized then remove the or t6,DIMP_1BIT # exponent bias, and set the implied 1 bit4: /* * If the two values are the same except the sign return the correct * zero according to the rounding mode. */ beq t0,t4,2f # if the sign's are the same continue bne t1,t5,2f # if the exp's are not the same continue bne t2,t6,2f # if the fraction's are not the bne t3,t7,2f # same continue and v0,a3,CSR_RM_MASK # get the rounding mode bne v0,CSR_RM_RMI,1f # check for round to - infinity or t2,t0,t4 # set the result and exit, for round to move t3,zero # - infinity the zero result is the move v0,zero # and of the operand's signs b rd_2w1: and t2,t0,t4 # set the result and exit, for other move t3,zero # rounding modes the zero result is the move v0,zero # or of the operand's signs b rd_2w2: subu v1,t1,t5 # find the difference of the exponents move v0,v1 # in (v1) and the absolute value of bge v1,zero,1f # the difference in (v0) negu v01: ble v0,DFRAC_BITS+2,3f # is the difference is greater than the # number of bits of precision li t8,STKBIT # set the sticky register bge v1,zero,2f # result is RT with a STKBIT added (for RS) move t1,t5 # result exponent will be RT's exponent move t2,zero move t3,zero b 9f2: # the result is RS with a STKBIT added (for RT) move t6,zero move t7,zero b 9f3: move t8,zero # clear the sticky register /* * If the exponent difference is greater than zero shift the smaller * value right by the exponent difference to align the binary point * before the addition. Also select the exponent of the result to * be the largest exponent of the two values. The result exponent is * left in (t1) so only if RS is to be shifted does RT's exponent * need to be moved into (t1).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -