Browse Source

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

git-svn-id: trunk@36523 -
Károly Balogh 8 years ago
parent
commit
f1ee65610d
1 changed files with 114 additions and 1 deletions
  1. 114 1
      rtl/m68k/mathu.inc

+ 114 - 1
rtl/m68k/mathu.inc

@@ -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}