m_fixed.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /* Emacs style mode select -*- C++ -*-
  2. *-----------------------------------------------------------------------------
  3. *
  4. *
  5. * PrBoom: a Doom port merged with LxDoom and LSDLDoom
  6. * based on BOOM, a modified and improved DOOM engine
  7. * Copyright (C) 1999 by
  8. * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
  9. * Copyright (C) 1999-2000 by
  10. * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
  11. * Copyright 2005, 2006 by
  12. * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
  13. *
  14. * This program is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU General Public License
  16. * as published by the Free Software Foundation; either version 2
  17. * of the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  27. * 02111-1307, USA.
  28. *
  29. * DESCRIPTION:
  30. * Fixed point arithemtics, implementation.
  31. *
  32. *-----------------------------------------------------------------------------*/
  33. #ifndef __M_FIXED__
  34. #define __M_FIXED__
  35. #include "config.h"
  36. #include "doomtype.h"
  37. /*
  38. * Fixed point, 32bit as 16.16.
  39. */
  40. #define FRACBITS 16
  41. #define FRACUNIT (1<<FRACBITS)
  42. typedef int fixed_t;
  43. /*
  44. * Absolute Value
  45. *
  46. * killough 5/10/98: In djgpp, use inlined assembly for performance
  47. * killough 9/05/98: better code seems to be gotten from using inlined C
  48. */
  49. #ifdef _MSC_VER
  50. # ifdef I386_ASM
  51. #pragma warning( disable : 4035 )
  52. __inline static int D_abs(int x)
  53. {
  54. __asm
  55. {
  56. mov eax,x
  57. cdq
  58. xor eax,edx
  59. sub eax,edx
  60. }
  61. }
  62. # else /* I386_ASM */
  63. inline static const int D_abs(x)
  64. {
  65. fixed_t _t = (x),_s;
  66. _s = _t >> (8*sizeof _t-1);
  67. return (_t^_s)-_s;
  68. }
  69. # endif /* I386_ASM */
  70. #else /* _MSC_VER */
  71. #define D_abs(x) ({fixed_t _t = (x), _s = _t >> (8*sizeof _t-1); (_t^_s)-_s;})
  72. #endif /* _MSC_VER */
  73. /*
  74. * Fixed Point Multiplication
  75. */
  76. #ifdef I386_ASM
  77. # ifdef _MSC_VER
  78. #pragma warning( disable : 4035 )
  79. __inline static fixed_t FixedMul(fixed_t a, fixed_t b)
  80. {
  81. // return (fixed_t)((longlong) a*b >> FRACBITS);
  82. __asm
  83. {
  84. mov eax,a
  85. imul b
  86. shrd eax,edx,16
  87. }
  88. }
  89. #pragma warning( default : 4035 )
  90. # else /* _MSC_VER */
  91. /* killough 5/10/98: In djgpp, use inlined assembly for performance
  92. * CPhipps - made __inline__ to inline, as specified in the gcc docs
  93. * Also made const. Also __asm__ to asm, as in docs.
  94. * Replaced inline asm with Julian's version for Eternity dated 6/7/2001
  95. */
  96. inline
  97. static CONSTFUNC fixed_t FixedMul(fixed_t a, fixed_t b)
  98. {
  99. fixed_t result;
  100. asm (
  101. " imull %2 ;"
  102. " shrdl $16,%%edx,%0 ;"
  103. : "=a" (result) /* eax is always the result */
  104. : "0" (a), /* eax is also first operand */
  105. "rm" (b) /* second operand can be reg or mem */
  106. : "%edx", "%cc" /* edx and condition codes clobbered */
  107. );
  108. return result;
  109. }
  110. # endif /* _MSC_VER */
  111. #else /* I386_ASM */
  112. /* CPhipps - made __inline__ to inline, as specified in the gcc docs
  113. * Also made const */
  114. inline static CONSTFUNC fixed_t FixedMul(fixed_t a, fixed_t b)
  115. {
  116. return (fixed_t)((int_64_t) a*b >> FRACBITS);
  117. }
  118. #endif /* I386_ASM */
  119. /*
  120. * Fixed Point Division
  121. */
  122. #ifdef I386_ASM
  123. # ifdef _MSC_VER
  124. #pragma warning( disable : 4035 )
  125. __inline static fixed_t FixedDiv(fixed_t a, fixed_t b)
  126. {
  127. // e6y
  128. // zg is a master of engineer science.
  129. //
  130. // Fixed crash with FixedDiv(-2147483648,x)
  131. // Exception Number : EXCEPTION_INT_OVERFLOW(C0000095)
  132. //
  133. // Some other ports (Eternity, Chocolate) return wrong value instead of MAXINT.
  134. // For example FixedDiv(-2147483648,-30576) should return INT_MAX instead of 307907126
  135. // 307907126 is truncated correct int64 value: 4602874423 - 2^32 = 307907126
  136. if ((unsigned)D_abs(a) >> 14 >= (unsigned)D_abs(b))
  137. return (a^b)<0 ? INT_MIN : INT_MAX;
  138. __asm
  139. {
  140. mov eax,a
  141. mov ebx,b
  142. mov edx,eax
  143. shl eax,16 // proff 11/06/98: Changed from sal to shl, I think
  144. // this is better
  145. sar edx,16
  146. idiv ebx // This is needed, because when I used 'idiv b' the
  147. // compiler produced wrong code in a different place
  148. }
  149. }
  150. #pragma warning( default : 4035 )
  151. # else /* _MSC_VER */
  152. /* killough 5/10/98: In djgpp, use inlined assembly for performance
  153. * killough 9/5/98: optimized to reduce the number of branches
  154. * CPhipps - made __inline__ to inline, as specified in the gcc docs
  155. * Also made const, also __asm__ to asm as in docs.
  156. * Replaced inline asm with Julian's version for Eternity dated 6/7/2001
  157. */
  158. inline
  159. static CONSTFUNC fixed_t FixedDiv(fixed_t a, fixed_t b)
  160. {
  161. //e6y: zg is a master of engineer science
  162. if ((unsigned)D_abs(a) >> 14 < (unsigned)D_abs(b))
  163. {
  164. fixed_t result;
  165. asm (
  166. " idivl %3 ;"
  167. : "=a" (result)
  168. : "0" (a<<16),
  169. "d" (a>>16),
  170. "rm" (b)
  171. : "%cc"
  172. );
  173. return result;
  174. }
  175. return ((a^b)>>31) ^ INT_MAX;
  176. }
  177. # endif /* _MSC_VER */
  178. #else /* I386_ASM */
  179. /* CPhipps - made __inline__ to inline, as specified in the gcc docs
  180. * Also made const */
  181. inline static CONSTFUNC fixed_t FixedDiv(fixed_t a, fixed_t b)
  182. {
  183. return ((unsigned)D_abs(a)>>14) >= (unsigned)D_abs(b) ? ((a^b)>>31) ^ INT_MAX :
  184. (fixed_t)(((int_64_t) a << FRACBITS) / b);
  185. }
  186. #endif /* I386_ASM */
  187. /* CPhipps -
  188. * FixedMod - returns a % b, guaranteeing 0<=a<b
  189. * (notice that the C standard for % does not guarantee this)
  190. */
  191. inline static CONSTFUNC fixed_t FixedMod(fixed_t a, fixed_t b)
  192. {
  193. if (b & (b-1)) {
  194. fixed_t r = a % b;
  195. return ((r<0) ? r+b : r);
  196. } else
  197. return (a & (b-1));
  198. }
  199. #endif