Browse Source

FPU exception mask: generlised system unit interface

Jonas Maebe 2 years ago
parent
commit
0758aa1143
63 changed files with 1013 additions and 856 deletions
  1. 25 20
      rtl/aarch64/aarch64.inc
  2. 3 0
      rtl/aarch64/cpuh.inc
  3. 7 19
      rtl/aarch64/mathu.inc
  4. 0 13
      rtl/aix/system.pp
  5. 75 34
      rtl/arm/arm.inc
  6. 3 0
      rtl/arm/cpuh.inc
  7. 5 17
      rtl/arm/mathu.inc
  8. 0 8
      rtl/arm/thumb.inc
  9. 15 13
      rtl/arm/thumb2.inc
  10. 1 1
      rtl/avr/avr.inc
  11. 5 0
      rtl/i386/cpuh.inc
  12. 1 0
      rtl/i386/i386.inc
  13. 18 0
      rtl/i386/math.inc
  14. 3 0
      rtl/i8086/cpuh.inc
  15. 1 0
      rtl/i8086/i8086.inc
  16. 12 0
      rtl/i8086/math.inc
  17. 9 18
      rtl/inc/dynlib.inc
  18. 20 0
      rtl/inc/generic.inc
  19. 18 1
      rtl/inc/mathh.inc
  20. 30 0
      rtl/inc/system.inc
  21. 0 1
      rtl/inc/thread.inc
  22. 15 0
      rtl/java/jsystem.inc
  23. 3 0
      rtl/java/jsystemh.inc
  24. 2 0
      rtl/jvm/cpuh.inc
  25. 0 8
      rtl/jvm/jvm.inc
  26. 1 1
      rtl/linux/powerpc/sighnd.inc
  27. 1 1
      rtl/linux/powerpc64/sighnd.inc
  28. 2 0
      rtl/m68k/cpuh.inc
  29. 21 24
      rtl/m68k/m68k.inc
  30. 3 0
      rtl/mips/cpuh.inc
  31. 10 14
      rtl/mips/mathu.inc
  32. 21 19
      rtl/mips/mips.inc
  33. 3 0
      rtl/mips64/cpuh.inc
  34. 9 0
      rtl/powerpc/cpuh.inc
  35. 1 205
      rtl/powerpc/mathu.inc
  36. 2 85
      rtl/powerpc/powerpc.inc
  37. 10 0
      rtl/powerpc64/cpuh.inc
  38. 1 213
      rtl/powerpc64/mathu.inc
  39. 2 26
      rtl/powerpc64/powerpc64.inc
  40. 170 0
      rtl/ppcgen/ppcfpuex.inc
  41. 186 0
      rtl/ppcgen/ppcmathu.inc
  42. 39 7
      rtl/riscv/riscv.inc
  43. 10 0
      rtl/riscv32/cpuh.inc
  44. 20 0
      rtl/riscv32/riscv32.inc
  45. 10 0
      rtl/riscv64/cpuh.inc
  46. 12 28
      rtl/riscv64/mathu.inc
  47. 20 0
      rtl/riscv64/riscv64.inc
  48. 3 0
      rtl/sparc/cpuh.inc
  49. 10 15
      rtl/sparc/mathu.inc
  50. 20 20
      rtl/sparc/sparc.inc
  51. 2 0
      rtl/sparc64/cpuh.inc
  52. 10 14
      rtl/sparc64/mathu.inc
  53. 20 20
      rtl/sparc64/sparc64.inc
  54. 2 0
      rtl/wasm32/cpuh.inc
  55. 1 0
      rtl/wasm32/wasm32.inc
  56. 6 0
      rtl/x86_64/cpuh.inc
  57. 18 4
      rtl/x86_64/math.inc
  58. 1 0
      rtl/x86_64/x86_64.inc
  59. 3 0
      rtl/xtensa/cpuh.inc
  60. 3 7
      rtl/xtensa/xtensa.inc
  61. 4 0
      rtl/z80/cpuh.inc
  62. 1 0
      rtl/z80/z80.inc
  63. 84 0
      tests/webtbs/tw38230.pp

+ 25 - 20
rtl/aarch64/aarch64.inc

@@ -39,9 +39,18 @@ function getfpcr: qword; nostackframe; assembler;
   end;
   end;
 
 
 
 
-procedure setfpcr(val: qword); nostackframe; assembler;
-  asm
-    msr fpcr,x0
+procedure setfpcr(val: qword);
+  begin
+    asm
+      ldr x0,val
+      msr fpcr,x0
+{$if not defined(darwin) or defined(ios) or defined(watchos) or defined(tvos)}
+      // read back the fpcr because on several (non-macOS) platforms it's raz
+      mrs x0,fpcr
+      str x0, val
+{$endif}
+    end;
+    DefaultFPUControlWord:=val;
   end;
   end;
 
 
 
 
@@ -51,6 +60,18 @@ function getfpsr: qword; nostackframe; assembler;
   end;
   end;
 
 
 
 
+function GetNativeFPUControlWord: TNativeFPUControlWord;
+  begin
+    result:=getfpcr;
+  end;
+
+
+procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord);
+  begin
+    setfpcr(cw);
+  end;
+
+
 procedure setfpsr(val: qword); nostackframe; assembler;
 procedure setfpsr(val: qword); nostackframe; assembler;
   asm
   asm
     msr fpsr, x0
     msr fpsr, x0
@@ -129,29 +150,13 @@ procedure SysInitFPU;
     setfpcr(getfpcr and $ff3fffff);
     setfpcr(getfpcr and $ff3fffff);
     { clear all "exception happened" flags we care about}
     { clear all "exception happened" flags we care about}
     setfpsr(getfpsr and not(fpu_exception_mask shr fpu_exception_mask_to_status_mask_shift));
     setfpsr(getfpsr and not(fpu_exception_mask shr fpu_exception_mask_to_status_mask_shift));
-    { enable invalid operations and division by zero exceptions. }
+    { enable invalid operations, overflow and division by zero exceptions. }
     setfpcr(((getfpcr and not(fpu_exception_mask)) or fpu_dze or fpu_ofe or fpu_ioe));
     setfpcr(((getfpcr and not(fpu_exception_mask)) or fpu_dze or fpu_ofe or fpu_ioe));
     softfloat_exception_mask:=[float_flag_underflow,float_flag_inexact,float_flag_denormal];
     softfloat_exception_mask:=[float_flag_underflow,float_flag_inexact,float_flag_denormal];
     softfloat_exception_flags:=[];
     softfloat_exception_flags:=[];
   end;
   end;
 
 
 
 
-{$define FPC_SYSTEM_HAS_SYSRESETFPU}
-Procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
-begin
-  softfloat_exception_flags:=[];
-  setfpsr(getfpsr and not(FPSR_EXCEPTIONS));
-end;
-
-
-procedure fpc_cpuinit;
-  begin
-    { don't let libraries influence the FPU cw set by the host program }
-    if not IsLibrary then
-      SysInitFPU;
-  end;
-
-
 {****************************************************************************
 {****************************************************************************
                                 Move / Fill
                                 Move / Fill
 ****************************************************************************}
 ****************************************************************************}

+ 3 - 0
rtl/aarch64/cpuh.inc

@@ -13,3 +13,6 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 
  **********************************************************************}
  **********************************************************************}
+
+type
+  TNativeFPUControlWord = qword;

+ 7 - 19
rtl/aarch64/mathu.inc

@@ -14,18 +14,6 @@
 
 
 {$asmmode gas}
 {$asmmode gas}
 
 
-function getfpcr: qword; nostackframe; assembler;
-  asm
-    mrs x0,fpcr
-  end;
-
-
-procedure setfpcr(val: qword); nostackframe; assembler;
-  asm
-    msr fpcr,x0
-  end;
-
-
 function getfpsr: qword; nostackframe; assembler;
 function getfpsr: qword; nostackframe; assembler;
   asm
   asm
     mrs x0,fpsr
     mrs x0,fpsr
@@ -42,7 +30,7 @@ function GetRoundMode: TFPURoundingMode;
   const
   const
     bits2rm: array[0..3] of TFPURoundingMode = (rmNearest,rmUp,rmDown,rmTruncate);
     bits2rm: array[0..3] of TFPURoundingMode = (rmNearest,rmUp,rmDown,rmTruncate);
   begin
   begin
-    result:=TFPURoundingMode(bits2rm[(getfpcr shr 22) and 3])
+    result:=TFPURoundingMode(bits2rm[(GetNativeFPUControlWord shr 22) and 3])
   end;
   end;
 
 
 
 
@@ -52,7 +40,7 @@ function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
   begin
   begin
     softfloat_rounding_mode:=RoundMode;
     softfloat_rounding_mode:=RoundMode;
     SetRoundMode:=GetRoundMode;
     SetRoundMode:=GetRoundMode;
-    setfpcr((getfpcr and $ff3fffff) or (rm2bits[RoundMode] shl 22));
+    SetNativeFPUControlWord((GetNativeFPUControlWord and $ff3fffff) or (rm2bits[RoundMode] shl 22));
   end;
   end;
 
 
 
 
@@ -112,9 +100,13 @@ function GetExceptionMask: TFPUExceptionMask;
 function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
 function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
   var
   var
     newfpcr: qword;
     newfpcr: qword;
+    old_softfloat_exception_mask: TFPUExceptionMask;
   begin
   begin
     { clear "exception happened" flags }
     { clear "exception happened" flags }
     ClearExceptions(false);
     ClearExceptions(false);
+    { as the fpcr flags might be RAZ, the softfloat exception mask
+      is considered as the authoritative mask }
+    result:=softfloat_exception_mask;
     softfloat_exception_mask:=mask;
     softfloat_exception_mask:=mask;
 
 
     { at least the ThunderX AArch64 support apparently hardware exceptions,
     { at least the ThunderX AArch64 support apparently hardware exceptions,
@@ -133,11 +125,7 @@ function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
       newfpcr:=newfpcr and not(fpu_ixe);
       newfpcr:=newfpcr and not(fpu_ixe);
     if exDenormalized in Mask then
     if exDenormalized in Mask then
       newfpcr:=newfpcr and not(fpu_ide);
       newfpcr:=newfpcr and not(fpu_ide);
-    setfpcr((getfpcr and not(fpu_exception_mask)) or newfpcr);
-
-    { as the fpcr flags might be RAZ, the softfloat exception mask
-      is considered as the authoritative mask }
-    result:=softfloat_exception_mask;
+    SetNativeFPUControlWord((GetNativeFPUControlWord and not(fpu_exception_mask)) or newfpcr);
   end;
   end;
 
 
 
 

+ 0 - 13
rtl/aix/system.pp

@@ -238,25 +238,12 @@ end;
 
 
 
 
 const
 const
-  FP_TRAP_SYNC = 1;                { precise fpu exceptions }
-  FP_TRAP_OFF = 0;                 { disable fpu exceptions }
-  FP_TRAP_QUERY = 2;               { current fpu exception state }
-  FP_TRAP_IMP = 3;                 { imprecise non-recoverable fpu exceptions }
-  FP_TRAP_IMP_REC = 4;             { imprecise recoverable fpu exceptions }
-  FP_TRAP_FASTMODE = 128;          { fastest fpu exception state }
-  FP_TRAP_ERROR = -1;
-  FP_TRAP_UNIMPL = -2;
-
   TRP_INVALID     = $00000080;
   TRP_INVALID     = $00000080;
   TRP_OVERFLOW    = $00000040;
   TRP_OVERFLOW    = $00000040;
   TRP_UNDERFLOW   = $00000020;
   TRP_UNDERFLOW   = $00000020;
   TRP_DIV_BY_ZERO = $00000010;
   TRP_DIV_BY_ZERO = $00000010;
   TRP_INEXACT     = $00000008;
   TRP_INEXACT     = $00000008;
 
 
-
-function fp_trap(flag: longint): longint; cdecl; external;
-procedure fp_enable(Mask: DWord);cdecl;external;
-
 Begin
 Begin
   IsConsole := TRUE;
   IsConsole := TRUE;
   StackLength := CheckInitialStkLen(InitialStkLen);
   StackLength := CheckInitialStkLen(InitialStkLen);

+ 75 - 34
rtl/arm/arm.inc

@@ -44,16 +44,30 @@ const
 {$endif}
 {$endif}
 
 
 {$if defined(FPUARM_HAS_FPA)}
 {$if defined(FPUARM_HAS_FPA)}
-Procedure SysInitFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
+{$define FPC_SYSTEM_HAS_GETSETNATIVEFPUCONTROLWORD}
+function GetNativeFPUControlWord: TNativeFPUControlWord; assembler;
+asm
+  rfs r0
+end;
+
+
+procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord);
 begin
 begin
-  { Enable FPU exceptions, but disable INEXACT, UNDERFLOW, DENORMAL }
+  DefaultFPUControlWord:=cw;
   asm
   asm
-    rfs r0
-    and r0,r0,#0xffe0ffff
-    orr r0,r0,#0x00070000
+    ldr r0, cw
     wfs r0
     wfs r0
   end;
   end;
 end;
 end;
+
+Procedure SysInitFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
+begin
+  { Enable FPU exceptions, but disable INEXACT, UNDERFLOW, DENORMAL }
+  SetNativeFPUControlWord((GetNativeFPUControlWord and $ffe0ffff) or $00070000);
+  softfloat_exception_mask:=[float_flag_underflow,float_flag_inexact,float_flag_denormal];
+  softfloat_exception_flags:=[];
+end;
+
 {$elseif defined(FPUARM_HAS_VFP_EXTENSION)}
 {$elseif defined(FPUARM_HAS_VFP_EXTENSION)}
 
 
 
 
@@ -64,26 +78,41 @@ const
   fpu_dz = 1 shl 3;
   fpu_dz = 1 shl 3;
   fpu_nv = 1 shl 4;
   fpu_nv = 1 shl 4;
 
 
-function getfpscr: sizeuint; nostackframe; assembler;
+  FPSCR_IOC = 1;
+  FPSCR_DZC = 1 shl 1;
+  FPSCR_OFC = 1 shl 2;
+  FPSCR_UFC = 1 shl 3;
+  FPSCR_IXC = 1 shl 4;
+  FPSCR_IDC = 1 shl 7;
+  FPSCR_EXCEPTIONS = FPSCR_IOC or FPSCR_DZC or FPSCR_OFC or FPSCR_UFC or FPSCR_IXC or FPSCR_IDC;
+
+function getfpscr: sizeuint; nostackframe; assembler; nostackframe;
   asm
   asm
     fmrx r0,fpscr
     fmrx r0,fpscr
   end;
   end;
 
 
 
 
-procedure setfpscr(flags : sizeuint); nostackframe; assembler;
-  asm
-    fmxr fpscr,r0
+procedure setfpscr(flags : sizeuint);
+  begin
+    DefaultFPUControlWord:=flags and not(FPSCR_EXCEPTIONS);
+    asm
+      ldr r0, flags
+      fmxr fpscr,r0
+    end;
   end;
   end;
 
 
+{$define FPC_SYSTEM_HAS_GETSETNATIVEFPUCONTROLWORD}
+function GetNativeFPUControlWord: TNativeFPUControlWord; {$if defined(SYSTEMINLINE)}inline;{$endif}
+  begin
+    result:=getfpscr;
+  end;
+
+
+procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord); {$if defined(SYSTEMINLINE)}inline;{$endif}
+  begin
+    setfpscr(cw);
+  end;
 
 
-const
-  FPSCR_IOC = 1;
-  FPSCR_DZC = 1 shl 1;
-  FPSCR_OFC = 1 shl 2;
-  FPSCR_UFC = 1 shl 3;
-  FPSCR_IXC = 1 shl 4;
-  FPSCR_IDC = 1 shl 7;
-  FPSCR_EXCEPTIONS = FPSCR_IOC or FPSCR_DZC or FPSCR_OFC or FPSCR_UFC or FPSCR_IXC or FPSCR_IDC;
 
 
 procedure RaisePendingExceptions;
 procedure RaisePendingExceptions;
   var
   var
@@ -165,23 +194,8 @@ begin
   softfloat_exception_flags:=[];
   softfloat_exception_flags:=[];
 end;
 end;
 
 
-{$define FPC_SYSTEM_HAS_SYSRESETFPU}
-Procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
-begin
-  softfloat_exception_flags:=[];
-  setfpscr(getfpscr and not(FPSCR_EXCEPTIONS));
-end;
-
-
-{$endif}
-{$endif}
-
-procedure fpc_cpuinit;
-begin
-  { don't let libraries influence the FPU cw set by the host program }
-  if not IsLibrary then
-    SysInitFPU;
-end;
+{$endif defined(FPUARM_HAS_VFP_EXTENSION)}
+{$endif not(defined(wince)) and not(defined(gba)) and not(defined(nds)) and not(defined(FPUSOFT)) and not(defined(FPULIBGCC))}
 
 
 {$ifdef wince}
 {$ifdef wince}
 function _controlfp(new: DWORD; mask: DWORD): DWORD; cdecl; external 'coredll';
 function _controlfp(new: DWORD; mask: DWORD): DWORD; cdecl; external 'coredll';
@@ -189,6 +203,7 @@ function _controlfp(new: DWORD; mask: DWORD): DWORD; cdecl; external 'coredll';
 {$define FPC_SYSTEM_HAS_SYSRESETFPU}
 {$define FPC_SYSTEM_HAS_SYSRESETFPU}
 Procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
 Procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
 begin
 begin
+  softfloat_exception_flags:=[];
 end;
 end;
 
 
 {$define FPC_SYSTEM_HAS_SYSINITFPU}
 {$define FPC_SYSTEM_HAS_SYSINITFPU}
@@ -197,9 +212,35 @@ begin
   { Enable FPU exceptions, but disable INEXACT, UNDERFLOW, DENORMAL }
   { Enable FPU exceptions, but disable INEXACT, UNDERFLOW, DENORMAL }
   { FPU precision 64 bit, rounding to nearest, affine infinity }
   { FPU precision 64 bit, rounding to nearest, affine infinity }
   _controlfp($000C0003, $030F031F);
   _controlfp($000C0003, $030F031F);
+  softfloat_exception_mask:=[float_flag_underflow,float_flag_inexact,float_flag_denormal];
+  softfloat_exception_flags:=[];
 end;
 end;
+
+{$define FPC_SYSTEM_HAS_GETSETNATIVEFPUCONTROLWORD}
+function GetNativeFPUControlWord: TNativeFPUControlWord;
+  begin
+    result:=_controlfp(0,0);
+  end;
+
+procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord);
+  begin
+    _controlfp(cw,$ffffffff);
+  end;
+
 {$endif wince}
 {$endif wince}
 
 
+{$ifndef FPC_SYSTEM_HAS_GETSETNATIVEFPUCONTROLWORD}
+{$define FPC_SYSTEM_HAS_GETSETNATIVEFPUCONTROLWORD}
+function GetNativeFPUControlWord: TNativeFPUControlWord; {$if defined(SYSTEMINLINE)}inline;{$endif}
+  begin
+    result:=0;
+  end;
+
+procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord); {$if defined(SYSTEMINLINE)}inline;{$endif}
+  begin
+  end;
+{$endif}
+
 {$ifdef linux}
 {$ifdef linux}
 function fpc_read_tp : pointer; [public, alias: 'fpc_read_tp'];assembler; nostackframe;
 function fpc_read_tp : pointer; [public, alias: 'fpc_read_tp'];assembler; nostackframe;
 asm
 asm

+ 3 - 0
rtl/arm/cpuh.inc

@@ -13,3 +13,6 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 
  **********************************************************************}
  **********************************************************************}
+
+type
+  TNativeFPUControlWord = dword;

+ 5 - 17
rtl/arm/mathu.inc

@@ -388,19 +388,7 @@ const
   _FPU_MASK_DM  =  $00000000;      { denormalized operation }
   _FPU_MASK_DM  =  $00000000;      { denormalized operation }
   _FPU_MASK_ALL =  $001f0000;      { mask for all flags     }
   _FPU_MASK_ALL =  $001f0000;      { mask for all flags     }
 
 
-function FPU_GetCW : dword; nostackframe; assembler;
-  asm
-    rfs r0
-  end;
-
-
-procedure FPU_SetCW(cw : dword); nostackframe; assembler;
-  asm
-    wfs r0
-  end;
-
-
-function FPUCw2ExceptionMask(cw: dword): TFPUExceptionMask;
+function FPUCw2ExceptionMask(cw: TNativeFPUControlWord): TFPUExceptionMask;
   begin
   begin
     Result:=[];
     Result:=[];
 
 
@@ -454,7 +442,7 @@ function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode
 function GetExceptionMask: TFPUExceptionMask;
 function GetExceptionMask: TFPUExceptionMask;
   begin
   begin
 {$if not(defined(gba)) and not(defined(nds)) and not(defined(FPUSOFT)) and not(defined(FPULIBGCC))}
 {$if not(defined(gba)) and not(defined(nds)) and not(defined(FPUSOFT)) and not(defined(FPULIBGCC))}
-    Result:=FPUCw2ExceptionMask(FPU_GetCW);
+    Result:=FPUCw2ExceptionMask(GetNativeFPUControlWord);
 {$else}
 {$else}
     Result:=softfloat_exception_mask;
     Result:=softfloat_exception_mask;
 {$endif}
 {$endif}
@@ -464,11 +452,11 @@ function GetExceptionMask: TFPUExceptionMask;
 function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
 function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
 {$if not(defined(gba)) and not(defined(nds)) and not(defined(FPUSOFT)) and not(defined(FPULIBGCC))}
 {$if not(defined(gba)) and not(defined(nds)) and not(defined(FPUSOFT)) and not(defined(FPULIBGCC))}
   var
   var
-    cw : dword;
+    cw : TNativeFPUControlWord;
 {$endif}
 {$endif}
   begin
   begin
 {$if not(defined(gba)) and not(defined(nds)) and not(defined(FPUSOFT)) and not(defined(FPULIBGCC))}
 {$if not(defined(gba)) and not(defined(nds)) and not(defined(FPUSOFT)) and not(defined(FPULIBGCC))}
-    cw:=FPU_GetCW;
+    cw:=GetNativeFPUControlWord;
     Result:=FPUCw2ExceptionMask(cw);
     Result:=FPUCw2ExceptionMask(cw);
     cw:=cw or _FPU_MASK_ALL;
     cw:=cw or _FPU_MASK_ALL;
 
 
@@ -490,7 +478,7 @@ function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
     if exPrecision in Mask then
     if exPrecision in Mask then
       cw:=cw and not(_FPU_MASK_PM);
       cw:=cw and not(_FPU_MASK_PM);
 
 
-    FPU_SetCW(cw);
+    SetNativeFPUControlWord(cw);
 {$else}
 {$else}
     Result:=softfloat_exception_mask;
     Result:=softfloat_exception_mask;
 {$endif}
 {$endif}

+ 0 - 8
rtl/arm/thumb.inc

@@ -25,14 +25,6 @@ begin
 end;
 end;
 
 
 
 
-procedure fpc_cpuinit;
-begin
-{$ifndef FPUNONE}
-  SysInitFPU;
-{$endif FPUNONE}
-end;
-
-
 procedure fpc_cpucodeinit;
 procedure fpc_cpucodeinit;
 begin
 begin
 end;
 end;

+ 15 - 13
rtl/arm/thumb2.inc

@@ -33,28 +33,17 @@ Procedure SysInitFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
 begin
 begin
   { Enable FPU exceptions, but disable INEXACT, UNDERFLOW, DENORMAL }
   { Enable FPU exceptions, but disable INEXACT, UNDERFLOW, DENORMAL }
   asm
   asm
-{$if defined(FPUFPA) or defined(FPUFPA10) or defined(FPUFPA11)}
-
-    rfs r0
-    and r0,r0,#0xffe0ffff
-    orr r0,r0,#0x00070000
-    wfs r0
-{$else}
     movw r0, #(0xed88)
     movw r0, #(0xed88)
     movt r0, #(0xe000)
     movt r0, #(0xe000)
     ldr r1, [r0]
     ldr r1, [r0]
     orr r1, r1, #(0xF << 20)
     orr r1, r1, #(0xF << 20)
     str r1, [r0]
     str r1, [r0]
-{$endif}
   end;
   end;
+  softfloat_exception_mask:=[float_flag_underflow,float_flag_inexact,float_flag_denormal];
+  softfloat_exception_flags:=[];
 end;
 end;
 {$endif}
 {$endif}
 
 
-procedure fpc_cpuinit;
-begin
-  SysInitFPU;
-end;
-
 {$ifdef wince}
 {$ifdef wince}
 function _controlfp(new: DWORD; mask: DWORD): DWORD; cdecl; external 'coredll';
 function _controlfp(new: DWORD; mask: DWORD): DWORD; cdecl; external 'coredll';
 
 
@@ -68,12 +57,25 @@ end;
 Procedure SysInitFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
 Procedure SysInitFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
 begin
 begin
   softfloat_exception_mask:=[float_flag_underflow,float_flag_inexact,float_flag_denormal];
   softfloat_exception_mask:=[float_flag_underflow,float_flag_inexact,float_flag_denormal];
+  softfloat_exception_flags:=[];
   { Enable FPU exceptions, but disable INEXACT, UNDERFLOW, DENORMAL }
   { Enable FPU exceptions, but disable INEXACT, UNDERFLOW, DENORMAL }
   { FPU precision 64 bit, rounding to nearest, affine infinity }
   { FPU precision 64 bit, rounding to nearest, affine infinity }
   _controlfp($000C0003, $030F031F);
   _controlfp($000C0003, $030F031F);
 end;
 end;
 {$endif wince}
 {$endif wince}
 
 
+{$define FPC_SYSTEM_HAS_GETSETNATIVEFPUCONTROLWORD}
+function GetNativeFPUControlWord: TNativeFPUControlWord;
+  begin
+    result:=_controlfp(0,0);
+  end;
+
+procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord);
+  begin
+    _controlfp(cw,$ffffffff);
+  end;
+
+
 {****************************************************************************
 {****************************************************************************
                        stack frame related stuff
                        stack frame related stuff
 ****************************************************************************}
 ****************************************************************************}

+ 1 - 1
rtl/avr/avr.inc

@@ -25,7 +25,7 @@ function avr_save: byte;[INTERNPROC: in_avr_save];
 { Restores SREG }
 { Restores SREG }
 procedure avr_restore(old_sreg: byte); [INTERNPROC: in_avr_restore];
 procedure avr_restore(old_sreg: byte); [INTERNPROC: in_avr_restore];
 
 
-
+{$define FPC_SYSTEM_HAS_FPC_CPUINIT}
 procedure fpc_cpuinit;{$ifdef SYSTEMINLINE}inline;{$endif}
 procedure fpc_cpuinit;{$ifdef SYSTEMINLINE}inline;{$endif}
   begin
   begin
   end;
   end;

+ 5 - 0
rtl/i386/cpuh.inc

@@ -47,3 +47,8 @@ function fpc_x86_get_gs:longint;[internproc:fpc_in_x86_get_gs];
 { $i cpummprocs.inc}
 { $i cpummprocs.inc}
 {$endif not VER3_0 and not VER3_2}
 {$endif not VER3_0 and not VER3_2}
 
 
+type
+  TNativeFPUControlWord = record
+    cw8087: word;
+    MXCSR: dword;
+  end;

+ 1 - 0
rtl/i386/i386.inc

@@ -56,6 +56,7 @@ function cpuid_support : boolean;assembler;nostackframe;
 {$endif FPC_SYSTEM_HAS_MOVE}
 {$endif FPC_SYSTEM_HAS_MOVE}
 {$endif FPC_PIC}
 {$endif FPC_PIC}
 
 
+{$define FPC_SYSTEM_HAS_FPC_CPUINIT}
 procedure fpc_cpuinit;
 procedure fpc_cpuinit;
   begin
   begin
     { because of the brain dead sse detection on x86, this test is post poned to fpc_cpucodeinit which
     { because of the brain dead sse detection on x86, this test is post poned to fpc_cpucodeinit which

+ 18 - 0
rtl/i386/math.inc

@@ -114,6 +114,24 @@ const
       end;
       end;
 
 
 
 
+    function GetNativeFPUControlWord: TNativeFPUControlWord; {$if defined(SYSTEMINLINE)}inline;{$endif}
+      begin
+        result.cw8087:=Get8087CW;
+        if has_sse_support then
+          result.MXCSR:=GetMXCSR
+        else
+          result.MXCSR:=-1;
+      end;
+
+
+    procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord); {$if defined(SYSTEMINLINE)}inline;{$endif}
+      begin
+        Set8087CW(cw.cw8087);
+        if cw.MXCSR<>-1 then
+          SetMXCSR(cw.MXCSR);
+      end;
+
+
     procedure SetSSECSR(w : dword);
     procedure SetSSECSR(w : dword);
       begin
       begin
         SetMXCSR(w);
         SetMXCSR(w);

+ 3 - 0
rtl/i8086/cpuh.inc

@@ -40,3 +40,6 @@ function fpc_x86_get_ds:word;[internproc:fpc_in_x86_get_ds];
 function fpc_x86_get_es:word;[internproc:fpc_in_x86_get_es];
 function fpc_x86_get_es:word;[internproc:fpc_in_x86_get_es];
 function fpc_x86_get_fs:word;[internproc:fpc_in_x86_get_fs];
 function fpc_x86_get_fs:word;[internproc:fpc_in_x86_get_fs];
 function fpc_x86_get_gs:word;[internproc:fpc_in_x86_get_gs];
 function fpc_x86_get_gs:word;[internproc:fpc_in_x86_get_gs];
+
+type
+  TNativeFPUControlWord = word;

+ 1 - 0
rtl/i8086/i8086.inc

@@ -14,6 +14,7 @@
 
 
  **********************************************************************}
  **********************************************************************}
 
 
+{$define FPC_SYSTEM_HAS_FPC_CPUINIT}
 procedure fpc_cpuinit;
 procedure fpc_cpuinit;
   begin
   begin
   end;
   end;

+ 12 - 0
rtl/i8086/math.inc

@@ -39,6 +39,18 @@
 	pop ax
 	pop ax
       end;
       end;
 
 
+    function GetNativeFPUControlWord: TNativeFPUControlWord; {$if defined(SYSTEMINLINE)}inline;{$endif}
+      begin
+        result:=Get8087CW;
+      end;
+
+
+    procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord); {$if defined(SYSTEMINLINE)}inline;{$endif}
+      begin
+        Set8087CW(cw);
+      end;
+
+
     procedure Handle_I8086_Error(InterruptNumber : dword); public name 'FPC_HANDLE_I8086_ERROR';
     procedure Handle_I8086_Error(InterruptNumber : dword); public name 'FPC_HANDLE_I8086_ERROR';
       var
       var
         FpuStatus : word;
         FpuStatus : word;

+ 9 - 18
rtl/inc/dynlib.inc

@@ -23,34 +23,25 @@ Function DoSafeLoadLibrary(const Name : RawByteString) : TLibHandle;
 {$else not FPCRTL_FILESYSTEM_TWO_BYTE_API}
 {$else not FPCRTL_FILESYSTEM_TWO_BYTE_API}
 Function DoSafeLoadLibrary(const Name : UnicodeString) : TLibHandle;
 Function DoSafeLoadLibrary(const Name : UnicodeString) : TLibHandle;
 {$endif not FPCRTL_FILESYSTEM_TWO_BYTE_API}
 {$endif not FPCRTL_FILESYSTEM_TWO_BYTE_API}
-{$if defined(cpui386) or defined(cpux86_64)}
+{$ifndef FPUNONE}
   var
   var
-    fpucw : Word;
-    ssecw : DWord;
-{$endif}
+    fpucw: TNativeFPUControlWord;
   begin
   begin
     try
     try
-{$if defined(cpui386) or defined(cpux86_64)}
-      fpucw:=Get8087CW;
-{$ifdef cpui386}
-      if has_sse_support then
-{$endif cpui386}
-        ssecw:=GetMXCSR;
+      fpucw:=GetNativeFPUControlWord;
+{$else}
+  begin
 {$endif}
 {$endif}
 {$ifndef FPCRTL_FILESYSTEM_TWO_BYTE_API}
 {$ifndef FPCRTL_FILESYSTEM_TWO_BYTE_API}
       Result:=CurrentDLM.LoadLibraryA(Name);
       Result:=CurrentDLM.LoadLibraryA(Name);
 {$else FPCRTL_FILESYSTEM_TWO_BYTE_API}
 {$else FPCRTL_FILESYSTEM_TWO_BYTE_API}
       Result:=CurrentDLM.LoadLibraryU(Name);
       Result:=CurrentDLM.LoadLibraryU(Name);
 {$endif FPCRTL_FILESYSTEM_TWO_BYTE_API}
 {$endif FPCRTL_FILESYSTEM_TWO_BYTE_API}
-      finally
-{$if defined(cpui386) or defined(cpux86_64)}
-      Set8087CW(fpucw);
-{$ifdef cpui386}
-      if has_sse_support then
-{$endif cpui386}
-        SetMXCSR(ssecw);
-{$endif}
+{$ifndef FPUNONE}
+    finally
+      SetNativeFPUControlWord(fpucw);
     end;
     end;
+{$endif}
   end;
   end;
 
 
 Function LoadLibrary(const Name : RawByteString) : TLibHandle;
 Function LoadLibrary(const Name : RawByteString) : TLibHandle;

+ 20 - 0
rtl/inc/generic.inc

@@ -2646,6 +2646,9 @@ end;
 procedure SysResetFpu;{$ifdef SYSTEMINLINE}inline;{$endif}
 procedure SysResetFpu;{$ifdef SYSTEMINLINE}inline;{$endif}
 begin
 begin
   softfloat_exception_flags:=[];
   softfloat_exception_flags:=[];
+{$if declared(DefaultFPUControlWord)}
+  SetNativeFPUControlWord(DefaultFPUControlWord);
+{$endif}
 end;
 end;
 
 
 {$endif FPC_SYSTEM_HAS_SYSRESETFPU}
 {$endif FPC_SYSTEM_HAS_SYSRESETFPU}
@@ -2655,11 +2658,28 @@ end;
 procedure SysInitFpu;{$ifdef SYSTEMINLINE}inline;{$endif}
 procedure SysInitFpu;{$ifdef SYSTEMINLINE}inline;{$endif}
 begin
 begin
   softfloat_exception_mask:=[float_flag_underflow,float_flag_inexact,float_flag_denormal];
   softfloat_exception_mask:=[float_flag_underflow,float_flag_inexact,float_flag_denormal];
+  softfloat_exception_flags:=[];
 end;
 end;
 
 
 {$endif FPC_SYSTEM_HAS_SYSINITFPU}
 {$endif FPC_SYSTEM_HAS_SYSINITFPU}
 {$endif}
 {$endif}
 
 
+{$ifndef FPC_SYSTEM_HAS_FPC_CPUINIT}
+procedure fpc_cpuinit;
+  begin
+{$ifndef FPUNONE}
+{$ifdef FPC_HAS_FEATURE_DYNLIBS}
+    if not IsLibrary then
+{$endif}
+      SysInitFPU;
+{$if declared(DefaultFPUControlWord)}
+    DefaultFPUControlWord:=GetNativeFPUControlWord;
+{$endif}
+    SysResetFPU;
+{$endif}
+  end;
+{$endif}
+
 {$ifndef FPC_SYSTEM_HAS_SWAPENDIAN}
 {$ifndef FPC_SYSTEM_HAS_SWAPENDIAN}
 function SwapEndian(const AValue: SmallInt): SmallInt;{$ifdef SYSTEMINLINE}inline;{$endif}
 function SwapEndian(const AValue: SmallInt): SmallInt;{$ifdef SYSTEMINLINE}inline;{$endif}
   begin
   begin

+ 18 - 1
rtl/inc/mathh.inc

@@ -15,6 +15,7 @@
    { i386 FPU Controlword }
    { i386 FPU Controlword }
 
 
 {$if defined(cpui8086) or defined(cpui386) or defined(cpux86_64)}
 {$if defined(cpui8086) or defined(cpui386) or defined(cpux86_64)}
+    {$define FPC_SYSTEM_FPU_CUSTOM_CONTROL_WORD}
     const
     const
       Default8087CW : word = $1332;
       Default8087CW : word = $1332;
 
 
@@ -23,6 +24,7 @@
 {$endif}
 {$endif}
 
 
 {$if defined (cpui386) or defined(cpux86_64)}
 {$if defined (cpui386) or defined(cpux86_64)}
+    {$define FPC_SYSTEM_FPU_CUSTOM_CONTROL_WORD}
     const
     const
       DefaultMXCSR: dword = $1900;
       DefaultMXCSR: dword = $1900;
 
 
@@ -33,6 +35,7 @@
 {$endif}
 {$endif}
 
 
 {$if defined(cpum68k)}
 {$if defined(cpum68k)}
+    {$define FPC_SYSTEM_FPU_CUSTOM_CONTROL_WORD}
 {$if defined(fpu68881) or defined(fpucoldfire)}
 {$if defined(fpu68881) or defined(fpucoldfire)}
     const
     const
     {$ifdef FPC_68K_SYSTEM_HAS_FPU_EXCEPTIONS}
     {$ifdef FPC_68K_SYSTEM_HAS_FPU_EXCEPTIONS}
@@ -45,9 +48,20 @@
     procedure SetFPSR(x: DWord);
     procedure SetFPSR(x: DWord);
     function GetFPCR: DWord;
     function GetFPCR: DWord;
     function GetFPSR: DWord;
     function GetFPSR: DWord;
+{$else}
+    {$define FPC_SYSTEM_FPUCW_IMMUTABLE}
+{$endif}
 {$endif}
 {$endif}
+
+{$if (defined(FPC_SYSTEM_FPUCW_IMMUTABLE) or defined(FPU_NONE)) and not declared(TNativeFPUControlWord)}
+  type
+    TNativeFPUControlWord = record
+    end;
 {$endif}
 {$endif}
 
 
+    function GetNativeFPUControlWord: TNativeFPUControlWord; {$if (defined(FPC_SYSTEM_FPUCW_IMMUTABLE) or defined(FPUNONE)) and defined(SYSTEMINLINE)}inline;{$endif}
+    procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord); {$if (defined(FPC_SYSTEM_FPUCW_IMMUTABLE) or defined(FPUNONE)) and defined(SYSTEMINLINE)}inline;{$endif}
+
   type
   type
     TFPURoundingMode = (rmNearest, rmDown, rmUp, rmTruncate);
     TFPURoundingMode = (rmNearest, rmDown, rmUp, rmTruncate);
     TFPUPrecisionMode = (pmSingle, pmReserved, pmDouble, pmExtended);
     TFPUPrecisionMode = (pmSingle, pmReserved, pmDouble, pmExtended);
@@ -83,8 +97,11 @@ ThreadVar
 {$else FPC_HAS_FEATURE_THREADING}
 {$else FPC_HAS_FEATURE_THREADING}
 Var
 Var
 {$endif FPC_HAS_FEATURE_THREADING}
 {$endif FPC_HAS_FEATURE_THREADING}
-  softfloat_exception_mask : TFPUExceptionMask;
   softfloat_exception_flags : TFPUExceptionMask;
   softfloat_exception_flags : TFPUExceptionMask;
+
+{ global/shared just like the native ones }
+var
+  softfloat_exception_mask : TFPUExceptionMask;
   softfloat_rounding_mode : TFPURoundingMode;
   softfloat_rounding_mode : TFPURoundingMode;
 
 
 procedure float_raise(i: TFPUException);
 procedure float_raise(i: TFPUException);

+ 30 - 0
rtl/inc/system.inc

@@ -101,6 +101,20 @@ begin
 end;
 end;
 {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
 {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
 
 
+{$if not defined(FPC_SYSTEM_FPU_CUSTOM_CONTROL_WORD) and not defined(FPUNONE) and not defined(FPC_SYSTEM_FPUCW_IMMUTABLE)}
+var
+  { Control word of the fpu that determes which exceptions will be thrown and
+    potentially other flags (precision, exception-happened flags, ... Used to
+    initialise the FPU when starting a new thread (in SysResetFPU).
+
+    Some platforms already have a legacy/existing global variable holding this
+    information (FPC_SYSTEM_FPU_CUSTOM_CONTROL_WORD). In case of FPU_NONE,
+    we don't support floating point at all. And in case of
+    FPC_SYSTEM_FPUCW_IMMUTABLE, either the control word cannot be changed
+    (e.g. wasm), or FPU operations are supported by only as softfloat }
+  DefaultFPUControlWord: TNativeFPUControlWord;
+{$endif}
+
 { checks whether the given suggested size for the stack of the current
 { checks whether the given suggested size for the stack of the current
  thread is acceptable. If this is the case, returns it unaltered.
  thread is acceptable. If this is the case, returns it unaltered.
  Otherwise it should return an acceptable value.
  Otherwise it should return an acceptable value.
@@ -1138,6 +1152,22 @@ begin
 end;
 end;
 {$endif FPC_INIT_FINAL_UNITS_BY_CALLS}
 {$endif FPC_INIT_FINAL_UNITS_BY_CALLS}
 
 
+
+{*****************************************************************************
+                        FPU Exceptions state
+*****************************************************************************}
+
+{$if defined(FPC_SYSTEM_FPUCW_IMMUTABLE) or defined(FPU_NONE)}
+function GetNativeFPUControlWord: TNativeFPUControlWord; {$if defined(SYSTEMINLINE)}inline;{$endif}
+begin
+  result:=default(TNativeFPUControlWord);
+end;
+
+procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord); {$if defined(SYSTEMINLINE)}inline;{$endif}
+begin
+end;
+{$endif}
+
 {*****************************************************************************
 {*****************************************************************************
                           Error / Exit / ExitProc
                           Error / Exit / ExitProc
 *****************************************************************************}
 *****************************************************************************}

+ 0 - 1
rtl/inc/thread.inc

@@ -36,7 +36,6 @@ Var
       begin
       begin
 {$ifndef FPUNONE}
 {$ifndef FPUNONE}
         SysResetFPU;
         SysResetFPU;
-        SysInitFPU;
 {$endif}
 {$endif}
 {$ifndef HAS_MEMORYMANAGER}
 {$ifndef HAS_MEMORYMANAGER}
 {$ifndef FPC_NO_DEFAULT_HEAP}
 {$ifndef FPC_NO_DEFAULT_HEAP}

+ 15 - 0
rtl/java/jsystem.inc

@@ -920,6 +920,21 @@ begin
    end;
    end;
 end;
 end;
 *)
 *)
+
+{*****************************************************************************
+                        FPU Exceptions state
+*****************************************************************************}
+
+{$if defined(FPC_SYSTEM_FPUCW_IMMUTABLE) or defined(FPU_NONE)}
+function GetNativeFPUControlWord: TNativeFPUControlWord; {$if defined(SYSTEMINLINE)}inline;{$endif}
+begin
+  result:=default(TNativeFPUControlWord);
+end;
+
+procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord); {$if defined(SYSTEMINLINE)}inline;{$endif}
+begin
+end;
+{$endif}
 {*****************************************************************************
 {*****************************************************************************
                           Error / Exit / ExitProc
                           Error / Exit / ExitProc
 *****************************************************************************}
 *****************************************************************************}

+ 3 - 0
rtl/java/jsystemh.inc

@@ -18,6 +18,9 @@
                         Processor specific routines
                         Processor specific routines
 ****************************************************************************}
 ****************************************************************************}
 
 
+{ CPU specific stuff }
+{$i cpuh.inc}
+
 {$ifdef FPC_USE_LIBC}
 {$ifdef FPC_USE_LIBC}
   {$ifdef SYSTEMINLINE}
   {$ifdef SYSTEMINLINE}
     {$define INLINEGENERICS}
     {$define INLINEGENERICS}

+ 2 - 0
rtl/jvm/cpuh.inc

@@ -13,3 +13,5 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 
  **********************************************************************}
  **********************************************************************}
+
+{$define FPC_SYSTEM_FPUCW_IMMUTABLE}

+ 0 - 8
rtl/jvm/jvm.inc

@@ -33,14 +33,6 @@ Procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
   end;
   end;
 
 
 
 
-procedure fpc_cpuinit;
-  begin
-    SysResetFPU;
-    if not(IsLibrary) then
-      SysInitFPU;
-  end;
-
-
 {$define FPC_SYSTEM_HAS_GET_CALLER_ADDR}
 {$define FPC_SYSTEM_HAS_GET_CALLER_ADDR}
 function get_caller_addr(framebp:pointer;addr:pointer=nil):pointer;
 function get_caller_addr(framebp:pointer;addr:pointer=nil):pointer;
   begin
   begin

+ 1 - 1
rtl/linux/powerpc/sighnd.inc

@@ -23,7 +23,7 @@ begin
   res:=0;
   res:=0;
 {$ifndef FPUNONE}
 {$ifndef FPUNONE}
   { exception flags are turned off by kernel }
   { exception flags are turned off by kernel }
-  fpc_enable_ppc_fpu_exceptions;
+  SysResetFpu;
 {$endif}
 {$endif}
   case sig of
   case sig of
     SIGFPE :
     SIGFPE :

+ 1 - 1
rtl/linux/powerpc64/sighnd.inc

@@ -22,7 +22,7 @@ begin
   res:=0;
   res:=0;
 
 
   { exception flags are turned off by kernel }
   { exception flags are turned off by kernel }
-  fpc_enable_ppc_fpu_exceptions;
+  SysResetFpu;
   case sig of
   case sig of
     SIGFPE :
     SIGFPE :
       { distuingish between different FPU exceptions }
       { distuingish between different FPU exceptions }

+ 2 - 0
rtl/m68k/cpuh.inc

@@ -18,3 +18,5 @@
    Test68000 : byte = 0;      { Must be determined at startup for both }
    Test68000 : byte = 0;      { Must be determined at startup for both }
    Test68881 : byte = 0;
    Test68881 : byte = 0;
 
 
+ type
+   TNativeFPUControlWord = dword;

+ 21 - 24
rtl/m68k/m68k.inc

@@ -40,9 +40,12 @@ asm
   fmove.l fpsr, d0
   fmove.l fpsr, d0
 end;
 end;
 
 
-procedure SetFPCR(x: DWord); assembler; nostackframe;
-asm
-  fmove.l x, fpcr
+procedure SetFPCR(x: DWord);
+begin
+  Default68kFPCR:=x;
+  asm
+    fmove.l x, fpcr
+  end;
 end;
 end;
 
 
 procedure SetFPSR(x: DWord); assembler; nostackframe;
 procedure SetFPSR(x: DWord); assembler; nostackframe;
@@ -50,9 +53,20 @@ asm
   fmove.l x, fpsr
   fmove.l x, fpsr
 end;
 end;
 
 
+function GetNativeFPUControlWord: TNativeFPUControlWord;
+  begin
+    result:=GetFPCR;
+  end;
+
+procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord);
+  begin
+    SetFPCR(cw);
+  end;
+
 {$DEFINE FPC_SYSTEM_HAS_SYSRESETFPU}
 {$DEFINE FPC_SYSTEM_HAS_SYSRESETFPU}
 procedure SysResetFPU;
 procedure SysResetFPU;
 begin
 begin
+  softfloat_exception_flags:=[];
   SetFPCR(Default68KFPCR);
   SetFPCR(Default68KFPCR);
   SetFPSR(0);
   SetFPSR(0);
 end;
 end;
@@ -60,29 +74,12 @@ end;
 {$DEFINE FPC_SYSTEM_HAS_SYSINITFPU}
 {$DEFINE FPC_SYSTEM_HAS_SYSINITFPU}
 procedure SysInitFPU;
 procedure SysInitFPU;
 begin
 begin
+  softfloat_exception_mask:=[float_flag_underflow,float_flag_inexact,float_flag_denormal];
+  softfloat_exception_flags:=[];
+  SetFPSR(0);
 end;
 end;
 
 
-procedure fpc_cpuinit;
-  begin
-    if IsLibrary then
-      begin
-        Default68kFPCR:=GetFPCR;
-      end;
-    SysResetFPU;
-  end;
-
-{$ELSE}
-
-procedure fpc_cpuinit;
-  begin
-{$IFNDEF FPUNONE}
-    SysResetFPU;
-    if (not IsLibrary) then
-      SysInitFPU;
-{$ENDIF}
-  end;
-
-{$ENDIF}
+{$endif}
 
 
 {$ifndef INTERNAL_BACKTRACE}
 {$ifndef INTERNAL_BACKTRACE}
 {$define FPC_SYSTEM_HAS_GET_FRAME}
 {$define FPC_SYSTEM_HAS_GET_FRAME}

+ 3 - 0
rtl/mips/cpuh.inc

@@ -13,3 +13,6 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 
  **********************************************************************}
  **********************************************************************}
+
+type
+  TNativeFPUControlWord = dword;

+ 10 - 14
rtl/mips/mathu.inc

@@ -12,10 +12,6 @@
 
 
  **********************************************************************}
  **********************************************************************}
 
 
-{ exported by the system unit }
-function get_fsr : dword;external name 'FPC_GETFSR';
-procedure set_fsr(fsr : dword);external name 'FPC_SETFSR';
-
 const
 const
   { FPU enable exception bits for FCSR register }
   { FPU enable exception bits for FCSR register }
   fpu_enable_inexact   =  $80;
   fpu_enable_inexact   =  $80;
@@ -53,17 +49,17 @@ const
 
 
 function GetRoundMode: TFPURoundingMode;
 function GetRoundMode: TFPURoundingMode;
   begin
   begin
-    result:=fsr2roundmode[get_fsr and fpu_rounding_mask];
+    result:=fsr2roundmode[GetNativeFPUControlWord and fpu_rounding_mask];
   end;
   end;
 
 
 function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
 function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
   var
   var
-    fsr: longword;
+    fsr: TNativeFPUControlWord;
   begin
   begin
-    fsr:=get_fsr;
+    fsr:=GetNativeFPUControlWord;
     result:=fsr2roundmode[fsr and fpu_rounding_mask];
     result:=fsr2roundmode[fsr and fpu_rounding_mask];
     softfloat_rounding_mode:=RoundMode;
     softfloat_rounding_mode:=RoundMode;
-    set_fsr((fsr and not fpu_rounding_mask) or roundmode2fsr[RoundMode]);
+    SetNativeFPUControlWord((fsr and not fpu_rounding_mask) or roundmode2fsr[RoundMode]);
   end;
   end;
 
 
 
 
@@ -79,7 +75,7 @@ function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode
   end;
   end;
 
 
 
 
-function fsr2ExceptionMask(fsr: longword): TFPUExceptionMask;
+function fsr2ExceptionMask(fsr: TNativeFPUControlWord): TFPUExceptionMask;
   begin
   begin
     result:=[];
     result:=[];
     { invalid operation }
     { invalid operation }
@@ -106,15 +102,15 @@ function fsr2ExceptionMask(fsr: longword): TFPUExceptionMask;
 
 
 function GetExceptionMask: TFPUExceptionMask;
 function GetExceptionMask: TFPUExceptionMask;
   begin
   begin
-    result:=fsr2ExceptionMask(get_fsr);
+    result:=fsr2ExceptionMask(GetNativeFPUControlWord);
   end;
   end;
 
 
 
 
 function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
 function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
   var
   var
-    fsr : longword;
+    fsr : TNativeFPUControlWord;
   begin
   begin
-    fsr:=get_fsr;
+    fsr:=GetNativeFPUControlWord;
     result:=fsr2ExceptionMask(fsr);
     result:=fsr2ExceptionMask(fsr);
 
 
     { Reset flags, cause and enables }
     { Reset flags, cause and enables }
@@ -141,12 +137,12 @@ function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
       fsr:=fsr or (fpu_enable_inexact);
       fsr:=fsr or (fpu_enable_inexact);
 
 
     { update control register contents }
     { update control register contents }
-    set_fsr(fsr);
+    SetNativeFPUControlWord(fsr);
   end;
   end;
 
 
 
 
 procedure ClearExceptions(RaisePending: Boolean =true);
 procedure ClearExceptions(RaisePending: Boolean =true);
   begin
   begin
-    set_fsr(get_fsr and not (fpu_flags_mask or fpu_cause_mask));
+    SetNativeFPUControlWord(GetNativeFPUControlWord and not (fpu_flags_mask or fpu_cause_mask));
   end;
   end;
 
 

+ 21 - 19
rtl/mips/mips.inc

@@ -22,9 +22,25 @@ function get_fsr : dword;assembler;nostackframe;[public, alias: 'FPC_GETFSR'];
   end;
   end;
 
 
 
 
-procedure set_fsr(fsr : dword);assembler;nostackframe;[public, alias: 'FPC_SETFSR'];
-  asm
-    ctc1 $4,$31
+procedure set_fsr(fsr : dword);[public, alias: 'FPC_SETFSR'];
+  begin
+    DefaultFPUControlWord:=fsr;
+    asm
+      lw $4,fsr
+      ctc1 $4,$31
+    end;
+  end;
+
+
+function GetNativeFPUControlWord: TNativeFPUControlWord; {$if defined(SYSTEMINLINE)}inline;{$endif}
+  begin
+    result:=get_fsr;
+  end;
+
+
+procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord); {$if defined(SYSTEMINLINE)}inline;{$endif}
+  begin
+    set_fsr(cw);
   end;
   end;
 
 
 
 
@@ -60,26 +76,12 @@ const
 procedure SysInitFPU;
 procedure SysInitFPU;
   begin
   begin
     set_fsr(get_fsr and (not fpu_all_bits) or (default_fpu_enable or fpu_rounding_nearest));
     set_fsr(get_fsr and (not fpu_all_bits) or (default_fpu_enable or fpu_rounding_nearest));
-  end;
-
-
-{$define FPC_SYSTEM_HAS_SYSRESETFPU}
-procedure SysResetFPU;
-  begin
+    softfloat_exception_mask:=[float_flag_inexact,float_flag_denormal];
+    softfloat_exception_flags:=[];
   end;
   end;
 {$endif FPUMIPS2 or FPUMIPS3}
 {$endif FPUMIPS2 or FPUMIPS3}
 
 
 
 
-procedure fpc_cpuinit;
-  begin
-{$ifndef FPUNONE}
-    SysResetFPU;
-    if (not IsLibrary) then
-      SysInitFPU;
-{$endif FPUNONE}
-  end;
-
-
 {$ifndef INTERNAL_BACKTRACE}
 {$ifndef INTERNAL_BACKTRACE}
 {$define FPC_SYSTEM_HAS_GET_FRAME}
 {$define FPC_SYSTEM_HAS_GET_FRAME}
 function get_frame:pointer;assembler;nostackframe;
 function get_frame:pointer;assembler;nostackframe;

+ 3 - 0
rtl/mips64/cpuh.inc

@@ -13,3 +13,6 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 
  **********************************************************************}
  **********************************************************************}
+
+type
+  TNativeFPUControlWord = dword;

+ 9 - 0
rtl/powerpc/cpuh.inc

@@ -13,3 +13,12 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 
  **********************************************************************}
  **********************************************************************}
+type
+{$ifndef aix}
+  TNativeFPUControlWord = dword;
+{$else aix}
+  TNativeFPUControlWord = record
+    rndmode: word;
+    exceptionmask: byte;
+  end;
+{$endif}

+ 1 - 205
rtl/powerpc/mathu.inc

@@ -1,205 +1 @@
-{
-    This file is part of the Free Pascal run time library.
-    Copyright (c) 2005 by Thomas Schatzl
-    member of the Free Pascal development team
-
-    See the file COPYING.FPC, included in this distribution,
-    for details about the copyright.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
- **********************************************************************}
-
-const
-  RoundModeMask        = %00000011;
-  NonIEEEModeMask      = %00000100;
-
-  InvalidOperationMask = %10000000;
-  OverflowMask         = %01000000;
-  UnderflowMask        = %00100000;
-  ZeroDivideMask       = %00010000;
-  InexactMask          = %00001000;
-  AllExceptionsMask    = %11111000;
-  ExceptionsPendingMask = %11111111111111100000011100000000;
-
-  ExceptionMask        = InvalidOperationMask or OverflowMask or UnderflowMask or ZeroDivideMask or InexactMask;
-
-  AllConfigBits        = ExceptionMask or NonIEEEModeMask or RoundModeMask;
-
-function getFPSCR : DWord; assembler; nostackframe;
-asm
-  mffs f0
-  stfd f0, -12(r1)
-  lwz r3, -8(r1)
-end;
-
-procedure setFPSCR(newFPSCR : DWord); assembler; nostackframe;
-asm
-  stw r3, -8(r1)
-  lfd f0, -12(r1)
-  mtfsf 255, f0
-end;
-
-{$ifdef aix}
-const
-  FP_RND_RZ = 0;
-  FP_RND_RN = 1;
-  FP_RND_RP = 2;
-  FP_RND_RM = 3;
-
-function fp_is_enabled(Mask: DWord): boolean;cdecl;external;
-procedure fp_enable(Mask: DWord);cdecl;external;
-function feclearexcept(Mask: DWord):DWord;cdecl;external;
-procedure fp_disable(Mask: DWord);cdecl;external;
-function fp_read_rnd: word;cdecl;external;
-function fp_swap_rnd(RoundMode: word): word;cdecl;external;
-
-{$else aix}
-const
-  FP_RND_RZ = 1;
-  FP_RND_RN = 0;
-  FP_RND_RP = 2;
-  FP_RND_RM = 3;
-{$endif aix}
-
-function GetRoundMode: TFPURoundingMode;
-begin
-{$ifndef aix}
-  case (getFPSCR and RoundModeMask) of
-{$else not aix}
-  case fp_read_rnd of
-{$endif not aix}
-    FP_RND_RN : result := rmNearest;
-    FP_RND_RZ : result := rmTruncate;
-    FP_RND_RP : result := rmUp;
-    FP_RND_RM : result := rmDown;
-  end;
-end;
-
-function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
-var
-  mode : DWord;
-begin
-  softfloat_rounding_mode:=RoundMode;
-  case (RoundMode) of
-    rmNearest :
-      begin
-        mode := FP_RND_RN;
-      end;
-    rmTruncate :
-      begin
-        mode := FP_RND_RZ;
-      end;
-    rmUp :
-      begin
-        mode := FP_RND_RP;
-      end;
-    rmDown :
-      begin
-        mode := FP_RND_RM;
-      end;
-  end;
-  result := GetRoundMode;
-{$ifndef aix}
-  setFPSCR((getFPSCR and (not RoundModeMask)) or mode);
-{$else not aix}
-  fp_swap_rnd(mode);
-{$endif not aix}
-end;
-
-
-function GetPrecisionMode: TFPUPrecisionMode;
-begin
-  result := pmDouble;
-end;
-
-function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode;
-begin
-  { nothing to do, not supported }
-  result := pmDouble;
-end;
-
-
-function GetExceptionMask: TFPUExceptionMask;
-begin
-  result := [];
-{$ifndef aix}
-  if ((getFPSCR and InvalidOperationMask) = 0) then 
-    result := result + [exInvalidOp];
-  if ((getFPSCR and OverflowMask) = 0) then 
-    result := result + [exOverflow];
-  if ((getFPSCR and UnderflowMask) = 0) then 
-    result := result + [exUnderflow];
-  if ((getFPSCR and ZeroDivideMask) = 0) then 
-    result := result + [exZeroDivide];
-  if ((getFPSCR and InexactMask) = 0) then 
-    result := result + [exPrecision];
-{$else not aix}
-  if not fp_is_enabled(InvalidOperationMask) then
-    result := result + [exInvalidOp];
-  if not fp_is_enabled(OverflowMask) then
-    result := result + [exOverflow];
-  if not fp_is_enabled(UnderflowMask) then
-    result := result + [exUnderflow];
-  if not fp_is_enabled(ZeroDivideMask) then
-    result := result + [exZeroDivide];
-  if not fp_is_enabled(InexactMask) then
-    result := result + [exPrecision];
-{$endif not aix}
-end;
-
-function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
-var
-  mode : DWord;
-begin
-  mode := 0;
-  softfloat_exception_mask := mask;
-  if (exInvalidOp in Mask) then
-    begin
-      mode := mode or InvalidOperationMask;
-    end;
-  if (exOverflow in Mask) then
-    begin
-      mode := mode or OverflowMask;
-    end;
-  if (exUnderflow in Mask) then
-    begin
-      mode := mode or UnderflowMask;
-    end;
-  if (exZeroDivide in Mask) then
-    begin
-      mode := mode or ZeroDivideMask;
-    end;
-  if (exPrecision in Mask) then
-    begin
-      mode := mode or InexactMask;
-    end;
-
-  setFPSCR((getFPSCR or ExceptionMask) and not mode and not ExceptionsPendingMask);
-  softfloat_exception_flags := [];
-  { also clear out pending exceptions on AIX }
-{$ifdef aix}
-  { clear pending exceptions }
-  feclearexcept(AllExceptionsMask);
-  { enable the exceptions that are not disabled }
-  fp_enable(mode xor AllExceptionsMask);
-  { and disable the rest }
-  fp_disable(mode);
-{$endif}
-  result := Mask - [exDenormalized];
-end;
-
-
-procedure ClearExceptions(RaisePending: Boolean = true);
-begin
-{$ifdef aix}
-  { clear pending exceptions }
-  feclearexcept(AllExceptionsMask);
-{$endif}
-  softfloat_exception_flags := [];
-  { RaisePending has no effect on PPC, always raises them at the correct location }
-  setFPSCR(getFPSCR and (not ExceptionsPendingMask));
-end;
-
+{$i ../ppcgen/ppcmathu.inc}

+ 2 - 85
rtl/powerpc/powerpc.inc

@@ -30,61 +30,10 @@
 {****************************************************************************
 {****************************************************************************
                            PowerPC specific stuff
                            PowerPC specific stuff
 ****************************************************************************}
 ****************************************************************************}
-{
 
 
-const
-  ppc_fpu_overflow     = (1 shl (32-3));
-  ppc_fpu_underflow    = (1 shl (32-4));
-  ppc_fpu_divbyzero    = (1 shl (32-5));
-  ppc_fpu_inexact      = (1 shl (32-6));
-  ppc_fpu_invalid_snan = (1 shl (32-7));
-}
+{$i ../ppcgen/ppcfpuex.inc}
 
 
 {$ifndef FPUNONE}
 {$ifndef FPUNONE}
-
-procedure fpc_enable_ppc_fpu_exceptions;
-assembler; nostackframe;
-asm
-  { clear all "exception happened" flags we care about}
-  mtfsfi 0,0
-  mtfsfi 1,0
-  mtfsfi 2,0
-  mtfsfi 3,0
-  mtfsb0 21
-  mtfsb0 22
-  mtfsb0 23
-
-  { enable invalid operations and division by zero exceptions. }
-  { No overflow/underflow, since those give some spurious      }
-  { exceptions                                                 }
-  mtfsfi 6,9
-end;
-
-procedure fpc_cpuinit;
-begin
-  { don't let libraries influence the FPU cw set by the host program }
-  if not IsLibrary then
-    fpc_enable_ppc_fpu_exceptions;
-end;
-
-
-function fpc_get_ppc_fpscr: cardinal;
-assembler;
-var
-  temp: record a,b:longint; end;
-asm
-  mffs f0
-  stfd f0,temp
-  lwz  r3,temp.b
-  { clear all exception flags }
-{
-  rlwinm r4,r3,0,16,31
-  stw  r4,temp.b
-  lfd  f0,temp
-  a_mtfsf f0
-}
-end;
-
 { This function is never called directly, it's a dummy to hold the register save/
 { This function is never called directly, it's a dummy to hold the register save/
   load subroutines
   load subroutines
 }
 }
@@ -215,13 +164,7 @@ _restfpr_31_l:  lwz     r0, 4(r11)
 end;
 end;
 {$endif MACOS}
 {$endif MACOS}
 
 
-{$else}
-
-procedure fpc_cpuinit;
-begin
-end;
-
-{$endif}
+{$endif NOT FPUNONE}
 
 
 {****************************************************************************
 {****************************************************************************
                                 Move / Fill
                                 Move / Fill
@@ -1230,32 +1173,6 @@ asm
   mr     r3, r10
   mr     r3, r10
 end;
 end;
 
 
-{$IFDEF MORPHOS}
-{ this is only required for MorphOS }
-{$define FPC_SYSTEM_HAS_SYSINITFPU}
-procedure SysInitFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
-  var tmp: array[0..1] of dword;
-begin
-  asm
-     { setting fpu to round to nearest mode }
-     li r3,0
-     stw r3,8(r1)
-     stw r3,12(r1)
-     lfd f1,8(r1)
-     mtfsf 7,f1
-  end;
-  { powerpc might use softfloat code }
-  softfloat_exception_flags:=[];
-  softfloat_exception_mask:=[float_flag_underflow, float_flag_inexact, float_flag_denormal];
-end;
-
-{$define FPC_SYSTEM_HAS_SYSRESETFPU}
-procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
-begin
-  softfloat_exception_flags:=[];
-end;
-{$ENDIF}
-
 {$ifndef FPC_SYSTEM_HAS_MEM_BARRIER}
 {$ifndef FPC_SYSTEM_HAS_MEM_BARRIER}
 {$define FPC_SYSTEM_HAS_MEM_BARRIER}
 {$define FPC_SYSTEM_HAS_MEM_BARRIER}
 
 

+ 10 - 0
rtl/powerpc64/cpuh.inc

@@ -13,3 +13,13 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 
  **********************************************************************}
  **********************************************************************}
+
+type
+{$ifndef aix}
+  TNativeFPUControlWord = dword;
+{$else aix}
+  TNativeFPUControlWord = record
+    rndmode: word;
+    exceptionmask: byte;
+  end;
+{$endif}

+ 1 - 213
rtl/powerpc64/mathu.inc

@@ -1,213 +1 @@
-{
-    This file is part of the Free Pascal run time library.
-    Copyright (c) 2005 by Thomas Schatzl
-    member of the Free Pascal development team
-
-    See the file COPYING.FPC, included in this distribution,
-    for details about the copyright.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
- **********************************************************************}
-
-const
-  RoundModeMask        = %00000011;
-  NonIEEEModeMask      = %00000100;
-
-  InvalidOperationMask = %10000000;
-  OverflowMask         = %01000000;
-  UnderflowMask        = %00100000;
-  ZeroDivideMask       = %00010000;
-  InexactMask          = %00001000;
-  AllExceptionsMask    = %11111000;
-  ExceptionsPendingMask = %11111111111111100000011100000000;
-
-  ExceptionMask        = InvalidOperationMask or OverflowMask or UnderflowMask or ZeroDivideMask or InexactMask;
-
-  AllConfigBits        = ExceptionMask or NonIEEEModeMask or RoundModeMask;
-
-function getFPSCR : DWord; assembler; nostackframe;
-asm
-  mffs f0
-  stfd f0, -16(r1)
-{$ifdef FPC_BIG_ENDIAN}
-  lwz r3, -12(r1)
-{$else}
-  lwz r3, -16(r1)
-{$endif}
-end;
-
-procedure setFPSCR(newFPSCR : DWord); assembler; nostackframe;
-asm
-{$ifdef FPC_BIG_ENDIAN}
-  stw r3, -12(r1)
-{$else}
-  stw r3, -16(r1)
-{$endif}
-  lfd f0, -16(r1)
-  mtfsf 255, f0
-end;
-
-{$ifdef aix}
-const
-  FP_RND_RZ = 0;
-  FP_RND_RN = 1;
-  FP_RND_RP = 2;
-  FP_RND_RM = 3;
-
-function fp_is_enabled(Mask: DWord): boolean;cdecl;external;
-procedure fp_enable(Mask: DWord);cdecl;external;
-function feclearexcept(Mask: DWord):DWord;cdecl;external;
-procedure fp_disable(Mask: DWord);cdecl;external;
-function fp_read_rnd: word;cdecl;external;
-function fp_swap_rnd(RoundMode: word): word;cdecl;external;
-
-{$else aix}
-const
-  FP_RND_RZ = 1;
-  FP_RND_RN = 0;
-  FP_RND_RP = 2;
-  FP_RND_RM = 3;
-{$endif aix}
-
-function GetRoundMode: TFPURoundingMode;
-begin
-{$ifndef aix}
-  case (getFPSCR and RoundModeMask) of
-{$else not aix}
-  case fp_read_rnd of
-{$endif not aix}
-    FP_RND_RN : result := rmNearest;
-    FP_RND_RZ : result := rmTruncate;
-    FP_RND_RP : result := rmUp;
-    FP_RND_RM : result := rmDown;
-  end;
-end;
-
-function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
-var
-  mode : DWord;
-begin
-  softfloat_rounding_mode:=RoundMode;
-  case (RoundMode) of
-    rmNearest :
-      begin
-        mode := FP_RND_RN;
-      end;
-    rmTruncate :
-      begin
-        mode := FP_RND_RZ;
-      end;
-    rmUp :
-      begin
-        mode := FP_RND_RP;
-      end;
-    rmDown :
-      begin
-        mode := FP_RND_RM;
-      end;
-  end;
-  result := GetRoundMode;
-{$ifndef aix}
-  setFPSCR((getFPSCR and (not RoundModeMask)) or mode);
-{$else not aix}
-  fp_swap_rnd(mode);
-{$endif not aix}
-end;
-
-
-function GetPrecisionMode: TFPUPrecisionMode;
-begin
-  result := pmDouble;
-end;
-
-function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode;
-begin
-  { nothing to do, not supported }
-  result := pmDouble;
-end;
-
-
-function GetExceptionMask: TFPUExceptionMask;
-begin
-  result := [];
-{$ifndef aix}
-  if ((getFPSCR and InvalidOperationMask) = 0) then
-    result := result + [exInvalidOp];
-  if ((getFPSCR and OverflowMask) = 0) then
-    result := result + [exOverflow];
-  if ((getFPSCR and UnderflowMask) = 0) then
-    result := result + [exUnderflow];
-  if ((getFPSCR and ZeroDivideMask) = 0) then
-    result := result + [exZeroDivide];
-  if ((getFPSCR and InexactMask) = 0) then
-    result := result + [exPrecision];
-{$else not aix}
-  if not fp_is_enabled(InvalidOperationMask) then
-    result := result + [exInvalidOp];
-  if not fp_is_enabled(OverflowMask) then
-    result := result + [exOverflow];
-  if not fp_is_enabled(UnderflowMask) then
-    result := result + [exUnderflow];
-  if not fp_is_enabled(ZeroDivideMask) then
-    result := result + [exZeroDivide];
-  if not fp_is_enabled(InexactMask) then
-    result := result + [exPrecision];
-{$endif not aix}
-end;
-
-function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
-var
-  mode : DWord;
-begin
-  mode := 0;
-  softfloat_exception_mask := mask;
-  if (exInvalidOp in Mask) then
-    begin
-      mode := mode or InvalidOperationMask;
-    end;
-  if (exOverflow in Mask) then
-    begin
-      mode := mode or OverflowMask;
-    end;
-  if (exUnderflow in Mask) then
-    begin
-      mode := mode or UnderflowMask;
-    end;
-  if (exZeroDivide in Mask) then
-    begin
-      mode := mode or ZeroDivideMask;
-    end;
-  if (exPrecision in Mask) then
-    begin
-      mode := mode or InexactMask;
-    end;
-
-  setFPSCR((getFPSCR or ExceptionMask) and not mode and not ExceptionsPendingMask);
-  softfloat_exception_flags := [];;
-  { also clear out pending exceptions on AIX }
-{$ifdef aix}
-  { clear pending exceptions }
-  feclearexcept(AllExceptionsMask);
-  { enable the exceptions that are not disabled }
-  fp_enable(mode xor AllExceptionsMask);
-  { and disable the rest }
-  fp_disable(mode);
-{$endif}
-  result := Mask - [exDenormalized];
-end;
-
-
-procedure ClearExceptions(RaisePending: Boolean = true);
-begin
-{$ifdef aix}
-  { clear pending exceptions }
-  feclearexcept(AllExceptionsMask);
-{$endif}
-  softfloat_exception_flags := [];
-  { RaisePending has no effect on PPC, always raises them at the correct location }
-  setFPSCR(getFPSCR and (not ExceptionsPendingMask));
-end;
-
+{$i ../ppcgen/ppcmathu.inc}

+ 2 - 26
rtl/powerpc64/powerpc64.inc

@@ -21,32 +21,7 @@
                            PowerPC specific stuff
                            PowerPC specific stuff
 ****************************************************************************}
 ****************************************************************************}
 
 
-procedure fpc_enable_ppc_fpu_exceptions; assembler; nostackframe;
-asm
-  { clear all "exception happened" flags we care about}
-  mtfsfi 0,0
-  mtfsfi 1,0
-  mtfsfi 2,0
-  mtfsfi 3,0
-{$ifdef fpc_mtfsb0_corrected}
-  mtfsb0 21
-  mtfsb0 22
-  mtfsb0 23
-{$endif fpc_mtfsb0_corrected}
-
-  { enable invalid operations and division by zero exceptions. }
-  { No overflow/underflow, since those give some spurious      }
-  { exceptions                                                 }
-  mtfsfi 6,9
-end;
-
-
-procedure fpc_cpuinit;
-begin
-  { don't let libraries influence the FPU cw set by the host program }
-  if not IsLibrary then
-    fpc_enable_ppc_fpu_exceptions;
-end;
+{$i ../ppcgen/ppcfpuex.inc}
 
 
 {****************************************************************************
 {****************************************************************************
                                 Move / Fill
                                 Move / Fill
@@ -726,6 +701,7 @@ asm
   mr     r3, r10
   mr     r3, r10
 end;
 end;
 
 
+
 function InterLockedDecrement64(var Target: Int64) : Int64; assembler; nostackframe;
 function InterLockedDecrement64(var Target: Int64) : Int64; assembler; nostackframe;
 { input:  address of target in r3 }
 { input:  address of target in r3 }
 { output: target-1 in r3          }
 { output: target-1 in r3          }

+ 170 - 0
rtl/ppcgen/ppcfpuex.inc

@@ -0,0 +1,170 @@
+{$ifndef FPUNONE}
+
+const
+  InvalidOperationMask = %10000000;
+  OverflowMask         = %01000000;
+  UnderflowMask        = %00100000;
+  ZeroDivideMask       = %00010000;
+  InexactMask          = %00001000;
+
+{$ifndef aix}
+
+const
+  FP_RND_RZ = 1;
+  FP_RND_RN = 0;
+  FP_RND_RP = 2;
+  FP_RND_RM = 3;
+  FP_RND_SHIFT = 28;
+  FP_RND_MASK = 3;
+
+procedure fpc_setup_fpu;
+var
+  cw: TNativeFPUControlWord;
+begin
+  asm
+    { clear all "exception happened" flags we care about}
+    mtfsfi 0,0
+    mtfsfi 1,0
+    mtfsfi 2,0
+    mtfsfi 3,0
+    mtfsb0 21
+    mtfsb0 22
+    mtfsb0 23
+  end;
+  cw:=GetNativeFPUControlWord;
+  cw:=(cw and not(OverflowMask or UnderflowMask or InexactMask or (FP_RND_MASK shl FP_RND_SHIFT))) or InvalidOperationMask or ZeroDivideMask or (FP_RND_RN shl FP_RND_SHIFT);
+  SetNativeFPUControlWord(cw);
+end;
+
+
+function fpc_get_ppc_fpscr: TNativeFPUControlWord;
+assembler;
+var
+  temp: record a,b:longint; end;
+asm
+  mffs f0
+  stfd f0,temp
+  lwz  r3,temp.b
+end;
+
+procedure fpc_set_ppc_fpsrc(cw: TNativeFPUControlWord);
+var
+  cwtemp: qword;
+begin
+  DefaultFPUControlWord:=cw;
+  cwtemp:=cw;
+  asm
+    lfd f0, cwtemp
+    mtfsf 255, f0
+  end
+end;
+{$else aix}
+const
+  FP_RND_RZ = 0;
+  FP_RND_RN = 1;
+  FP_RND_RP = 2;
+  FP_RND_RM = 3;
+
+  FP_TRAP_SYNC         =  1;       { precise trapping on }
+  FP_TRAP_OFF          =  0;       { trapping off        }
+  FP_TRAP_QUERY        =  2;       { query trapping mode }
+  FP_TRAP_IMP          =  3;       { non-recoverable imprecise trapping on }
+  FP_TRAP_IMP_REC      =  4;       { recoverable imprecise trapping on }
+  FP_TRAP_FASTMODE     =  128;     { select fastest available mode }
+  FP_TRAP_ERROR        = -1;       { error condition }
+  FP_TRAP_UNIMPL       = -2;       { requested mode not available }
+
+function fp_is_enabled(Mask: DWord): boolean;cdecl;external;
+procedure fp_enable(Mask: DWord);cdecl;external;
+function feclearexcept(Mask: DWord):DWord;cdecl;external;
+procedure fp_disable(Mask: DWord);cdecl;external;
+function fp_read_rnd: word;cdecl;external;
+function fp_swap_rnd(RoundMode: word): word;cdecl;external;
+function fp_trap(flag: longint): longint;cdecl; external;
+
+procedure fpc_setup_fpu;
+var
+  cw: TNativeFPUControlWord;
+begin
+  feclearexcept(InvalidOperationMask or OverflowMask or UnderflowMask or ZeroDivideMask or InexactMask);
+  if fp_trap(FP_TRAP_SYNC)<0 then
+    fp_trap(FP_TRAP_IMP_REC);
+  cw:=GetNativeFPUControlWord;
+  cw.rndmode:=FP_RND_RN;
+  cw.exceptionmask:=InvalidOperationMask or ZeroDivideMask;
+  SetNativeFPUControlWord(cw);
+end;
+
+
+function fpc_get_ppc_fpscr: TNativeFPUControlWord;
+begin
+  result.rndmode:=fp_read_rnd;
+  result.exceptionmask:=0;
+  if not fp_is_enabled(InvalidOperationMask) then
+    result.exceptionmask:=result.exceptionmask or InvalidOperationMask;
+  if not fp_is_enabled(OverflowMask) then
+    result.exceptionmask:=result.exceptionmask or OverflowMask;
+  if not fp_is_enabled(UnderflowMask) then
+    result.exceptionmask:=result.exceptionmask or UnderflowMask;
+  if not fp_is_enabled(InvalidOperationMask) then
+    result.exceptionmask:=result.exceptionmask or ZeroDivideMask;
+  if not fp_is_enabled(InexactMask) then
+    result.exceptionmask:=result.exceptionmask or InexactMask;
+end;
+
+
+procedure fpc_set_ppc_fpsrc(cw: TNativeFPUControlWord);
+var
+  enablemask, disablemask: dword;
+begin
+  fp_swap_rnd(cw.rndmode);
+  enablemask:=0;
+  disablemask:=0;
+  if (cw.exceptionmask and InvalidOperationMask)<>0 then
+    disablemask:=disablemask or InvalidOperationMask
+  else
+    enablemask:=enablemask or InvalidOperationMask;
+  if (cw.exceptionmask and OverflowMask)<>0 then
+    disablemask:=disablemask or OverflowMask
+  else
+    enablemask:=enablemask or OverflowMask;
+  if (cw.exceptionmask and UnderflowMask)<>0 then
+    disablemask:=disablemask or UnderflowMask
+  else
+    enablemask:=enablemask or UnderflowMask;
+  if (cw.exceptionmask and ZeroDivideMask)<>0 then
+    disablemask:=disablemask or ZeroDivideMask
+  else
+    enablemask:=enablemask or ZeroDivideMask;
+  if (cw.exceptionmask and InexactMask)<>0 then
+    disablemask:=disablemask or InexactMask
+  else
+    enablemask:=enablemask or InexactMask;
+  fp_enable(enablemask);
+  fp_disable(disablemask);
+  DefaultFPUControlWord:=cw;
+end;
+{$endif}
+
+
+function GetNativeFPUControlWord: TNativeFPUControlWord; {$if defined(SYSTEMINLINE)}inline;{$endif}
+  begin
+    result:=fpc_get_ppc_fpscr;
+  end;
+
+
+procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord); {$if defined(SYSTEMINLINE)}inline;{$endif}
+  begin
+    fpc_set_ppc_fpsrc(cw);
+  end;
+
+
+{$define FPC_SYSTEM_HAS_SYSINITFPU}
+procedure SysInitFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
+begin
+  { powerpc might use softfloat code }
+  softfloat_exception_flags:=[];
+  softfloat_exception_mask:=[float_flag_underflow, float_flag_overflow, float_flag_inexact, float_flag_denormal];
+  fpc_setup_fpu;
+end;
+{$endif NOT FPU_NONE}

+ 186 - 0
rtl/ppcgen/ppcmathu.inc

@@ -0,0 +1,186 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2005 by Thomas Schatzl
+    member of the Free Pascal development team
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+const
+  RoundModeMask        = %00000011;
+  NonIEEEModeMask      = %00000100;
+
+  InvalidOperationMask = %10000000;
+  OverflowMask         = %01000000;
+  UnderflowMask        = %00100000;
+  ZeroDivideMask       = %00010000;
+  InexactMask          = %00001000;
+  AllExceptionsMask    = %11111000;
+  ExceptionsPendingMask = %11111111111111100000011100000000;
+
+  ExceptionMask        = InvalidOperationMask or OverflowMask or UnderflowMask or ZeroDivideMask or InexactMask;
+
+  AllConfigBits        = ExceptionMask or NonIEEEModeMask or RoundModeMask;
+
+{$ifdef aix}
+const
+  FP_RND_RZ = 0;
+  FP_RND_RN = 1;
+  FP_RND_RP = 2;
+  FP_RND_RM = 3;
+
+function feclearexcept(Mask: DWord):DWord;cdecl;external;
+
+{$else aix}
+const
+  FP_RND_RZ = 1;
+  FP_RND_RN = 0;
+  FP_RND_RP = 2;
+  FP_RND_RM = 3;
+{$endif aix}
+
+function GetRoundMode: TFPURoundingMode;
+begin
+{$ifndef aix}
+  case GetNativeFPUControlWord and RoundModeMask of
+{$else not aix}
+  case GetNativeFPUControlWord.rndmode of
+{$endif not aix}
+    FP_RND_RN : result := rmNearest;
+    FP_RND_RZ : result := rmTruncate;
+    FP_RND_RP : result := rmUp;
+    FP_RND_RM : result := rmDown;
+  end;
+end;
+
+function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
+var
+  mode : DWord;
+  currentcw: TNativeFPUControlWord;
+begin
+  softfloat_rounding_mode:=RoundMode;
+  case (RoundMode) of
+    rmNearest :
+      begin
+        mode := FP_RND_RN;
+      end;
+    rmTruncate :
+      begin
+        mode := FP_RND_RZ;
+      end;
+    rmUp :
+      begin
+        mode := FP_RND_RP;
+      end;
+    rmDown :
+      begin
+        mode := FP_RND_RM;
+      end;
+  end;
+  result := GetRoundMode;
+  currentcw:=GetNativeFPUControlWord;
+{$ifndef aix}
+  SetNativeFPUControlWord((currentcw and (not RoundModeMask)) or mode);
+{$else not aix}
+  currentcw.rndmode:=mode;
+  SetNativeFPUControlWord(currentcw);
+{$endif not aix}
+end;
+
+
+function GetPrecisionMode: TFPUPrecisionMode;
+begin
+  result := pmDouble;
+end;
+
+function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode;
+begin
+  { nothing to do, not supported }
+  result := pmDouble;
+end;
+
+
+function GetExceptionMask: TFPUExceptionMask;
+var
+  currentExceptionMask: cardinal;
+begin
+  result := [];
+{$ifndef aix}
+  currentExceptionMask:=GetNativeFPUControlWord;
+{$else}
+  currentExceptionMask:=GetNativeFPUControlWord.exceptionmask;
+{$endif}
+  if ((currentExceptionMask and InvalidOperationMask) = 0) then
+    result := result + [exInvalidOp];
+  if ((currentExceptionMask and OverflowMask) = 0) then
+    result := result + [exOverflow];
+  if ((currentExceptionMask and UnderflowMask) = 0) then
+    result := result + [exUnderflow];
+  if ((currentExceptionMask and ZeroDivideMask) = 0) then
+    result := result + [exZeroDivide];
+  if ((currentExceptionMask and InexactMask) = 0) then
+    result := result + [exPrecision];
+end;
+
+function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
+var
+  mode : DWord;
+  currentcw: TNativeFPUControlWord;
+begin
+  mode := 0;
+  softfloat_exception_mask := mask;
+  if (exInvalidOp in Mask) then
+    begin
+      mode := mode or InvalidOperationMask;
+    end;
+  if (exOverflow in Mask) then
+    begin
+      mode := mode or OverflowMask;
+    end;
+  if (exUnderflow in Mask) then
+    begin
+      mode := mode or UnderflowMask;
+    end;
+  if (exZeroDivide in Mask) then
+    begin
+      mode := mode or ZeroDivideMask;
+    end;
+  if (exPrecision in Mask) then
+    begin
+      mode := mode or InexactMask;
+    end;
+
+  softfloat_exception_flags := [];
+  currentcw:=GetNativeFPUControlWord;
+{$ifdef aix}
+  currentcw.exceptionmask:=mode;
+{$else}
+  currentcw:=(currentcw or ExceptionMask) and not mode and not ExceptionsPendingMask;
+{$endif}
+  SetNativeFPUControlWord(currentcw);
+  { also clear out pending exceptions on AIX }
+{$ifdef aix}
+  { clear pending exceptions }
+  feclearexcept(AllExceptionsMask);
+{$endif}
+  result := Mask - [exDenormalized];
+end;
+
+
+procedure ClearExceptions(RaisePending: Boolean = true);
+begin
+{$ifdef aix}
+  { clear pending exceptions }
+  feclearexcept(AllExceptionsMask);
+{$else}
+  { RaisePending has no effect on PPC, always raises them at the correct location }
+  SetNativeFPUControlWord(GetNativeFPUControlWord and (not ExceptionsPendingMask));
+{$endif}
+  softfloat_exception_flags := [];
+end;

+ 39 - 7
rtl/riscv/riscv.inc

@@ -33,9 +33,46 @@ function getfflags: sizeuint; nostackframe; assembler;
   end;
   end;
 
 
 
 
-procedure setfflags(flags : sizeuint); nostackframe; assembler;
+procedure setfflags(flags : sizeuint);
+  begin
+    DefaultFPUControlWord.cw:=flags;
+    asm
+{$ifdef cpuriscv32}
+      lw a0, flags
+{$else}
+      ld a0, flags
+{$endif}
+      fsflags a0
+    end;
+  end;
+
+function getrm: dword; nostackframe; assembler;
   asm
   asm
-    fsflags a0
+    frrm a0
+  end;
+
+
+procedure setrm(val: dword);
+begin
+  DefaultFPUControlWord.cw:=val;
+  asm
+    lw a0, val
+    fsrm a0
+  end;
+end;
+
+
+function GetNativeFPUControlWord: TNativeFPUControlWord; {$if defined(SYSTEMINLINE)}inline;{$endif}
+  begin
+    result.cw:=getfflags;
+    result.rndmode:=getrm;
+  end;
+
+
+procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord); {$if defined(SYSTEMINLINE)}inline;{$endif}
+  begin
+    setfflags(cw.cw);
+    setrm(cw.rndmode);
   end;
   end;
 
 
 
 
@@ -82,8 +119,3 @@ procedure fpc_throwfpuexception;[public,alias:'FPC_THROWFPUEXCEPTION'];
       RaisePendingExceptions;
       RaisePendingExceptions;
   end;
   end;
 {$endif FPUFD}
 {$endif FPUFD}
-
-procedure fpc_cpuinit;{$ifdef SYSTEMINLINE}inline;{$endif}
-  begin
-    softfloat_exception_mask:=[exPrecision,exUnderflow];
-  end;

+ 10 - 0
rtl/riscv32/cpuh.inc

@@ -13,3 +13,13 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 
  **********************************************************************}
  **********************************************************************}
+
+{$ifdef FPUFD}
+type
+  TNativeFPUControlWord = record
+    cw: sizeuint;
+    rndmode: dword;
+  end;
+{$else}
+  {$define FPC_SYSTEM_FPUCW_IMMUTABLE}
+{$endif}

+ 20 - 0
rtl/riscv32/riscv32.inc

@@ -79,3 +79,23 @@ function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint
     inc(Target,Source);
     inc(Target,Source);
   end;
   end;
 
 
+{$define FPC_SYSTEM_HAS_SYSRESETFPU}
+procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
+{$ifdef FPUFD}
+var
+  cw: TNativeFPUControlWord;
+{$endif}
+begin
+  softfloat_exception_flags:=[];
+  softfloat_exception_mask:=[exPrecision,exUnderflow];
+{$ifdef FPUFD}
+  cw:=GetNativeFPUControlWord;
+  { riscv does not support triggering exceptoins when FPU exceptions happen;
+    it merely records which exceptions have happened until now -> clear }
+  cw.cw:=0;
+  { round to nearest }
+  cw.rndmode:=0;
+  SetNativeFPUControlWord(cw);
+{$endif}
+end;
+

+ 10 - 0
rtl/riscv64/cpuh.inc

@@ -13,3 +13,13 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 
  **********************************************************************}
  **********************************************************************}
+
+{$ifdef FPUFD}
+type
+  TNativeFPUControlWord = record
+    cw: sizeuint;
+    rndmode: dword;
+  end;
+{$else}
+  {$define FPC_SYSTEM_FPUCW_IMMUTABLE}
+{$endif}

+ 12 - 28
rtl/riscv64/mathu.inc

@@ -13,45 +13,25 @@
 **********************************************************************}
 **********************************************************************}
 
 
 {$ifdef FPUFD}
 {$ifdef FPUFD}
-function getrm: dword; nostackframe; assembler;
-  asm
-    frrm a0
-  end;
-
-
-procedure setrm(val: dword); nostackframe; assembler;
-  asm
-    fsrm a0
-  end;
-
-
-function getfflags: dword; nostackframe; assembler;
-  asm
-    frflags a0
-  end;
-
-
-procedure setfflags(flags : dword); nostackframe; assembler;
-  asm
-    fsflags a0
-  end;
-
-
 function GetRoundMode: TFPURoundingMode;
 function GetRoundMode: TFPURoundingMode;
   const
   const
     bits2rm: array[0..3] of TFPURoundingMode = (rmNearest,rmTruncate,rmDown,rmUp);
     bits2rm: array[0..3] of TFPURoundingMode = (rmNearest,rmTruncate,rmDown,rmUp);
   begin
   begin
-    result:=TFPURoundingMode(bits2rm[getrm])
+    result:=TFPURoundingMode(bits2rm[GetNativeFPUControlWord.rndmode])
   end;
   end;
 
 
 
 
 function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
 function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
   const
   const
     rm2bits : array[TFPURoundingMode] of byte = (0,2,3,1);
     rm2bits : array[TFPURoundingMode] of byte = (0,2,3,1);
+  var
+    cw: TNativeFPUControlWord;
   begin
   begin
     softfloat_rounding_mode:=RoundMode;
     softfloat_rounding_mode:=RoundMode;
     SetRoundMode:=GetRoundMode;
     SetRoundMode:=GetRoundMode;
-    setrm(rm2bits[RoundMode]);
+    cw:=GetNativeFPUControlWord;
+    cw.rndmode:=rm2bits[RoundMode];
+    SetNativeFPUControlWord(cw);
   end;
   end;
 
 
 
 
@@ -94,7 +74,7 @@ procedure RaisePendingExceptions;
     fflags : dword;
     fflags : dword;
     f: TFPUException;
     f: TFPUException;
   begin
   begin
-    fflags:=getfflags;
+    fflags:=GetNativeFPUControlWord.cw;
     if (fflags and fpu_dz) <> 0 then
     if (fflags and fpu_dz) <> 0 then
       float_raise(exZeroDivide);
       float_raise(exZeroDivide);
     if (fflags and fpu_of) <> 0 then
     if (fflags and fpu_of) <> 0 then
@@ -112,11 +92,15 @@ procedure RaisePendingExceptions;
 
 
 
 
 procedure ClearExceptions(RaisePending: Boolean);
 procedure ClearExceptions(RaisePending: Boolean);
+  var
+    cw: TNativeFPUControlWord;
   begin
   begin
     if raisepending then
     if raisepending then
       RaisePendingExceptions;
       RaisePendingExceptions;
     softfloat_exception_flags:=[];
     softfloat_exception_flags:=[];
-    setfflags(0);
+    cw:=GetNativeFPUControlWord;
+    cw.cw:=0;
+    SetNativeFPUControlWord(cw);
   end;
   end;
 {$else}
 {$else}
 function GetRoundMode: TFPURoundingMode;
 function GetRoundMode: TFPURoundingMode;

+ 20 - 0
rtl/riscv64/riscv64.inc

@@ -252,3 +252,23 @@ procedure WriteBarrier; assembler; nostackframe;
   asm
   asm
     fence ow, ow
     fence ow, ow
   end;
   end;
+
+{$define FPC_SYSTEM_HAS_SYSRESETFPU}
+procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
+{$ifdef FPUFD}
+var
+  cw: TNativeFPUControlWord;
+{$endif}
+begin
+  softfloat_exception_flags:=[];
+  softfloat_exception_mask:=[exPrecision,exUnderflow];
+{$ifdef FPUFD}
+  cw:=GetNativeFPUControlWord;
+  { riscv does not support triggering exceptoins when FPU exceptions happen;
+    it merely records which exceptions have happened until now -> clear }
+  cw.cw:=0;
+  { round to nearest }
+  cw.rndmode:=0;
+  SetNativeFPUControlWord(cw);
+{$endif}
+end;

+ 3 - 0
rtl/sparc/cpuh.inc

@@ -13,3 +13,6 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 
  **********************************************************************}
  **********************************************************************}
+
+type
+  TNativeFPUControlWord = dword;

+ 10 - 15
rtl/sparc/mathu.inc

@@ -12,16 +12,11 @@
 
 
  **********************************************************************}
  **********************************************************************}
 
 
-{ exported by the system unit }
-function get_fsr : dword;external name 'FPC_GETFSR';
-procedure set_fsr(fsr : dword);external name 'FPC_SETFSR';
-
-
 function GetRoundMode: TFPURoundingMode;
 function GetRoundMode: TFPURoundingMode;
   const
   const
     bits2rm: array[0..3] of TFPURoundingMode = (rmNearest,rmTruncate,rmUp,rmDown);
     bits2rm: array[0..3] of TFPURoundingMode = (rmNearest,rmTruncate,rmUp,rmDown);
   begin
   begin
-    result:=TFPURoundingMode(bits2rm[(get_fsr shr 30) and 3])
+    result:=TFPURoundingMode(bits2rm[(GetNativeFPUControlWord shr 30) and 3])
   end;
   end;
 
 
 
 
@@ -29,12 +24,12 @@ function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
   const
   const
     rm2bits: array[TFPURoundingMode] of byte = (0,3,2,1);
     rm2bits: array[TFPURoundingMode] of byte = (0,3,2,1);
   var
   var
-    cw: dword;
+    cw: TNativeFPUControlWord;
   begin
   begin
-    cw:=get_fsr;
+    cw:=GetNativeFPUControlWord;
     softfloat_rounding_mode:=RoundMode;
     softfloat_rounding_mode:=RoundMode;
     result:=TFPURoundingMode(cw shr 30);
     result:=TFPURoundingMode(cw shr 30);
-    set_fsr((cw and $3fffffff) or (rm2bits[RoundMode] shl 30));
+    SetNativeFPUControlWord((cw and $3fffffff) or (rm2bits[RoundMode] shl 30));
   end;
   end;
 
 
 function GetPrecisionMode: TFPUPrecisionMode;
 function GetPrecisionMode: TFPUPrecisionMode;
@@ -49,7 +44,7 @@ function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode
   end;
   end;
 
 
 
 
-function FSR2ExceptionMask(fsr: dword): TFPUExceptionMask;
+function FSR2ExceptionMask(fsr: TNativeFPUControlWord): TFPUExceptionMask;
   begin
   begin
     result:=[];
     result:=[];
     { invalid operation: bit 27 }
     { invalid operation: bit 27 }
@@ -76,15 +71,15 @@ function FSR2ExceptionMask(fsr: dword): TFPUExceptionMask;
 
 
 function GetExceptionMask: TFPUExceptionMask;
 function GetExceptionMask: TFPUExceptionMask;
   begin
   begin
-    result:=FSR2ExceptionMask(get_fsr);
+    result:=FSR2ExceptionMask(GetNativeFPUControlWord);
   end;
   end;
 
 
 
 
 function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
 function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
   var
   var
-    fsr : dword;
+    fsr : TNativeFPUControlWord;
   begin
   begin
-    fsr:=get_fsr;
+    fsr:=GetNativeFPUControlWord;
     result:=FSR2ExceptionMask(fsr);
     result:=FSR2ExceptionMask(fsr);
 
 
     { invalid operation: bit 27 }
     { invalid operation: bit 27 }
@@ -118,12 +113,12 @@ function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
       fsr:=fsr or (1 shl 23);
       fsr:=fsr or (1 shl 23);
 
 
     { update control register contents }
     { update control register contents }
-    set_fsr(fsr);
+    SetNativeFPUControlWord(fsr);
   end;
   end;
 
 
 
 
 procedure ClearExceptions(RaisePending: Boolean =true);
 procedure ClearExceptions(RaisePending: Boolean =true);
   begin
   begin
-    set_fsr(get_fsr and $fffffc1f);
+    SetNativeFPUControlWord(GetNativeFPUControlWord and $fffffc1f);
   end;
   end;
 
 

+ 20 - 20
rtl/sparc/sparc.inc

@@ -29,13 +29,24 @@ function get_fsr : dword;assembler;[public, alias: 'FPC_GETFSR'];
   end;
   end;
 
 
 
 
-procedure set_fsr(fsr : dword);assembler;[public, alias: 'FPC_SETFSR'];
-  var
-    _fsr : dword;
-  asm
-    // force memory location
-    st fsr,_fsr
-    ld _fsr,%fsr
+procedure set_fsr(fsr : dword);[public, alias: 'FPC_SETFSR'];
+  begin
+    DefaultFPUControlWord:=fsr;
+    asm
+      ld fsr,%fsr
+    end;
+  end;
+
+
+function GetNativeFPUControlWord: TNativeFPUControlWord; {$if defined(SYSTEMINLINE)}inline;{$endif}
+  begin
+    result:=get_fsr;
+  end;
+
+
+procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord); {$if defined(SYSTEMINLINE)}inline;{$endif}
+  begin
+    set_fsr(cw);
   end;
   end;
 
 
 
 
@@ -52,19 +63,8 @@ Procedure SysInitFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
     { enable div by 0 and invalid operation fpu exceptions
     { enable div by 0 and invalid operation fpu exceptions
       round towards zero; ieee compliant arithmetics }
       round towards zero; ieee compliant arithmetics }
     set_fsr((get_fsr and $3fbfffff) or $09000000);
     set_fsr((get_fsr and $3fbfffff) or $09000000);
-  end;
-
-{$define FPC_SYSTEM_HAS_SYSRESETFPU}
-Procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
-  begin
-  end;
-
-
-procedure fpc_cpuinit;
-  begin
-    SysResetFPU;
-    if not(IsLibrary) then
-      SysInitFPU;
+    softfloat_exception_mask:=[float_flag_underflow,float_flag_overflow,float_flag_inexact,float_flag_denormal];
+    softfloat_exception_flags:=[];
   end;
   end;
 
 
 
 

+ 2 - 0
rtl/sparc64/cpuh.inc

@@ -16,3 +16,5 @@
  const
  const
    STACK_BIAS = 2047;
    STACK_BIAS = 2047;
 
 
+ type
+   TNativeFPUControlWord = dword;

+ 10 - 14
rtl/sparc64/mathu.inc

@@ -12,15 +12,11 @@
 
 
  **********************************************************************}
  **********************************************************************}
 
 
-{ exported by the system unit }
-function get_fsr : dword;external name 'FPC_GETFSR';
-procedure set_fsr(fsr : dword);external name 'FPC_SETFSR';
-
 function GetRoundMode: TFPURoundingMode;
 function GetRoundMode: TFPURoundingMode;
   const
   const
     bits2rm: array[0..3] of TFPURoundingMode = (rmNearest,rmTruncate,rmUp,rmDown);
     bits2rm: array[0..3] of TFPURoundingMode = (rmNearest,rmTruncate,rmUp,rmDown);
   begin
   begin
-    result:=TFPURoundingMode(bits2rm[(get_fsr shr 30) and 3])
+    result:=TFPURoundingMode(bits2rm[(GetNativeFPUControlWord shr 30) and 3])
   end;
   end;
 
 
 
 
@@ -28,12 +24,12 @@ function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
   const
   const
     rm2bits: array[TFPURoundingMode] of byte = (0,3,2,1);
     rm2bits: array[TFPURoundingMode] of byte = (0,3,2,1);
   var
   var
-    cw: dword;
+    cw: TNativeFPUControlWord;
   begin
   begin
-    cw:=get_fsr;
+    cw:=GetNativeFPUControlWord;
     softfloat_rounding_mode:=RoundMode;
     softfloat_rounding_mode:=RoundMode;
     result:=TFPURoundingMode(cw shr 30);
     result:=TFPURoundingMode(cw shr 30);
-    set_fsr((cw and $3fffffff) or (rm2bits[RoundMode] shl 30));
+    SetNativeFPUControlWord((cw and $3fffffff) or (rm2bits[RoundMode] shl 30));
   end;
   end;
 
 
 
 
@@ -49,7 +45,7 @@ function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode
   end;
   end;
 
 
 
 
-function FSR2ExceptionMask(fsr: dword): TFPUExceptionMask;
+function FSR2ExceptionMask(fsr: TNativeFPUControlWord): TFPUExceptionMask;
   begin
   begin
     result:=[];
     result:=[];
     { invalid operation: bit 27 }
     { invalid operation: bit 27 }
@@ -76,15 +72,15 @@ function FSR2ExceptionMask(fsr: dword): TFPUExceptionMask;
 
 
 function GetExceptionMask: TFPUExceptionMask;
 function GetExceptionMask: TFPUExceptionMask;
   begin
   begin
-    result:=FSR2ExceptionMask(get_fsr);
+    result:=FSR2ExceptionMask(GetNativeFPUControlWord);
   end;
   end;
 
 
 
 
 function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
 function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
   var
   var
-    fsr : dword;
+    fsr : TNativeFPUControlWord;
   begin
   begin
-    fsr:=get_fsr;
+    fsr:=GetNativeFPUControlWord;
     result:=FSR2ExceptionMask(fsr);
     result:=FSR2ExceptionMask(fsr);
 
 
     { invalid operation: bit 27 }
     { invalid operation: bit 27 }
@@ -118,12 +114,12 @@ function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
       fsr:=fsr or (1 shl 23);
       fsr:=fsr or (1 shl 23);
 
 
     { update control register contents }
     { update control register contents }
-    set_fsr(fsr);
+    SetNativeFPUControlWord(fsr);
   end;
   end;
 
 
 
 
 procedure ClearExceptions(RaisePending: Boolean =true);
 procedure ClearExceptions(RaisePending: Boolean =true);
   begin
   begin
-    set_fsr(get_fsr and $fffffc1f);
+    SetNativeFPUControlWord(GetNativeFPUControlWord and $fffffc1f);
   end;
   end;
 
 

+ 20 - 20
rtl/sparc64/sparc64.inc

@@ -29,13 +29,24 @@ function get_fsr : dword;assembler;[public, alias: 'FPC_GETFSR'];
   end;
   end;
 
 
 
 
-procedure set_fsr(fsr : dword);assembler;[public, alias: 'FPC_SETFSR'];
-  var
-    _fsr : dword;
-  asm
-    // force memory location
-    st fsr,_fsr
-    ld _fsr,%fsr
+procedure set_fsr(fsr : dword);[public, alias: 'FPC_SETFSR'];
+  begin
+    DefaultFPUControlWord:=fsr;
+    asm
+      ld fsr,%fsr
+    end;
+  end;
+
+
+function GetNativeFPUControlWord: TNativeFPUControlWord; {$if defined(SYSTEMINLINE)}inline;{$endif}
+  begin
+    result:=get_fsr;
+  end;
+
+
+procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord); {$if defined(SYSTEMINLINE)}inline;{$endif}
+  begin
+    set_fsr(cw);
   end;
   end;
 
 
 
 
@@ -52,19 +63,8 @@ Procedure SysInitFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
     { enable div by 0 and invalid operation fpu exceptions
     { enable div by 0 and invalid operation fpu exceptions
       round towards zero; ieee compliant arithmetics }
       round towards zero; ieee compliant arithmetics }
     set_fsr((get_fsr and $3fbfffff) or $09000000);
     set_fsr((get_fsr and $3fbfffff) or $09000000);
-  end;
-
-{$define FPC_SYSTEM_HAS_SYSRESETFPU}
-Procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
-  begin
-  end;
-
-
-procedure fpc_cpuinit;
-  begin
-    SysResetFPU;
-    if not(IsLibrary) then
-      SysInitFPU;
+    softfloat_exception_mask:=[float_flag_overflow,float_flag_underflow,float_flag_inexact,float_flag_denormal];
+    softfloat_exception_flags:=[];
   end;
   end;
 
 
 
 

+ 2 - 0
rtl/wasm32/cpuh.inc

@@ -14,6 +14,8 @@
 
 
  **********************************************************************}
  **********************************************************************}
 
 
+{$define FPC_SYSTEM_FPUCW_IMMUTABLE}
+
 const
 const
   {$I cpuinnr.inc}
   {$I cpuinnr.inc}
 
 

+ 1 - 0
rtl/wasm32/wasm32.inc

@@ -19,6 +19,7 @@
 procedure fpc_wasm32_init_tls(memory: Pointer);external name '__wasm_init_tls';
 procedure fpc_wasm32_init_tls(memory: Pointer);external name '__wasm_init_tls';
 {$endif FPC_WASM_THREADS}
 {$endif FPC_WASM_THREADS}
 
 
+{$define FPC_SYSTEM_HAS_FPC_CPUINIT}
 procedure fpc_cpuinit;
 procedure fpc_cpuinit;
   begin
   begin
   end;
   end;

+ 6 - 0
rtl/x86_64/cpuh.inc

@@ -37,3 +37,9 @@ function fpc_x86_get_gs:longint;[internproc:fpc_in_x86_get_gs];
 { do not active yet, they are not usable yet neither is the naming fixed }
 { do not active yet, they are not usable yet neither is the naming fixed }
 { $i cpummprocs.inc}
 { $i cpummprocs.inc}
 {$endif not VER3_0 and not VER3_2}
 {$endif not VER3_0 and not VER3_2}
+
+type
+  TNativeFPUControlWord = record
+    cw8087: word;
+    MXCSR: dword;
+  end;

+ 18 - 4
rtl/x86_64/math.inc

@@ -95,10 +95,24 @@ const
       end;
       end;
 
 
 
 
-    procedure SetSSECSR(w : dword);
-      begin
-        SetMXCSR(w);
-      end;
+      function GetNativeFPUControlWord: TNativeFPUControlWord; {$if defined(SYSTEMINLINE)}inline;{$endif}
+        begin
+          result.cw8087:=Get8087CW;
+          result.MXCSR:=GetMXCSR
+        end;
+
+
+      procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord); {$if defined(SYSTEMINLINE)}inline;{$endif}
+        begin
+          Set8087CW(cw.cw8087);
+          SetMXCSR(cw.MXCSR);
+        end;
+
+
+      procedure SetSSECSR(w : dword);
+        begin
+          SetMXCSR(w);
+        end;
 
 
 
 
     function GetSSECSR: dword;
     function GetSSECSR: dword;

+ 1 - 0
rtl/x86_64/x86_64.inc

@@ -962,6 +962,7 @@ const
   MM_MaskUnderflow = %0000100000000000;
   MM_MaskUnderflow = %0000100000000000;
   MM_MaskPrecision = %0001000000000000;
   MM_MaskPrecision = %0001000000000000;
 
 
+{$define FPC_SYSTEM_HAS_FPC_CPUINIT}
 procedure fpc_cpuinit;
 procedure fpc_cpuinit;
   begin
   begin
     { don't let libraries influence the FPU cw set by the host program }
     { don't let libraries influence the FPU cw set by the host program }

+ 3 - 0
rtl/xtensa/cpuh.inc

@@ -13,3 +13,6 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 
  **********************************************************************}
  **********************************************************************}
+
+{ no hardware fpu }
+{$define FPC_SYSTEM_FPUCW_IMMUTABLE}

+ 3 - 7
rtl/xtensa/xtensa.inc

@@ -17,18 +17,14 @@
 {$define FPC_SYSTEM_HAS_SYSRESETFPU}
 {$define FPC_SYSTEM_HAS_SYSRESETFPU}
 Procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
 Procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
 begin
 begin
+  softfloat_exception_flags:=[];
 end;
 end;
 
 
 {$define FPC_SYSTEM_HAS_SYSINITFPU}
 {$define FPC_SYSTEM_HAS_SYSINITFPU}
 Procedure SysInitFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
 Procedure SysInitFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
 begin
 begin
-end;
-
-procedure fpc_cpuinit;
-begin
-  { don't let libraries influence the FPU cw set by the host program }
-  if not IsLibrary then
-    SysInitFPU;
+  softfloat_exception_mask:=[float_flag_underflow,float_flag_inexact,float_flag_denormal];
+  softfloat_exception_flags:=[];
 end;
 end;
 
 
 {$ifdef fpc_abi_windowed}
 {$ifdef fpc_abi_windowed}

+ 4 - 0
rtl/z80/cpuh.inc

@@ -14,6 +14,10 @@
 
 
  **********************************************************************}
  **********************************************************************}
 
 
+{$ifndef FPUNONE}
+{$define FPC_SYSTEM_FPUCW_IMMUTABLE}
+{$endif}
+
 const
 const
   {$I cpuinnr.inc}
   {$I cpuinnr.inc}
 
 

+ 1 - 0
rtl/z80/z80.inc

@@ -19,6 +19,7 @@
 var
 var
   z80_save_hl: Word; public name 'FPC_Z80_SAVE_HL';
   z80_save_hl: Word; public name 'FPC_Z80_SAVE_HL';
 
 
+{$define FPC_SYSTEM_HAS_FPC_CPUINIT}
 procedure fpc_cpuinit;{$ifdef SYSTEMINLINE}inline;{$endif}
 procedure fpc_cpuinit;{$ifdef SYSTEMINLINE}inline;{$endif}
   begin
   begin
   end;
   end;

+ 84 - 0
tests/webtbs/tw38230.pp

@@ -0,0 +1,84 @@
+{$mode objfpc}
+
+uses
+  {$ifdef unix}cthreads,{$endif} math, classes;
+
+type
+  tmythread = class(tthread)
+    constructor create; reintroduce;
+    procedure execute; override;
+  end;
+
+  tmychildthread = class(tmythread)
+    procedure execute; override;
+  end;
+
+var
+  e: TFPUException;
+  expectedfpumask: tfpuexceptionmask;
+
+constructor tmythread.create;
+  begin
+    inherited create(true);
+  end;
+
+procedure tmythread.execute;
+  var
+    e: TFPUException;
+  begin
+    write('thread: ');
+    for e in GetExceptionMask do
+      write(e,', ');
+    writeln;
+    if GetExceptionMask<>expectedfpumask then
+      begin
+        writeln(hexstr(cardinal(GetExceptionMask),8));
+        writeln(hexstr(cardinal(expectedfpumask),8));
+        halt(1);
+      end;
+    with tmychildthread.create do
+      begin
+        start;
+        waitfor;
+        free;
+        SetExceptionMask([ExDenormalized]);
+        // in case custom masks are not supported, get the actual new mask
+        expectedfpumask:=GetExceptionMask;
+        write('after setting ExDenormalized mask: ');
+        for e in expectedfpumask do
+          write(e,', ');
+        writeln;
+      end;
+  end;
+
+procedure tmychildthread.execute;
+  var
+    e: TFPUException;
+  begin
+    write('child thread: ');
+    for e in GetExceptionMask do
+      write(e,', ');
+    writeln;
+    if GetExceptionMask<>expectedfpumask then
+      halt(2);
+  end;
+
+begin
+    write('main: ');
+    for e in GetExceptionMask do
+      write(e,', ');
+    writeln;
+  expectedfpumask:=GetExceptionMask;
+  with tmythread.create do
+    begin
+      start;
+      waitfor;
+      free;
+    end;
+  with tmythread.create do
+    begin
+      start;
+      waitfor;
+      free;
+    end;
+end.