reg_u_add.S 3.9 KB

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