summaryrefslogtreecommitdiff
path: root/arch/m68k/fpsp040/x_ovfl.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/fpsp040/x_ovfl.S')
-rw-r--r--arch/m68k/fpsp040/x_ovfl.S185
1 files changed, 185 insertions, 0 deletions
diff --git a/arch/m68k/fpsp040/x_ovfl.S b/arch/m68k/fpsp040/x_ovfl.S
new file mode 100644
index 000000000..6fe4989ee
--- /dev/null
+++ b/arch/m68k/fpsp040/x_ovfl.S
@@ -0,0 +1,185 @@
+|
+| x_ovfl.sa 3.5 7/1/91
+|
+| fpsp_ovfl --- FPSP handler for overflow exception
+|
+| Overflow occurs when a floating-point intermediate result is
+| too large to be represented in a floating-point data register,
+| or when storing to memory, the contents of a floating-point
+| data register are too large to be represented in the
+| destination format.
+|
+| Trap disabled results
+|
+| If the instruction is move_out, then garbage is stored in the
+| destination. If the instruction is not move_out, then the
+| destination is not affected. For 68881 compatibility, the
+| following values should be stored at the destination, based
+| on the current rounding mode:
+|
+| RN Infinity with the sign of the intermediate result.
+| RZ Largest magnitude number, with the sign of the
+| intermediate result.
+| RM For pos overflow, the largest pos number. For neg overflow,
+| -infinity
+| RP For pos overflow, +infinity. For neg overflow, the largest
+| neg number
+|
+| Trap enabled results
+| All trap disabled code applies. In addition the exceptional
+| operand needs to be made available to the users exception handler
+| with a bias of $6000 subtracted from the exponent.
+|
+|
+
+| Copyright (C) Motorola, Inc. 1990
+| All Rights Reserved
+|
+| For details on the license for this file, please see the
+| file, README, in this same directory.
+
+X_OVFL: |idnt 2,1 | Motorola 040 Floating Point Software Package
+
+ |section 8
+
+#include "fpsp.h"
+
+ |xref ovf_r_x2
+ |xref ovf_r_x3
+ |xref store
+ |xref real_ovfl
+ |xref real_inex
+ |xref fpsp_done
+ |xref g_opcls
+ |xref b1238_fix
+
+ .global fpsp_ovfl
+fpsp_ovfl:
+ link %a6,#-LOCAL_SIZE
+ fsave -(%a7)
+ moveml %d0-%d1/%a0-%a1,USER_DA(%a6)
+ fmovemx %fp0-%fp3,USER_FP0(%a6)
+ fmoveml %fpcr/%fpsr/%fpiar,USER_FPCR(%a6)
+
+|
+| The 040 doesn't set the AINEX bit in the FPSR, the following
+| line temporarily rectifies this error.
+|
+ bsetb #ainex_bit,FPSR_AEXCEPT(%a6)
+|
+ bsrl ovf_adj |denormalize, round & store interm op
+|
+| if overflow traps not enabled check for inexact exception
+|
+ btstb #ovfl_bit,FPCR_ENABLE(%a6)
+ beqs ck_inex
+|
+ btstb #E3,E_BYTE(%a6)
+ beqs no_e3_1
+ bfextu CMDREG3B(%a6){#6:#3},%d0 |get dest reg no
+ bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit
+ bsrl b1238_fix
+ movel USER_FPSR(%a6),FPSR_SHADOW(%a6)
+ orl #sx_mask,E_BYTE(%a6)
+no_e3_1:
+ moveml USER_DA(%a6),%d0-%d1/%a0-%a1
+ fmovemx USER_FP0(%a6),%fp0-%fp3
+ fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+ frestore (%a7)+
+ unlk %a6
+ bral real_ovfl
+|
+| It is possible to have either inex2 or inex1 exceptions with the
+| ovfl. If the inex enable bit is set in the FPCR, and either
+| inex2 or inex1 occurred, we must clean up and branch to the
+| real inex handler.
+|
+ck_inex:
+| move.b FPCR_ENABLE(%a6),%d0
+| and.b FPSR_EXCEPT(%a6),%d0
+| andi.b #$3,%d0
+ btstb #inex2_bit,FPCR_ENABLE(%a6)
+ beqs ovfl_exit
+|
+| Inexact enabled and reported, and we must take an inexact exception.
+|
+take_inex:
+ btstb #E3,E_BYTE(%a6)
+ beqs no_e3_2
+ bfextu CMDREG3B(%a6){#6:#3},%d0 |get dest reg no
+ bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit
+ bsrl b1238_fix
+ movel USER_FPSR(%a6),FPSR_SHADOW(%a6)
+ orl #sx_mask,E_BYTE(%a6)
+no_e3_2:
+ moveb #INEX_VEC,EXC_VEC+1(%a6)
+ moveml USER_DA(%a6),%d0-%d1/%a0-%a1
+ fmovemx USER_FP0(%a6),%fp0-%fp3
+ fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+ frestore (%a7)+
+ unlk %a6
+ bral real_inex
+
+ovfl_exit:
+ bclrb #E3,E_BYTE(%a6) |test and clear E3 bit
+ beqs e1_set
+|
+| Clear dirty bit on dest resister in the frame before branching
+| to b1238_fix.
+|
+ bfextu CMDREG3B(%a6){#6:#3},%d0 |get dest reg no
+ bclrb %d0,FPR_DIRTY_BITS(%a6) |clr dest dirty bit
+ bsrl b1238_fix |test for bug1238 case
+
+ movel USER_FPSR(%a6),FPSR_SHADOW(%a6)
+ orl #sx_mask,E_BYTE(%a6)
+ moveml USER_DA(%a6),%d0-%d1/%a0-%a1
+ fmovemx USER_FP0(%a6),%fp0-%fp3
+ fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+ frestore (%a7)+
+ unlk %a6
+ bral fpsp_done
+e1_set:
+ moveml USER_DA(%a6),%d0-%d1/%a0-%a1
+ fmovemx USER_FP0(%a6),%fp0-%fp3
+ fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+ unlk %a6
+ bral fpsp_done
+
+|
+| ovf_adj
+|
+ovf_adj:
+|
+| Have a0 point to the correct operand.
+|
+ btstb #E3,E_BYTE(%a6) |test E3 bit
+ beqs ovf_e1
+
+ lea WBTEMP(%a6),%a0
+ bras ovf_com
+ovf_e1:
+ lea ETEMP(%a6),%a0
+
+ovf_com:
+ bclrb #sign_bit,LOCAL_EX(%a0)
+ sne LOCAL_SGN(%a0)
+
+ bsrl g_opcls |returns opclass in d0
+ cmpiw #3,%d0 |check for opclass3
+ bnes not_opc011
+
+|
+| FPSR_CC is saved and restored because ovf_r_x3 affects it. The
+| CCs are defined to be 'not affected' for the opclass3 instruction.
+|
+ moveb FPSR_CC(%a6),L_SCR1(%a6)
+ bsrl ovf_r_x3 |returns a0 pointing to result
+ moveb L_SCR1(%a6),FPSR_CC(%a6)
+ bral store |stores to memory or register
+
+not_opc011:
+ bsrl ovf_r_x2 |returns a0 pointing to result
+ bral store |stores to memory or register
+
+ |end