reg_u_mul.S 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. .file "reg_u_mul.S"
  3. /*---------------------------------------------------------------------------+
  4. | reg_u_mul.S |
  5. | |
  6. | Core multiplication routine |
  7. | |
  8. | Copyright (C) 1992,1993,1995,1997 |
  9. | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  10. | E-mail [email protected] |
  11. | |
  12. | |
  13. +---------------------------------------------------------------------------*/
  14. /*---------------------------------------------------------------------------+
  15. | Basic multiplication routine. |
  16. | Does not check the resulting exponent for overflow/underflow |
  17. | |
  18. | FPU_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw); |
  19. | |
  20. | Internal working is at approx 128 bits. |
  21. | Result is rounded to nearest 53 or 64 bits, using "nearest or even". |
  22. +---------------------------------------------------------------------------*/
  23. #include "exception.h"
  24. #include "fpu_emu.h"
  25. #include "control_w.h"
  26. #ifndef NON_REENTRANT_FPU
  27. /* Local storage on the stack: */
  28. #define FPU_accum_0 -4(%ebp) /* ms word */
  29. #define FPU_accum_1 -8(%ebp)
  30. #else
  31. /* Local storage in a static area: */
  32. .data
  33. .align 4,0
  34. FPU_accum_0:
  35. .long 0
  36. FPU_accum_1:
  37. .long 0
  38. #endif /* NON_REENTRANT_FPU */
  39. .text
  40. SYM_FUNC_START(FPU_u_mul)
  41. pushl %ebp
  42. movl %esp,%ebp
  43. #ifndef NON_REENTRANT_FPU
  44. subl $8,%esp
  45. #endif /* NON_REENTRANT_FPU */
  46. pushl %esi
  47. pushl %edi
  48. pushl %ebx
  49. movl PARAM1,%esi
  50. movl PARAM2,%edi
  51. #ifdef PARANOID
  52. testl $0x80000000,SIGH(%esi)
  53. jz L_bugged
  54. testl $0x80000000,SIGH(%edi)
  55. jz L_bugged
  56. #endif /* PARANOID */
  57. xorl %ecx,%ecx
  58. xorl %ebx,%ebx
  59. movl SIGL(%esi),%eax
  60. mull SIGL(%edi)
  61. movl %eax,FPU_accum_0
  62. movl %edx,FPU_accum_1
  63. movl SIGL(%esi),%eax
  64. mull SIGH(%edi)
  65. addl %eax,FPU_accum_1
  66. adcl %edx,%ebx
  67. /* adcl $0,%ecx // overflow here is not possible */
  68. movl SIGH(%esi),%eax
  69. mull SIGL(%edi)
  70. addl %eax,FPU_accum_1
  71. adcl %edx,%ebx
  72. adcl $0,%ecx
  73. movl SIGH(%esi),%eax
  74. mull SIGH(%edi)
  75. addl %eax,%ebx
  76. adcl %edx,%ecx
  77. /* Get the sum of the exponents. */
  78. movl PARAM6,%eax
  79. subl EXP_BIAS-1,%eax
  80. /* Two denormals can cause an exponent underflow */
  81. cmpl EXP_WAY_UNDER,%eax
  82. jg Exp_not_underflow
  83. /* Set to a really low value allow correct handling */
  84. movl EXP_WAY_UNDER,%eax
  85. Exp_not_underflow:
  86. /* Have now finished with the sources */
  87. movl PARAM3,%edi /* Point to the destination */
  88. movw %ax,EXP(%edi)
  89. /* Now make sure that the result is normalized */
  90. testl $0x80000000,%ecx
  91. jnz LResult_Normalised
  92. /* Normalize by shifting left one bit */
  93. shll $1,FPU_accum_0
  94. rcll $1,FPU_accum_1
  95. rcll $1,%ebx
  96. rcll $1,%ecx
  97. decw EXP(%edi)
  98. LResult_Normalised:
  99. movl FPU_accum_0,%eax
  100. movl FPU_accum_1,%edx
  101. orl %eax,%eax
  102. jz L_extent_zero
  103. orl $1,%edx
  104. L_extent_zero:
  105. movl %ecx,%eax
  106. jmp fpu_reg_round
  107. #ifdef PARANOID
  108. L_bugged:
  109. pushl EX_INTERNAL|0x205
  110. call EXCEPTION
  111. pop %ebx
  112. jmp L_exit
  113. L_exit:
  114. popl %ebx
  115. popl %edi
  116. popl %esi
  117. leave
  118. RET
  119. #endif /* PARANOID */
  120. SYM_FUNC_END(FPU_u_mul)