fenvinline.h 9.3 KB

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