reg_u_add.S
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:4k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. .file "reg_u_add.S"
  2. /*---------------------------------------------------------------------------+
  3.  |  reg_u_add.S                                                              |
  4.  |                                                                           |
  5.  | Add two valid (TAG_Valid) FPU_REG numbers, of the same sign, and put the  |
  6.  |   result in a destination FPU_REG.                                        |
  7.  |                                                                           |
  8.  | Copyright (C) 1992,1993,1995,1997                                         |
  9.  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  10.  |                  E-mail   billm@suburbia.net                              |
  11.  |                                                                           |
  12.  | Call from C as:                                                           |
  13.  |   int  FPU_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,             |
  14.  |                                                int control_w)             |
  15.  |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
  16.  |    one was raised, or -1 on internal error.                               |
  17.  |                                                                           |
  18.  +---------------------------------------------------------------------------*/
  19. /*
  20.  |    Kernel addition routine FPU_u_add(reg *arg1, reg *arg2, reg *answ).
  21.  |    Takes two valid reg f.p. numbers (TAG_Valid), which are
  22.  |    treated as unsigned numbers,
  23.  |    and returns their sum as a TAG_Valid or TAG_Special f.p. number.
  24.  |    The returned number is normalized.
  25.  |    Basic checks are performed if PARANOID is defined.
  26.  */
  27. #include "exception.h"
  28. #include "fpu_emu.h"
  29. #include "control_w.h"
  30. .text
  31. ENTRY(FPU_u_add)
  32. pushl %ebp
  33. movl %esp,%ebp
  34. pushl %esi
  35. pushl %edi
  36. pushl %ebx
  37. movl PARAM1,%esi /* source 1 */
  38. movl PARAM2,%edi /* source 2 */
  39. movl PARAM6,%ecx
  40. movl %ecx,%edx
  41. subl PARAM7,%ecx /* exp1 - exp2 */
  42. jge L_arg1_larger
  43. /* num1 is smaller */
  44. movl SIGL(%esi),%ebx
  45. movl SIGH(%esi),%eax
  46. movl %edi,%esi
  47. movl PARAM7,%edx
  48. negw %cx
  49. jmp L_accum_loaded
  50. L_arg1_larger:
  51. /* num1 has larger or equal exponent */
  52. movl SIGL(%edi),%ebx
  53. movl SIGH(%edi),%eax
  54. L_accum_loaded:
  55. movl PARAM3,%edi /* destination */
  56. movw %dx,EXP(%edi) /* Copy exponent to destination */
  57. xorl %edx,%edx /* clear the extension */
  58. #ifdef PARANOID
  59. testl $0x80000000,%eax
  60. je L_bugged
  61. testl $0x80000000,SIGH(%esi)
  62. je L_bugged
  63. #endif /* PARANOID */
  64. /* The number to be shifted is in %eax:%ebx:%edx */
  65. cmpw $32,%cx /* shrd only works for 0..31 bits */
  66. jnc L_more_than_31
  67. /* less than 32 bits */
  68. shrd %cl,%ebx,%edx
  69. shrd %cl,%eax,%ebx
  70. shr %cl,%eax
  71. jmp L_shift_done
  72. L_more_than_31:
  73. cmpw $64,%cx
  74. jnc L_more_than_63
  75. subb $32,%cl
  76. jz L_exactly_32
  77. shrd %cl,%eax,%edx
  78. shr %cl,%eax
  79. orl %ebx,%ebx
  80. jz L_more_31_no_low /* none of the lowest bits is set */
  81. orl $1,%edx /* record the fact in the extension */
  82. L_more_31_no_low:
  83. movl %eax,%ebx
  84. xorl %eax,%eax
  85. jmp L_shift_done
  86. L_exactly_32:
  87. movl %ebx,%edx
  88. movl %eax,%ebx
  89. xorl %eax,%eax
  90. jmp L_shift_done
  91. L_more_than_63:
  92. cmpw $65,%cx
  93. jnc L_more_than_64
  94. movl %eax,%edx
  95. orl %ebx,%ebx
  96. jz L_more_63_no_low
  97. orl $1,%edx
  98. jmp L_more_63_no_low
  99. L_more_than_64:
  100. movl $1,%edx /* The shifted nr always at least one '1' */
  101. L_more_63_no_low:
  102. xorl %ebx,%ebx
  103. xorl %eax,%eax
  104. L_shift_done:
  105. /* Now do the addition */
  106. addl SIGL(%esi),%ebx
  107. adcl SIGH(%esi),%eax
  108. jnc L_round_the_result
  109. /* Overflow, adjust the result */
  110. rcrl $1,%eax
  111. rcrl $1,%ebx
  112. rcrl $1,%edx
  113. jnc L_no_bit_lost
  114. orl $1,%edx
  115. L_no_bit_lost:
  116. incw EXP(%edi)
  117. L_round_the_result:
  118. jmp fpu_reg_round /* Round the result */
  119. #ifdef PARANOID
  120. /* If we ever get here then we have problems! */
  121. L_bugged:
  122. pushl EX_INTERNAL|0x201
  123. call EXCEPTION
  124. pop %ebx
  125. movl $-1,%eax
  126. jmp L_exit
  127. L_exit:
  128. popl %ebx
  129. popl %edi
  130. popl %esi
  131. leave
  132. ret
  133. #endif /* PARANOID */