reg_u_mul.S 3.6 KB

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