mathu.inc 15 KB

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