123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- {
- 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.
- **********************************************************************}
- {$asmmode gas}
- function getfpcr: dword; nostackframe; assembler;
- asm
- mrs x0,fpcr
- end;
- procedure setfpcr(val: dword); nostackframe; assembler;
- asm
- msr fpcr,x0
- end;
- function getfpsr: dword; nostackframe; assembler;
- asm
- mrs x0,fpsr
- end;
- procedure setfpsr(val: dword); nostackframe; assembler;
- asm
- msr fpsr, x0
- 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
- { as I am not aware of any hardware exception supporting AArch64 implementation,
- and else the trapping enable flags are RAZ, return the softfloat exception mask (FK)
- 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];
- }
- { as the fpcr flags might be RAZ, the softfloat exception mask
- is considered as the authoritative mask }
- result:=softfloat_exception_mask;
- end;
- function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
- var
- newfpcr: dword;
- begin
- { clear "exception happened" flags }
- ClearExceptions(false);
- softfloat_exception_mask:=mask;
- { at least the ThunderX AArch64 support apperently hardware exceptions,
- so set fpcr correctly, thought it might be WI on most implementations it does not hurt
- }
- 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);
- 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;
- 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;
|