fenvinline.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*
  2. Inline floating-point environment handling functions for Hyperstone e1-32X.
  3. Copyright (C) 2002-2003, George Thanos <george.thanos@gdt.gr>
  4. Yannis Mitsos <yannis.mitsos@gdt.gr>
  5. Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
  6. The GNU C Library is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU Lesser General Public
  8. License as published by the Free Software Foundation; either
  9. version 2.1 of the License, or (at your option) any later version.
  10. The GNU C Library is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. Lesser General Public License for more details.
  14. You should have received a copy of the GNU Lesser General Public
  15. License along with the GNU C Library; if not, write to the Free
  16. Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  17. 02111-1307 USA. */
  18. #if defined __GNUC__ && !defined _SOFT_FLOAT && !defined __NO_MATH_INLINES
  19. /**********************************************************
  20. * --- A small description of the E1-16/32X FP unit. ---
  21. * FP exceptions can be enabled and disabled through
  22. * <feenableexcept>, <fedisableexcept>.
  23. *
  24. * - When an enabled exception takes place a SIGFPE signal
  25. * is sent to the process by the exception handler. User
  26. * can test for the exception that took place through
  27. * <fetestexcept>.
  28. * feraiseexcept works only for accrued exceptions.
  29. *
  30. * - When a disabld exception takes place it does not generate
  31. * a trap. The user can check if any exception took place after
  32. * an FP instruction by issuing an <fetestexcept> command.
  33. * User should first clear the G2 register by issuing an
  34. * <feclearexcept> function.
  35. * The following program is a typical example of how the user
  36. * should check for exceptions that did not generate a SIGFPE
  37. * signal :
  38. * {
  39. * double f;
  40. * int raised;
  41. * feclearexcept (FE_ALL_EXCEPT);
  42. * f = compute ();
  43. * raised = fetestexcept (FE_OVERFLOW | FE_INVALID);
  44. * if (raised & FE_OVERFLOW) { ... }
  45. * if (raised & FE_INVALID) { ... }
  46. * ...
  47. * }
  48. ***********************************************************/
  49. /* Get FPU rounding mode */
  50. #define fegetround() \
  51. ({ \
  52. unsigned int tmp; \
  53. __asm__ __volatile__("mov %0, SR" \
  54. :"=l"(tmp) \
  55. :/*no input*/); \
  56. tmp &= (3<<13); \
  57. (tmp); \
  58. })
  59. /* Set FPU rounding mode */
  60. #define fesetround(round) \
  61. ({ \
  62. unsigned int tmp = (3 << 13); \
  63. while(1) { \
  64. /* Clear SR.FRM field */ \
  65. __asm__ __volatile__("andn SR, %0" \
  66. :/*no output*/ \
  67. :"l"(tmp) ); \
  68. tmp &= round; \
  69. \
  70. if(tmp) { \
  71. tmp = -1; \
  72. break; \
  73. } \
  74. \
  75. __asm__ __volatile__("or SR, %0" \
  76. :/*no input*/ \
  77. :"l"(round) ); \
  78. tmp = 0; \
  79. break; \
  80. } \
  81. (tmp); \
  82. })
  83. /* The following functions test for accrued exceptions.
  84. * No trap is generated on an FP exception.
  85. */
  86. static __inline__ feclearexcept(int __excepts)
  87. {
  88. unsigned int enabled_excepts, disabled_excepts;
  89. /* Check that __excepts is correctly set */
  90. if( __excepts & (~0x1F00) )
  91. return -1;
  92. __asm__ __volatile__("mov %0, SR"
  93. :"=l"(enabled_excepts)
  94. :/*no input*/ );
  95. enabled_excepts &= 0x1F00;
  96. disabled_excepts = ~enabled_excepts;
  97. disabled_excepts &= 0x1F00;
  98. enabled_excepts &= __excepts;
  99. disabled_excepts &= __excepts;
  100. /* Clear accrued exceptions */
  101. __asm__ __volatile__("andn G2, %0\n\t"
  102. "andn G2, %1\n\t"
  103. :/*no output*/
  104. :"l"(enabled_excepts),
  105. "l"(disabled_excepts >> 8) );
  106. return 0;
  107. }
  108. /* fetestexcepts tests both for actual and accrued
  109. * excepts. You can test for an exception either after
  110. * an FP instruction or within a SIGFPE handler
  111. */
  112. inline int fetestexcept(int __excepts)
  113. {
  114. unsigned int G2, G2en, G2dis;
  115. unsigned int enabled_excepts, disabled_excepts;
  116. /* Check that __excepts is correctly set */
  117. if( __excepts & (~0x1F00) )
  118. return -1;
  119. __asm__ __volatile__("mov %0, SR"
  120. :"=l"(enabled_excepts)
  121. :/*no input*/ );
  122. enabled_excepts &= 0x1F00;
  123. disabled_excepts = ~enabled_excepts;
  124. disabled_excepts &= 0x1F00;
  125. __asm__ __volatile__("mov %0, G2"
  126. :"=l"(G2)
  127. :/*no input*/ );
  128. G2en = G2 & 0x1F00;
  129. G2dis = G2 & 0x1F;
  130. G2en &= enabled_excepts;
  131. G2dis &= (disabled_excepts >> 8);
  132. return ( G2en | (G2dis << 8) );
  133. }
  134. static __inline__ int feraiseexcept(int __excepts)
  135. {
  136. __asm__ __volatile__("or G2, %0"
  137. :/*no output*/
  138. :"l"( __excepts >> 8 ) );
  139. return 0;
  140. }
  141. /* The following functions enable/disable individual exceptions.
  142. * If enabling an exception trap is going to occur, in case of error.
  143. */
  144. #define feenableexcept(__excepts) \
  145. ({ \
  146. int __retval, __pexcepts; \
  147. int __tmpexcepts = __excepts; \
  148. \
  149. while(1) { \
  150. __asm__ __volatile__("mov %0, SR" \
  151. :"=l"(__pexcepts) \
  152. :/*no input*/ ); \
  153. __pexcepts &= 0x1F00; \
  154. \
  155. /* Check if __except values are valid */ \
  156. if( __tmpexcepts & ~0x1F00 ) { \
  157. __retval = -1; \
  158. fprintf(stderr,"Non valid excepts\n");\
  159. break; \
  160. } \
  161. \
  162. __asm__ __volatile__("or SR, %0" \
  163. :/*no output*/ \
  164. :"l"(__tmpexcepts) ); \
  165. __retval = __pexcepts; \
  166. break; \
  167. } \
  168. (__retval); \
  169. })
  170. #define fedisableexcept(__excepts) \
  171. ({ \
  172. int __retval, __pexcepts; \
  173. int __tmpexcepts = __excepts; \
  174. \
  175. while(1) { \
  176. __asm__ __volatile__("mov %0, SR" \
  177. :"=l"(__pexcepts) \
  178. :/*no input*/ ); \
  179. __pexcepts &= 0x1F00; \
  180. \
  181. /* Check if __except values are valid */ \
  182. if( __tmpexcepts & ~0x1F00 ) { \
  183. __retval = -1; \
  184. fprintf(stderr,"Non valid excepts\n");\
  185. break; \
  186. } \
  187. \
  188. __asm__ __volatile__("andn SR, %0" \
  189. :/*no output*/ \
  190. :"l"(__tmpexcepts) ); \
  191. __retval = __pexcepts; \
  192. break; \
  193. } \
  194. (__retval); \
  195. })
  196. static __inline__ int fegetexcept(int excepts)
  197. {
  198. unsigned int tmp;
  199. __asm__ __volatile__("mov %0, SR"
  200. :"=l"(tmp)
  201. :/*no input*/ );
  202. tmp &= 0x1F00;
  203. return tmp;
  204. }
  205. static __inline__ int fegetenv(fenv_t *envp)
  206. {
  207. __asm__ __volatile__("mov %0, SR\n\t
  208. mov %1, SR\n\t
  209. mov %2, G2\n\t
  210. mov %3, G2\n\t"
  211. :"=l"(envp->round_mode),
  212. "=l"(envp->trap_enabled),
  213. "=l"(envp->accrued_except),
  214. "=l"(envp->actual_except)
  215. :/*no input*/ );
  216. envp->round_mode &= (3<<13);
  217. envp->trap_enabled &= 0x1F00;
  218. envp->accrued_except &= 0x1F;
  219. envp->accrued_except <<= 8;
  220. envp->actual_except &= 0x1F00;
  221. }
  222. #define feholdexcept(envp) \
  223. ( \
  224. fegetenv(envp); \
  225. fedisableexcept(FE_ALL_EXCEPT); \
  226. feclearexcept(FE_ALL_EXCEPT); \
  227. (0); \
  228. )
  229. #define fesetenv(envp) \
  230. ({ \
  231. /* Clear FRM & FTE field of SR */ \
  232. unsigned long clearSR = ( 127<<8 ); \
  233. __asm__ __volatile__("andn SR, %0\n\t" \
  234. "or SR, %1\n\t" \
  235. "or SR, %2\n\t" \
  236. :/*no output*/ \
  237. :"l"(clearSR), \
  238. "l"(envp->round_mode), \
  239. "l"(envp->trap_enabled) ); \
  240. __asm__ __volatile__("andn G2, 0x1F1F\n\t" \
  241. "or G2, %0\n\t" \
  242. "or G2, %1\n\t" \
  243. :/*no output*/ \
  244. :"l"( envp->accrued_except >> 8),\
  245. :"l"( envp->actual_except ) ); \
  246. (0); /* return 0 */ \
  247. })
  248. #define feupdateenv(envp) \
  249. ({ \
  250. /* Clear FRM & FTE field of SR */ \
  251. __asm__ __volatile__(/* We dont clear the prev SR*/ \
  252. "or SR, %1\n\t" \
  253. "or SR, %2\n\t" \
  254. :/*no output*/ \
  255. :"l"(clearSR), \
  256. "l"(envp->round_mode), \
  257. "l"(envp->accrued_except) ); \
  258. __asm__ __volatile__(/* We dont clear the prev SR*/ \
  259. "or G2, %0\n\t" \
  260. "or G2, %1\n\t" \
  261. :/*no output*/ \
  262. :"l"( envp->accrued_except >> 8),\
  263. :"l"( envp->actual_except ) ); \
  264. (0); /* return 0 */ \
  265. })
  266. #endif /* __GNUC__ && !_SOFT_FLOAT */