mathu.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2004 by Florian Klaempfl
  4. member of the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$if defined(wince)}
  12. const
  13. _DN_SAVE = $00000000;
  14. _DN_FLUSH = $01000000;
  15. _EM_INVALID = $00000010;
  16. _EM_DENORMAL = $00080000;
  17. _EM_ZERODIVIDE = $00000008;
  18. _EM_OVERFLOW = $00000004;
  19. _EM_UNDERFLOW = $00000002;
  20. _EM_INEXACT = $00000001;
  21. _IC_AFFINE = $00040000;
  22. _IC_PROJECTIVE = $00000000;
  23. _RC_CHOP = $00000300;
  24. _RC_UP = $00000200;
  25. _RC_DOWN = $00000100;
  26. _RC_NEAR = $00000000;
  27. _PC_24 = $00020000;
  28. _PC_53 = $00010000;
  29. _PC_64 = $00000000;
  30. _MCW_DN = $03000000;
  31. _MCW_EM = $0008001F;
  32. _MCW_IC = $00040000;
  33. _MCW_RC = $00000300;
  34. _MCW_PC = $00030000;
  35. function _controlfp(new: DWORD; mask: DWORD): DWORD; cdecl; external 'coredll';
  36. function GetRoundMode: TFPURoundingMode;
  37. var
  38. c: dword;
  39. begin
  40. c:=_controlfp(0, 0);
  41. Result:=TFPURoundingMode((c shr 16) and 3);
  42. end;
  43. function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
  44. var
  45. c: dword;
  46. begin
  47. c:=Ord(RoundMode) shl 16;
  48. c:=_controlfp(c, _MCW_RC);
  49. Result:=TFPURoundingMode((c shr 16) and 3);
  50. end;
  51. function GetPrecisionMode: TFPUPrecisionMode;
  52. var
  53. c: dword;
  54. begin
  55. c:=_controlfp(0, 0);
  56. if c and _MCW_PC = _PC_64 then
  57. Result:=pmDouble
  58. else
  59. Result:=pmSingle;
  60. end;
  61. function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode;
  62. var
  63. c: dword;
  64. begin
  65. Result:=GetPrecisionMode;
  66. if Precision = pmSingle then
  67. c:=_PC_24
  68. else
  69. c:=_PC_64;
  70. _controlfp(c, _MCW_PC);
  71. end;
  72. function ConvertExceptionMask(em: dword): TFPUExceptionMask;
  73. begin
  74. Result:=[];
  75. if em and _EM_INVALID = 0 then
  76. Result:=Result + [exInvalidOp];
  77. if em and _EM_DENORMAL = 0 then
  78. Result:=Result + [exDenormalized];
  79. if em and _EM_ZERODIVIDE = 0 then
  80. Result:=Result + [exZeroDivide];
  81. if em and _EM_OVERFLOW = 0 then
  82. Result:=Result + [exOverflow];
  83. if em and _EM_UNDERFLOW = 0 then
  84. Result:=Result + [exUnderflow];
  85. if em and _EM_INEXACT = 0 then
  86. Result:=Result + [exPrecision];
  87. end;
  88. function GetExceptionMask: TFPUExceptionMask;
  89. begin
  90. Result:=ConvertExceptionMask(_controlfp(0, 0));
  91. end;
  92. function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
  93. var
  94. c: dword;
  95. begin
  96. c:=0;
  97. if not(exInvalidOp in Mask) then
  98. c:=c or _EM_INVALID;
  99. if not(exDenormalized in Mask) then
  100. c:=c or _EM_DENORMAL;
  101. if not(exZeroDivide in Mask) then
  102. c:=c or _EM_ZERODIVIDE;
  103. if not(exOverflow in Mask) then
  104. c:=c or _EM_OVERFLOW;
  105. if not(exUnderflow in Mask) then
  106. c:=c or _EM_UNDERFLOW;
  107. if not(exPrecision in Mask) then
  108. c:=c or _EM_INEXACT;
  109. c:=_controlfp(c, _MCW_EM);
  110. Result:=ConvertExceptionMask(c);
  111. end;
  112. procedure ClearExceptions(RaisePending: Boolean =true);
  113. begin
  114. end;
  115. {$elseif defined(darwin) or defined(FPUVFPV2) or defined(FPUVFPV3) or defined(FPUVFPV3_d16)}
  116. const
  117. _VFP_ENABLE_IM = 1 shl 8; { invalid operation }
  118. _VFP_ENABLE_ZM = 1 shl 9; { divide by zero }
  119. _VFP_ENABLE_OM = 1 shl 10; { overflow }
  120. _VFP_ENABLE_UM = 1 shl 11; { underflow }
  121. _VFP_ENABLE_PM = 1 shl 12; { inexact }
  122. _VFP_ENABLE_DM = 1 shl 15; { denormalized operation }
  123. _VFP_ENABLE_ALL = _VFP_ENABLE_IM or
  124. _VFP_ENABLE_ZM or
  125. _VFP_ENABLE_OM or
  126. _VFP_ENABLE_UM or
  127. _VFP_ENABLE_PM or
  128. _VFP_ENABLE_DM; { mask for all flags }
  129. _VFP_ROUNDINGMODE_MASK_SHIFT = 22;
  130. _VFP_ROUNDINGMODE_MASK = 3 shl _VFP_ROUNDINGMODE_MASK_SHIFT;
  131. _VFP_EXCEPTIONS_PENDING_MASK =
  132. (1 shl 0) or
  133. (1 shl 1) or
  134. (1 shl 2) or
  135. (1 shl 3) or
  136. (1 shl 4) or
  137. (1 shl 7);
  138. function VFP_GetCW : dword; nostackframe; assembler;
  139. asm
  140. fmrx r0,fpscr
  141. end;
  142. procedure VFP_SetCW(cw : dword); nostackframe; assembler;
  143. asm
  144. fmxr fpscr,r0
  145. end;
  146. function GetRoundMode: TFPURoundingMode;
  147. var
  148. rm: byte;
  149. begin
  150. case (VFP_GetCW and _VFP_ROUNDINGMODE_MASK) shr _VFP_ROUNDINGMODE_MASK_SHIFT of
  151. 0 : result := rmNearest;
  152. 1 : result := rmUp;
  153. 2 : result := rmDown;
  154. 3 : result := rmTruncate;
  155. end;
  156. end;
  157. function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
  158. var
  159. mode: dword;
  160. begin
  161. softfloat_rounding_mode:=RoundMode;
  162. case (RoundMode) of
  163. rmNearest :
  164. begin
  165. mode := 0;
  166. end;
  167. rmUp :
  168. begin
  169. mode := 1;
  170. end;
  171. rmDown :
  172. begin
  173. mode := 2;
  174. end;
  175. rmTruncate :
  176. begin
  177. mode := 3;
  178. end;
  179. end;
  180. mode:=mode shl _VFP_ROUNDINGMODE_MASK_SHIFT;
  181. VFP_SetCW((VFP_GetCW and (not _VFP_ROUNDINGMODE_MASK)) or mode);
  182. result := RoundMode;
  183. end;
  184. function GetPrecisionMode: TFPUPrecisionMode;
  185. begin
  186. result := pmDouble;
  187. end;
  188. function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode;
  189. begin
  190. { nothing to do, not supported }
  191. result := pmDouble;
  192. end;
  193. function GetExceptionMask: TFPUExceptionMask;
  194. var
  195. cw : dword;
  196. begin
  197. Result:=[];
  198. cw:=VFP_GetCW;
  199. if (cw and _VFP_ENABLE_IM)=0 then
  200. include(Result,exInvalidOp);
  201. if (cw and _VFP_ENABLE_DM)=0 then
  202. include(Result,exDenormalized);
  203. if (cw and _VFP_ENABLE_ZM)=0 then
  204. include(Result,exZeroDivide);
  205. if (cw and _VFP_ENABLE_OM)=0 then
  206. include(Result,exOverflow);
  207. if (cw and _VFP_ENABLE_UM)=0 then
  208. include(Result,exUnderflow);
  209. if (cw and _VFP_ENABLE_PM)=0 then
  210. include(Result,exPrecision);
  211. end;
  212. function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
  213. var
  214. cw : dword;
  215. begin
  216. cw:=VFP_GetCW and not(_VFP_ENABLE_ALL);
  217. {$ifndef darwin}
  218. if not(exInvalidOp in Mask) then
  219. cw:=cw or _VFP_ENABLE_IM;
  220. if not(exDenormalized in Mask) then
  221. cw:=cw or _VFP_ENABLE_DM;
  222. if not(exZeroDivide in Mask) then
  223. cw:=cw or _VFP_ENABLE_ZM;
  224. if not(exOverflow in Mask) then
  225. cw:=cw or _VFP_ENABLE_OM;
  226. if not(exUnderflow in Mask) then
  227. cw:=cw or _VFP_ENABLE_UM;
  228. if not(exPrecision in Mask) then
  229. cw:=cw or _VFP_ENABLE_PM;
  230. {$endif}
  231. VFP_SetCW(cw);
  232. result:=Mask;
  233. softfloat_exception_mask:=Mask;
  234. end;
  235. procedure ClearExceptions(RaisePending: Boolean =true);
  236. begin
  237. { RaisePending has no effect on ARM, it always raises them at the correct location }
  238. VFP_SetCW(VFP_GetCW and (not _VFP_EXCEPTIONS_PENDING_MASK));
  239. end;
  240. {$else wince/darwin/vfpv2/vfpv3}
  241. {*****************************************************************************
  242. FPA code
  243. *****************************************************************************}
  244. {
  245. Docs from uclib
  246. * We have a slight terminology confusion here. On the ARM, the register
  247. * we're interested in is actually the FPU status word - the FPU control
  248. * word is something different (which is implementation-defined and only
  249. * accessible from supervisor mode.)
  250. *
  251. * The FPSR looks like this:
  252. *
  253. * 31-24 23-16 15-8 7-0
  254. * | system ID | trap enable | system control | exception flags |
  255. *
  256. * We ignore the system ID bits; for interest's sake they are:
  257. *
  258. * 0000 "old" FPE
  259. * 1000 FPPC hardware
  260. * 0001 FPE 400
  261. * 1001 FPA hardware
  262. *
  263. * The trap enable and exception flags are both structured like this:
  264. *
  265. * 7 - 5 4 3 2 1 0
  266. * | reserved | INX | UFL | OFL | DVZ | IVO |
  267. *
  268. * where a `1' bit in the enable byte means that the trap can occur, and
  269. * a `1' bit in the flags byte means the exception has occurred.
  270. *
  271. * The exceptions are:
  272. *
  273. * IVO - invalid operation
  274. * DVZ - divide by zero
  275. * OFL - overflow
  276. * UFL - underflow
  277. * INX - inexact (do not use; implementations differ)
  278. *
  279. * The system control byte looks like this:
  280. *
  281. * 7-5 4 3 2 1 0
  282. * | reserved | AC | EP | SO | NE | ND |
  283. *
  284. * where the bits mean
  285. *
  286. * ND - no denormalised numbers (force them all to zero)
  287. * NE - enable NaN exceptions
  288. * SO - synchronous operation
  289. * EP - use expanded packed-decimal format
  290. * AC - use alternate definition for C flag on compare operations
  291. */
  292. /* masking of interrupts */
  293. #define _FPU_MASK_IM 0x00010000 /* invalid operation */
  294. #define _FPU_MASK_ZM 0x00020000 /* divide by zero */
  295. #define _FPU_MASK_OM 0x00040000 /* overflow */
  296. #define _FPU_MASK_UM 0x00080000 /* underflow */
  297. #define _FPU_MASK_PM 0x00100000 /* inexact */
  298. #define _FPU_MASK_DM 0x00000000 /* denormalized operation */
  299. /* The system id bytes cannot be changed.
  300. Only the bottom 5 bits in the trap enable byte can be changed.
  301. Only the bottom 5 bits in the system control byte can be changed.
  302. Only the bottom 5 bits in the exception flags are used.
  303. The exception flags are set by the fpu, but can be zeroed by the user. */
  304. #define _FPU_RESERVED 0xffe0e0e0 /* These bits are reserved. */
  305. /* The fdlibm code requires strict IEEE double precision arithmetic,
  306. no interrupts for exceptions, rounding to nearest. Changing the
  307. rounding mode will break long double I/O. Turn on the AC bit,
  308. the compiler generates code that assumes it is on. */
  309. #define _FPU_DEFAULT 0x00001000 /* Default value. */
  310. #define _FPU_IEEE 0x001f1000 /* Default + exceptions enabled. */
  311. }
  312. {$if not(defined(gba)) and not(defined(nds)) and not(defined(FPUSOFT)) and not(defined(FPULIBGCC))}
  313. const
  314. _FPU_MASK_IM = $00010000; { invalid operation }
  315. _FPU_MASK_ZM = $00020000; { divide by zero }
  316. _FPU_MASK_OM = $00040000; { overflow }
  317. _FPU_MASK_UM = $00080000; { underflow }
  318. _FPU_MASK_PM = $00100000; { inexact }
  319. _FPU_MASK_DM = $00000000; { denormalized operation }
  320. _FPU_MASK_ALL = $001f0000; { mask for all flags }
  321. function FPU_GetCW : dword; nostackframe; assembler;
  322. asm
  323. rfs r0
  324. end;
  325. procedure FPU_SetCW(cw : dword); nostackframe; assembler;
  326. asm
  327. wfs r0
  328. end;
  329. {$endif}
  330. function GetRoundMode: TFPURoundingMode;
  331. begin
  332. GetRoundMode:=softfloat_rounding_mode;
  333. end;
  334. function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
  335. begin
  336. softfloat_rounding_mode:=RoundMode;
  337. SetRoundMode:=RoundMode;
  338. end;
  339. function GetPrecisionMode: TFPUPrecisionMode;
  340. begin
  341. result := pmDouble;
  342. end;
  343. function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode;
  344. begin
  345. { does not apply }
  346. result := pmDouble;
  347. end;
  348. function GetExceptionMask: TFPUExceptionMask;
  349. var
  350. cw : dword;
  351. begin
  352. {$if not(defined(gba)) and not(defined(nds)) and not(defined(FPUSOFT)) and not(defined(FPULIBGCC))}
  353. Result:=[];
  354. cw:=FPU_GetCW;
  355. if (cw and _FPU_MASK_IM)=0 then
  356. include(Result,exInvalidOp);
  357. if (cw and _FPU_MASK_DM)=0 then
  358. include(Result,exDenormalized);
  359. if (cw and _FPU_MASK_ZM)=0 then
  360. include(Result,exZeroDivide);
  361. if (cw and _FPU_MASK_OM)=0 then
  362. include(Result,exOverflow);
  363. if (cw and _FPU_MASK_UM)=0 then
  364. include(Result,exUnderflow);
  365. if (cw and _FPU_MASK_PM)=0 then
  366. include(Result,exPrecision);
  367. {$else}
  368. Result:=softfloat_exception_mask;
  369. {$endif}
  370. end;
  371. function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
  372. var
  373. cw : dword;
  374. begin
  375. {$if not(defined(gba)) and not(defined(nds)) and not(defined(FPUSOFT)) and not(defined(FPULIBGCC))}
  376. cw:=FPU_GetCW or _FPU_MASK_ALL;
  377. if exInvalidOp in Mask then
  378. cw:=cw and not(_FPU_MASK_IM);
  379. if exDenormalized in Mask then
  380. cw:=cw and not(_FPU_MASK_DM);
  381. if exZeroDivide in Mask then
  382. cw:=cw and not(_FPU_MASK_ZM);
  383. if exOverflow in Mask then
  384. cw:=cw and not(_FPU_MASK_OM);
  385. if exUnderflow in Mask then
  386. cw:=cw and not(_FPU_MASK_UM);
  387. if exPrecision in Mask then
  388. cw:=cw and not(_FPU_MASK_PM);
  389. FPU_SetCW(cw);
  390. {$endif}
  391. softfloat_exception_mask:=Mask;
  392. Result:=Mask;
  393. end;
  394. procedure ClearExceptions(RaisePending: Boolean =true);
  395. begin
  396. end;
  397. {$endif wince}