mathu.inc 13 KB

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