diff options
Diffstat (limited to 'riscv_new/rtl/riscv64/mathu.inc')
-rw-r--r-- | riscv_new/rtl/riscv64/mathu.inc | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/riscv_new/rtl/riscv64/mathu.inc b/riscv_new/rtl/riscv64/mathu.inc new file mode 100644 index 0000000000..74743e0a6e --- /dev/null +++ b/riscv_new/rtl/riscv64/mathu.inc @@ -0,0 +1,151 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2014 by Jonas Maebe + 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. + +**********************************************************************} + +function getfpcr: dword; nostackframe; assembler; + asm + end; + + +procedure setfpcr(val: dword); nostackframe; assembler; + asm + end; + + +function getfpsr: dword; nostackframe; assembler; + asm + end; + + +procedure setfpsr(val: dword); nostackframe; assembler; + asm + end; + + +function GetRoundMode: TFPURoundingMode; + const + bits2rm: array[0..3] of TFPURoundingMode = (rmNearest,rmUp,rmDown,rmTruncate); + begin + result:=TFPURoundingMode(bits2rm[(getfpcr shr 22) and 3]) + end; + + +function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode; + const + rm2bits: array[TFPURoundingMode] of byte = (0,2,1,3); + begin + softfloat_rounding_mode:=RoundMode; + SetRoundMode:=RoundMode; + setfpcr((getfpcr and $ff3fffff) or (rm2bits[RoundMode] shl 22)); + end; + + +function GetPrecisionMode: TFPUPrecisionMode; + begin + result:=pmDouble; + end; + + +function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode; + begin + 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; + + +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]; + 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); + { 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; + end; + + +procedure ClearExceptions(RaisePending: Boolean); + var + fpsr: dword; + f: TFPUException; + begin + fpsr:=getfpsr; + 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; + softfloat_exception_flags:=[]; + setfpsr(fpsr and not(fpu_exception_mask shr fpu_exception_mask_to_status_mask_shift)); + end; |