Browse Source

* fixed floating point exception masking support for RiscV64

git-svn-id: branches/laksen/riscv_new@39638 -
florian 7 years ago
parent
commit
203409ab48
2 changed files with 106 additions and 69 deletions
  1. 36 69
      rtl/riscv64/mathu.inc
  2. 70 0
      rtl/riscv64/riscv64.inc

+ 36 - 69
rtl/riscv64/mathu.inc

@@ -22,13 +22,15 @@ procedure setfpcr(val: dword); nostackframe; assembler;
   end;
 
 
-function getfpsr: dword; nostackframe; assembler;
+function getfflags: dword; nostackframe; assembler;
   asm
+    frflags a0
   end;
 
 
-procedure setfpsr(val: dword); nostackframe; assembler;
+procedure setfflags(flags : dword); nostackframe; assembler;
   asm
+    fsflags a0
   end;
 
 
@@ -61,91 +63,56 @@ function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode
     result:=pmDouble;
   end;
 
-
 const
-  fpu_ioe = 1 shl 8;
-  fpu_dze = 1 shl 9;
-  fpu_ofe = 1 shl 10;
-  fpu_ufe = 1 shl 11;
-  fpu_ixe = 1 shl 12;
-  fpu_ide = 1 shl 15;
-  fpu_exception_mask = fpu_ioe or fpu_dze or fpu_ofe or fpu_ufe or fpu_ixe or fpu_ide;
-  fpu_exception_mask_to_status_mask_shift = 8;
+  fpu_nx = 1 shl 0;
+  fpu_uf = 1 shl 1;
+  fpu_of = 1 shl 2;
+  fpu_dz = 1 shl 3;
+  fpu_nv = 1 shl 4;
 
 
 function GetExceptionMask: TFPUExceptionMask;
-  var
-    fpcr: dword;
   begin
-    fpcr:=getfpcr;
-    result:=[];
-    if ((fpcr and fpu_ioe)=0) then
-      result := result+[exInvalidOp];
-    if ((fpcr and fpu_ofe)=0) then
-      result := result+[exOverflow];
-    if ((fpcr and fpu_ufe)=0) then
-      result := result+[exUnderflow];
-    if ((fpcr and fpu_dze)=0) then
-      result := result+[exZeroDivide];
-    if ((fpcr and fpu_ixe)=0) then
-      result := result+[exPrecision];
-    if ((fpcr and fpu_ide)=0) then
-      result := result+[exDenormalized];
+    Result:=softfloat_exception_mask;
   end;
 
 
 function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
-  var
-    newfpcr: dword;
   begin
-    softfloat_exception_mask:=mask;
-    newfpcr:=fpu_exception_mask;
-    if exInvalidOp in Mask then
-      newfpcr:=newfpcr and not(fpu_ioe);
-    if exOverflow in Mask then
-      newfpcr:=newfpcr and not(fpu_ofe);
-    if exUnderflow in Mask then
-      newfpcr:=newfpcr and not(fpu_ufe);
-    if exZeroDivide in Mask then
-      newfpcr:=newfpcr and not(fpu_dze);
-    if exPrecision in Mask then
-      newfpcr:=newfpcr and not(fpu_ixe);
-    if exDenormalized in Mask then
-      newfpcr:=newfpcr and not(fpu_ide);
+    Result:=softfloat_exception_mask;
     { clear "exception happened" flags }
     ClearExceptions(false);
-    { set new exception mask }
-    setfpcr((getfpcr and not(fpu_exception_mask)) or newfpcr);
-    { unsupported mask bits will remain 0 -> read exception mask again }
-    result:=GetExceptionMask;
-    softfloat_exception_mask:=result;
+    softfloat_exception_mask:=Mask;
   end;
 
 
-procedure ClearExceptions(RaisePending: Boolean);
+procedure RaisePendingExceptions;
   var
-    fpsr: dword;
+    fflags : dword;
     f: TFPUException;
   begin
-    fpsr:=getfpsr;
+    fflags:=getfflags;
+    if (fflags and fpu_dz) <> 0 then
+      float_raise(exZeroDivide);
+    if (fflags and fpu_of) <> 0 then
+      float_raise(exOverflow);
+    if (fflags and fpu_uf) <> 0 then
+      float_raise(exUnderflow);
+    if (fflags and fpu_nv) <> 0 then
+      float_raise(exInvalidOp);
+    if (fflags and fpu_nx) <> 0 then
+      float_raise(exPrecision);
+    { now the soft float exceptions }
+    for f in softfloat_exception_flags do
+      float_raise(f);
+  end;
+
+
+procedure ClearExceptions(RaisePending: Boolean);
+  begin
     if raisepending then
-      begin
-        if (fpsr and (fpu_dze shr fpu_exception_mask_to_status_mask_shift)) <> 0 then
-          float_raise(exZeroDivide);
-        if (fpsr and (fpu_ofe shr fpu_exception_mask_to_status_mask_shift)) <> 0 then
-          float_raise(exOverflow);
-        if (fpsr and (fpu_ufe shr fpu_exception_mask_to_status_mask_shift)) <> 0 then
-          float_raise(exUnderflow);
-        if (fpsr and (fpu_ioe shr fpu_exception_mask_to_status_mask_shift)) <> 0 then
-          float_raise(exInvalidOp);
-        if (fpsr and (fpu_ixe shr fpu_exception_mask_to_status_mask_shift)) <> 0 then
-          float_raise(exPrecision);
-        if (fpsr and (fpu_ide shr fpu_exception_mask_to_status_mask_shift)) <> 0 then
-          float_raise(exDenormalized);
-        { now the soft float exceptions }
-        for f in  softfloat_exception_flags do
-          float_raise(f);
-      end;
+      RaisePendingExceptions;
     softfloat_exception_flags:=[];
-    setfpsr(fpsr and not(fpu_exception_mask shr fpu_exception_mask_to_status_mask_shift));
+    setfflags(0);
   end;
+

+ 70 - 0
rtl/riscv64/riscv64.inc

@@ -19,6 +19,76 @@ procedure fpc_cpuinit;{$ifdef SYSTEMINLINE}inline;{$endif}
   begin
   end;
 
+{****************************************************************************
+                       fpu exception related stuff
+****************************************************************************}
+
+const
+  fpu_nx = 1 shl 0;
+  fpu_uf = 1 shl 1;
+  fpu_of = 1 shl 2;
+  fpu_dz = 1 shl 3;
+  fpu_nv = 1 shl 4;
+
+function getfflags: dword; nostackframe; assembler;
+  asm
+    frflags a0
+  end;
+
+
+procedure setfflags(flags : dword); nostackframe; assembler;
+  asm
+    fsflags a0
+  end;
+
+
+procedure RaisePendingExceptions;
+  var
+    fflags : dword;
+    f: TFPUException;
+  begin
+    fflags:=getfflags;
+    if (fflags and fpu_dz) <> 0 then
+      float_raise(exZeroDivide);
+    if (fflags and fpu_of) <> 0 then
+      float_raise(exOverflow);
+    if (fflags and fpu_uf) <> 0 then
+      float_raise(exUnderflow);
+    if (fflags and fpu_nv) <> 0 then
+      float_raise(exInvalidOp);
+    if (fflags and fpu_nx) <> 0 then
+      float_raise(exPrecision);
+    { now the soft float exceptions }
+    for f in softfloat_exception_flags do
+      float_raise(f);
+  end;
+
+
+procedure fpc_throwfpuexception;[public,alias:'FPC_THROWFPUEXCEPTION'];
+  var
+    fflags : dword;
+  begin
+    fflags:=getfflags;
+    { check, if the exception is masked }
+    if ((fflags and fpu_dz) <> 0) and (exZeroDivide in softfloat_exception_mask) then
+      fflags:=fflags and not(fpu_dz);
+    if ((fflags and fpu_of) <> 0) and (exOverflow in softfloat_exception_mask) then
+      fflags:=fflags and not(fpu_of);
+    if ((fflags and fpu_uf) <> 0) and (exUnderflow in softfloat_exception_mask) then
+      fflags:=fflags and not(fpu_uf);
+    if ((fflags and fpu_nv) <> 0) and (exInvalidOp in softfloat_exception_mask) then
+      fflags:=fflags and not(fpu_nv);
+    if ((fflags and fpu_nx) <> 0) and (exPrecision in softfloat_exception_mask) then
+      fflags:=fflags and not(fpu_nx);
+    setfflags(fflags);
+    if fflags<>0 then
+      RaisePendingExceptions;
+  end;
+
+
+{****************************************************************************
+                       stack frame related stuff
+****************************************************************************}
 
 {$IFNDEF INTERNAL_BACKTRACE}
 {$define FPC_SYSTEM_HAS_GET_FRAME}