mathu.inc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2014 by Jonas Maebe
  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. {$asmmode gas}
  12. function getfpsr: qword; nostackframe; assembler;
  13. asm
  14. mrs x0,fpsr
  15. end;
  16. procedure setfpsr(val: qword); nostackframe; assembler;
  17. asm
  18. msr fpsr, x0
  19. end;
  20. function GetRoundMode: TFPURoundingMode;
  21. const
  22. bits2rm: array[0..3] of TFPURoundingMode = (rmNearest,rmUp,rmDown,rmTruncate);
  23. begin
  24. result:=TFPURoundingMode(bits2rm[(GetNativeFPUControlWord shr 22) and 3])
  25. end;
  26. function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
  27. const
  28. rm2bits: array[TFPURoundingMode] of byte = (0,2,1,3);
  29. begin
  30. softfloat_rounding_mode:=RoundMode;
  31. SetRoundMode:=GetRoundMode;
  32. SetNativeFPUControlWord((GetNativeFPUControlWord and $ff3fffff) or (rm2bits[RoundMode] shl 22));
  33. end;
  34. function GetPrecisionMode: TFPUPrecisionMode;
  35. begin
  36. result:=pmDouble;
  37. end;
  38. function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode;
  39. begin
  40. result:=pmDouble;
  41. end;
  42. const
  43. fpu_ioe = 1 shl 8;
  44. fpu_dze = 1 shl 9;
  45. fpu_ofe = 1 shl 10;
  46. fpu_ufe = 1 shl 11;
  47. fpu_ixe = 1 shl 12;
  48. fpu_ide = 1 shl 15;
  49. fpu_exception_mask = qword(fpu_ioe or fpu_dze or fpu_ofe or fpu_ufe or fpu_ixe or fpu_ide);
  50. fpu_exception_mask_to_status_mask_shift = 8;
  51. function GetExceptionMask: TFPUExceptionMask;
  52. {
  53. var
  54. fpcr: dword;
  55. }
  56. begin
  57. { as I am not aware of any hardware exception supporting AArch64 implementation,
  58. and else the trapping enable flags are RAZ, return the softfloat exception mask (FK)
  59. fpcr:=getfpcr;
  60. result:=[];
  61. if ((fpcr and fpu_ioe)=0) then
  62. result := result+[exInvalidOp];
  63. if ((fpcr and fpu_ofe)=0) then
  64. result := result+[exOverflow];
  65. if ((fpcr and fpu_ufe)=0) then
  66. result := result+[exUnderflow];
  67. if ((fpcr and fpu_dze)=0) then
  68. result := result+[exZeroDivide];
  69. if ((fpcr and fpu_ixe)=0) then
  70. result := result+[exPrecision];
  71. if ((fpcr and fpu_ide)=0) then
  72. result := result+[exDenormalized];
  73. }
  74. { as the fpcr flags might be RAZ, the softfloat exception mask
  75. is considered as the authoritative mask }
  76. result:=softfloat_exception_mask;
  77. end;
  78. function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
  79. var
  80. newfpcr: qword;
  81. old_softfloat_exception_mask: TFPUExceptionMask;
  82. begin
  83. { clear "exception happened" flags }
  84. ClearExceptions(false);
  85. { as the fpcr flags might be RAZ, the softfloat exception mask
  86. is considered as the authoritative mask }
  87. result:=softfloat_exception_mask;
  88. softfloat_exception_mask:=mask;
  89. { at least the ThunderX AArch64 support apparently hardware exceptions,
  90. so set fpcr correctly, thought it might be WI on most implementations it does not hurt
  91. }
  92. newfpcr:=fpu_exception_mask;
  93. if exInvalidOp in Mask then
  94. newfpcr:=newfpcr and not(fpu_ioe);
  95. if exOverflow in Mask then
  96. newfpcr:=newfpcr and not(fpu_ofe);
  97. if exUnderflow in Mask then
  98. newfpcr:=newfpcr and not(fpu_ufe);
  99. if exZeroDivide in Mask then
  100. newfpcr:=newfpcr and not(fpu_dze);
  101. if exPrecision in Mask then
  102. newfpcr:=newfpcr and not(fpu_ixe);
  103. if exDenormalized in Mask then
  104. newfpcr:=newfpcr and not(fpu_ide);
  105. SetNativeFPUControlWord((GetNativeFPUControlWord and not(fpu_exception_mask)) or newfpcr);
  106. end;
  107. procedure ClearExceptions(RaisePending: Boolean);
  108. var
  109. fpsr: qword;
  110. f: TFPUException;
  111. begin
  112. fpsr:=getfpsr;
  113. if raisepending then
  114. begin
  115. if (fpsr and (fpu_dze shr fpu_exception_mask_to_status_mask_shift)) <> 0 then
  116. float_raise(exZeroDivide);
  117. if (fpsr and (fpu_ofe shr fpu_exception_mask_to_status_mask_shift)) <> 0 then
  118. float_raise(exOverflow);
  119. if (fpsr and (fpu_ufe shr fpu_exception_mask_to_status_mask_shift)) <> 0 then
  120. float_raise(exUnderflow);
  121. if (fpsr and (fpu_ioe shr fpu_exception_mask_to_status_mask_shift)) <> 0 then
  122. float_raise(exInvalidOp);
  123. if (fpsr and (fpu_ixe shr fpu_exception_mask_to_status_mask_shift)) <> 0 then
  124. float_raise(exPrecision);
  125. if (fpsr and (fpu_ide shr fpu_exception_mask_to_status_mask_shift)) <> 0 then
  126. float_raise(exDenormalized);
  127. { now the soft float exceptions }
  128. for f in softfloat_exception_flags do
  129. float_raise(f);
  130. end;
  131. softfloat_exception_flags:=[];
  132. setfpsr(fpsr and not(fpu_exception_mask shr fpu_exception_mask_to_status_mask_shift));
  133. end;