{
    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.

**********************************************************************}

{$ifdef FPUFD}
function GetRoundMode: TFPURoundingMode;
  const
    bits2rm: array[0..3] of TFPURoundingMode = (rmNearest,rmTruncate,rmDown,rmUp);
  begin
    result:=TFPURoundingMode(bits2rm[GetNativeFPUControlWord.rndmode])
  end;


function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
  const
    rm2bits : array[TFPURoundingMode] of byte = (0,2,3,1);
  var
    cw: TNativeFPUControlWord;
  begin
    softfloat_rounding_mode:=RoundMode;
    SetRoundMode:=GetRoundMode;
    cw:=GetNativeFPUControlWord;
    cw.rndmode:=rm2bits[RoundMode];
    SetNativeFPUControlWord(cw);
  end;


function GetPrecisionMode: TFPUPrecisionMode;
  begin
    result:=pmDouble;
  end;


function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode;
  begin
    result:=pmDouble;
  end;

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 GetExceptionMask: TFPUExceptionMask;
  begin
    Result:=softfloat_exception_mask;
  end;


function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
  begin
    Result:=softfloat_exception_mask;
    { clear "exception happened" flags }
    ClearExceptions(false);
    softfloat_exception_mask:=Mask;
  end;


procedure RaisePendingExceptions;
  var
    fflags : dword;
    f: TFPUException;
  begin
    fflags:=GetNativeFPUControlWord.cw;
    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);
  var
    cw: TNativeFPUControlWord;
  begin
    if raisepending then
      RaisePendingExceptions;
    softfloat_exception_flags:=[];
    cw:=GetNativeFPUControlWord;
    cw.cw:=0;
    SetNativeFPUControlWord(cw);
  end;
{$else}
function GetRoundMode: TFPURoundingMode;
  begin
    GetRoundMode:=softfloat_rounding_mode;
  end;


function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
  begin
    result:=softfloat_rounding_mode;
    softfloat_rounding_mode:=RoundMode;
  end;


function GetPrecisionMode: TFPUPrecisionMode;
  begin
    result := pmDouble;
  end;


function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode;
  begin
    { does not apply }
    result := pmDouble;
  end;


function GetExceptionMask: TFPUExceptionMask;
  begin
    Result:=softfloat_exception_mask;
  end;


function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
  begin
    Result:=softfloat_exception_mask;
    softfloat_exception_mask:=Mask;
  end;


procedure ClearExceptions(RaisePending: Boolean =true);
  begin
    softfloat_exception_flags:=[];
  end;
{$endif}