m68k: added support for setting the rounding mode on hardware FPUs

git-svn-id: trunk@36523 -
This commit is contained in:
Károly Balogh 2017-06-18 19:06:34 +00:00
parent 8a6c995b75
commit f1ee65610d

View File

@ -12,6 +12,119 @@
**********************************************************************}
{$if defined(FPU68881) or defined(FPUCOLDFIRE)}
{ 68881/2 FPCR Encodings
Rounding Mode Rounding Precision
(RND Field) Encoding (PREC Field)
To Nearest (RN) 0 0 Extend (X)
To Zero (RZ) 0 1 Single (S)
To Minus Infinity (RM) 1 0 Double (D)
To Plus Infinity (RP) 1 1 Undefined
}
{ 68881/2 FPCR layout }
{ Exception Enable Byte: }
{ 15 - BSUN - Branch/Set on Unordered }
{ 14 - SNAN - Signal Not A Number }
{ 13 - OPERR - Operand Error }
{ 12 - OVFL - Overflow }
{ 11 - UNFL - Underflow }
{ 10 - DZ - Divide by Zero }
{ 09 - INEX2 - Inexact Operation }
{ 08 - INEX1 - Inexact Decimal Input }
{ Mode Control Byte: }
{ 07 - PREC - Rounding Precision }
{ 06 - PREC - Rounding Precision }
{ 05 - RND - Rounding Mode }
{ 04 - RND - Rounding Mode }
{ 03 - 0 - Reserved, Set to zero }
{ 02 - 0 - Reserved, Set to zero }
{ 01 - 0 - Reserved, Set to zero }
{ 00 - 0 - Reserved, Set to zero }
{
Please note that the rounding mode setting via FPCR in most emulators is broken.
The list includes most versions and incarnations of UAE, MorphOS' Trance emulator,
and others. The following code was verified to work on real hardware. (KB)
}
const
FPU68K_ROUND_MASK_SHIFT = 4;
FPU68K_ROUND_MASK = 3 shl FPU68K_ROUND_MASK_SHIFT;
FPU68K_ROUND_NEAREST = 0 shl FPU68K_ROUND_MASK_SHIFT;
FPU68K_ROUND_ZERO = 1 shl FPU68K_ROUND_MASK_SHIFT;
FPU68K_ROUND_MINUSINF = 2 shl FPU68K_ROUND_MASK_SHIFT;
FPU68K_ROUND_PLUSINF = 3 shl FPU68K_ROUND_MASK_SHIFT;
const
FPU68K_PREC_MASK_SHIFT = 6;
FPU68K_PREC_MASK = 3 shl FPU68K_PREC_MASK_SHIFT;
FPU68K_PREC_EXTENDED = 0 shl FPU68K_PREC_MASK_SHIFT;
FPU68K_PREC_SINGLE = 1 shl FPU68K_PREC_MASK_SHIFT;
FPU68K_PREC_DOUBLE = 2 shl FPU68K_PREC_MASK_SHIFT;
function GetFPCR: DWord; assembler; nostackframe;
asm
fmove.l fpcr,d0
end;
function SetFPCR(x: DWord): DWord; assembler; nostackframe;
asm
fmove.l x, fpcr
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;
function GetRoundMode: TFPURoundingMode;
const
FPUToFPCRoundingMode: array[0..3] of TFPURoundingMode = ( rmNearest, rmTruncate, rmUp, rmDown );
begin
Result:=FPUToFPCRoundingMode[(GetFPCR and FPU68K_ROUND_MASK) shr FPU68K_ROUND_MASK_SHIFT];
end;
function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
const
FPCToFPURoundingMode: array[TFPURoundingMode] of DWord =
( FPU68K_ROUND_NEAREST, FPU68K_ROUND_MINUSINF, FPU68K_ROUND_PLUSINF, FPU68K_ROUND_ZERO );
var
FPCR: DWord;
begin
FPCR:=GetFPCR and not FPU68K_ROUND_MASK;
SetFPCR(FPCR or FPCToFPURoundingMode[RoundMode]);
softfloat_rounding_mode:=RoundMode;
Result:=RoundMode;
end;
function GetPrecisionMode: TFPUPrecisionMode;
begin
result:=pmDouble;
end;
function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode;
begin
result:=pmDouble;
end;
procedure ClearExceptions(RaisePending: Boolean);
begin
softfloat_exception_flags:=[];
end;
{$else}
function GetExceptionMask: TFPUExceptionMask;
begin
Result := softfloat_exception_mask;
@ -48,4 +161,4 @@ procedure ClearExceptions(RaisePending: Boolean);
begin
softfloat_exception_flags:=[];
end;
{$endif}