From 7e3e75f1ddd29aab06e7efbeef4bb7320d752643 Mon Sep 17 00:00:00 2001 From: florian Date: Sun, 19 Aug 2018 10:55:41 +0000 Subject: * fixed floating point exception masking support for RiscV64 git-svn-id: https://svn.freepascal.org/svn/fpc/branches/laksen@39638 3ad0048d-3df7-0310-abae-a5850022a9f2 --- riscv_new/rtl/riscv64/mathu.inc | 105 +++++++++++++------------------------- riscv_new/rtl/riscv64/riscv64.inc | 70 +++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 69 deletions(-) diff --git a/riscv_new/rtl/riscv64/mathu.inc b/riscv_new/rtl/riscv64/mathu.inc index 74743e0a6e..e76b595641 100644 --- a/riscv_new/rtl/riscv64/mathu.inc +++ b/riscv_new/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; + diff --git a/riscv_new/rtl/riscv64/riscv64.inc b/riscv_new/rtl/riscv64/riscv64.inc index 886ed4fc1b..cac65a5b85 100644 --- a/riscv_new/rtl/riscv64/riscv64.inc +++ b/riscv_new/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} -- cgit v1.2.1