Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/arch/m68k/ifpsp060/src/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 743 kB image not shown  

Quelle  fpsp.S   Sprache: Sparc

 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
M68000 Hi-Performance Microprocessor Division
M68060 Software Package
Production Release P1.00 -- October 10, 1994

M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.

THE SOFTWARE is provided on an "AS IS" basis and without warranty.
To the maximum extent permitted by applicable law,
MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
and any warranty against infringement with regard to the SOFTWARE
(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.

To the maximum extent permitted by applicable law,
IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.

You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
so long as this entire notice is retained without alteration in any modified and/or
redistributed versions, and that such modified versions are clearly identified as such.
No licenses are granted by implication, estoppel or otherwise under any patents
or trademarks of Motorola, Inc.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# freal.s:
# This file is appended to the top of the 060FPSP package
# and contains the entry points into the package. The user, in
# effect, branches to one of the branch table entries located
# after _060FPSP_TABLE.
# Also, subroutine stubs exist in this file (_fpsp_done for
# example) that are referenced by the FPSP package itself in order
# to call a given routine. The stub routine actually performs the
# callout. The FPSP code does a "bsr" to the stub routine. This
# extra layer of hierarchy adds a slight performance penalty but
# it makes the FPSP code easier to read and more mainatinable.
#

set _off_bsun, 0x00
set _off_snan, 0x04
set _off_operr, 0x08
set _off_ovfl, 0x0c
set _off_unfl, 0x10
set _off_dz, 0x14
set _off_inex, 0x18
set _off_fline, 0x1c
set _off_fpu_dis, 0x20
set _off_trap, 0x24
set _off_trace, 0x28
set _off_access, 0x2c
set _off_done, 0x30

set _off_imr, 0x40
set _off_dmr, 0x44
set _off_dmw, 0x48
set _off_irw, 0x4c
set _off_irl, 0x50
set _off_drb, 0x54
set _off_drw, 0x58
set _off_drl, 0x5c
set _off_dwb, 0x60
set _off_dww, 0x64
set _off_dwl, 0x68

_060FPSP_TABLE:

###############################################################

# Here's the table of ENTRY POINTS for those linking the package.
 bra.l  _fpsp_snan
 short  0x0000
 bra.l  _fpsp_operr
 short  0x0000
 bra.l  _fpsp_ovfl
 short  0x0000
 bra.l  _fpsp_unfl
 short  0x0000
 bra.l  _fpsp_dz
 short  0x0000
 bra.l  _fpsp_inex
 short  0x0000
 bra.l  _fpsp_fline
 short  0x0000
 bra.l  _fpsp_unsupp
 short  0x0000
 bra.l  _fpsp_effadd
 short  0x0000

 space  56

###############################################################
 global  _fpsp_done
_fpsp_done:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_done,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_ovfl
_real_ovfl:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_ovfl,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_unfl
_real_unfl:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_unfl,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_inex
_real_inex:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_inex,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_bsun
_real_bsun:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_bsun,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_operr
_real_operr:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_operr,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_snan
_real_snan:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_snan,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_dz
_real_dz:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_dz,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_fline
_real_fline:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_fline,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_fpu_disabled
_real_fpu_disabled:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_fpu_dis,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_trap
_real_trap:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_trap,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_trace
_real_trace:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_trace,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_access
_real_access:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_access,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

#######################################

 global  _imem_read
_imem_read:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_imr,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _dmem_read
_dmem_read:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_dmr,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _dmem_write
_dmem_write:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_dmw,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _imem_read_word
_imem_read_word:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_irw,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _imem_read_long
_imem_read_long:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_irl,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _dmem_read_byte
_dmem_read_byte:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_drb,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _dmem_read_word
_dmem_read_word:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_drw,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _dmem_read_long
_dmem_read_long:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_drl,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _dmem_write_byte
_dmem_write_byte:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_dwb,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _dmem_write_word
_dmem_write_word:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_dww,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _dmem_write_long
_dmem_write_long:
 mov.l  %d0,-(%sp)
 mov.l  (_060FPSP_TABLE-0x80+_off_dwl,%pc),%d0
 pea.l  (_060FPSP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

#
# This file contains a set of define statements for constants
# in order to promote readability within the corecode itself.
#

set LOCAL_SIZE,  192   # stack frame size(bytes)
set LV,   -LOCAL_SIZE  # stack offset

set EXC_SR,  0x4   # stack status register
set EXC_PC,  0x6   # stack pc
set EXC_VOFF,  0xa   # stacked vector offset
set EXC_EA,  0xc   # stacked <ea>

set EXC_FP,  0x0   # frame pointer

set EXC_AREGS,  -68   # offset of all address regs
set EXC_DREGS,  -100   # offset of all data regs
set EXC_FPREGS,  -36   # offset of all fp regs

set EXC_A7,  EXC_AREGS+(7*4)  # offset of saved a7
set OLD_A7,  EXC_AREGS+(6*4)  # extra copy of saved a7
set EXC_A6,  EXC_AREGS+(6*4)  # offset of saved a6
set EXC_A5,  EXC_AREGS+(5*4)
set EXC_A4,  EXC_AREGS+(4*4)
set EXC_A3,  EXC_AREGS+(3*4)
set EXC_A2,  EXC_AREGS+(2*4)
set EXC_A1,  EXC_AREGS+(1*4)
set EXC_A0,  EXC_AREGS+(0*4)
set EXC_D7,  EXC_DREGS+(7*4)
set EXC_D6,  EXC_DREGS+(6*4)
set EXC_D5,  EXC_DREGS+(5*4)
set EXC_D4,  EXC_DREGS+(4*4)
set EXC_D3,  EXC_DREGS+(3*4)
set EXC_D2,  EXC_DREGS+(2*4)
set EXC_D1,  EXC_DREGS+(1*4)
set EXC_D0,  EXC_DREGS+(0*4)

set EXC_FP0,  EXC_FPREGS+(0*12) # offset of saved fp0
set EXC_FP1,  EXC_FPREGS+(1*12) # offset of saved fp1
set EXC_FP2,  EXC_FPREGS+(2*12) # offset of saved fp2 (not used)

set FP_SCR1,  LV+80   # fp scratch 1
set FP_SCR1_EX,  FP_SCR1+0
set FP_SCR1_SGN, FP_SCR1+2
set FP_SCR1_HI,  FP_SCR1+4
set FP_SCR1_LO,  FP_SCR1+8

set FP_SCR0,  LV+68   # fp scratch 0
set FP_SCR0_EX,  FP_SCR0+0
set FP_SCR0_SGN, FP_SCR0+2
set FP_SCR0_HI,  FP_SCR0+4
set FP_SCR0_LO,  FP_SCR0+8

set FP_DST,  LV+56   # fp destination operand
set FP_DST_EX,  FP_DST+0
set FP_DST_SGN,  FP_DST+2
set FP_DST_HI,  FP_DST+4
set FP_DST_LO,  FP_DST+8

set FP_SRC,  LV+44   # fp source operand
set FP_SRC_EX,  FP_SRC+0
set FP_SRC_SGN,  FP_SRC+2
set FP_SRC_HI,  FP_SRC+4
set FP_SRC_LO,  FP_SRC+8

set USER_FPIAR,  LV+40   # FP instr address register

set USER_FPSR,  LV+36   # FP status register
set FPSR_CC,  USER_FPSR+0  # FPSR condition codes
set FPSR_QBYTE,  USER_FPSR+1  # FPSR qoutient byte
set FPSR_EXCEPT, USER_FPSR+2  # FPSR exception status byte
set FPSR_AEXCEPT, USER_FPSR+3  # FPSR accrued exception byte

set USER_FPCR,  LV+32   # FP control register
set FPCR_ENABLE, USER_FPCR+2  # FPCR exception enable
set FPCR_MODE,  USER_FPCR+3  # FPCR rounding mode control

set L_SCR3,  LV+28   # integer scratch 3
set L_SCR2,  LV+24   # integer scratch 2
set L_SCR1,  LV+20   # integer scratch 1

set STORE_FLG,  LV+19   # flag: operand store (ie. not fcmp/ftst)

set EXC_TEMP2,  LV+24   # temporary space
set EXC_TEMP,  LV+16   # temporary space

set DTAG,  LV+15   # destination operand type
set STAG,  LV+14   # source operand type

set SPCOND_FLG,  LV+10   # flag: special case (see below)

set EXC_CC,  LV+8   # saved condition codes
set EXC_EXTWPTR, LV+4   # saved current PC (active)
set EXC_EXTWORD, LV+2   # saved extension word
set EXC_CMDREG,  LV+2   # saved extension word
set EXC_OPWORD,  LV+0   # saved operation word

################################

# Helpful macros

set FTEMP,  0   # offsets within an
set FTEMP_EX,  0   # extended precision
set FTEMP_SGN,  2   # value saved in memory.
set FTEMP_HI,  4
set FTEMP_LO,  8
set FTEMP_GRS,  12

set LOCAL,  0   # offsets within an
set LOCAL_EX,  0   # extended precision
set LOCAL_SGN,  2   # value saved in memory.
set LOCAL_HI,  4
set LOCAL_LO,  8
set LOCAL_GRS,  12

set DST,  0   # offsets within an
set DST_EX,  0   # extended precision
set DST_HI,  4   # value saved in memory.
set DST_LO,  8

set SRC,  0   # offsets within an
set SRC_EX,  0   # extended precision
set SRC_HI,  4   # value saved in memory.
set SRC_LO,  8

set SGL_LO,  0x3f81   # min sgl prec exponent
set SGL_HI,  0x407e   # max sgl prec exponent
set DBL_LO,  0x3c01   # min dbl prec exponent
set DBL_HI,  0x43fe   # max dbl prec exponent
set EXT_LO,  0x0   # min ext prec exponent
set EXT_HI,  0x7ffe   # max ext prec exponent

set EXT_BIAS,  0x3fff   # extended precision bias
set SGL_BIAS,  0x007f   # single precision bias
set DBL_BIAS,  0x03ff   # double precision bias

set NORM,  0x00   # operand type for STAG/DTAG
set ZERO,  0x01   # operand type for STAG/DTAG
set INF,  0x02   # operand type for STAG/DTAG
set QNAN,  0x03   # operand type for STAG/DTAG
set DENORM,  0x04   # operand type for STAG/DTAG
set SNAN,  0x05   # operand type for STAG/DTAG
set UNNORM,  0x06   # operand type for STAG/DTAG

##################
# FPSR/FPCR bits #
##################
set neg_bit,  0x3   # negative result
set z_bit,  0x2   # zero result
set inf_bit,  0x1   # infinite result
set nan_bit,  0x0   # NAN result

set q_sn_bit,  0x7   # sign bit of quotient byte

set bsun_bit,  7   # branch on unordered
set snan_bit,  6   # signalling NAN
set operr_bit,  5   # operand error
set ovfl_bit,  4   # overflow
set unfl_bit,  3   # underflow
set dz_bit,  2   # divide by zero
set inex2_bit,  1   # inexact result 2
set inex1_bit,  0   # inexact result 1

set aiop_bit,  7   # accrued inexact operation bit
set aovfl_bit,  6   # accrued overflow bit
set aunfl_bit,  5   # accrued underflow bit
set adz_bit,  4   # accrued dz bit
set ainex_bit,  3   # accrued inexact bit

#############################
# FPSR individual bit masks #
#############################
set neg_mask,  0x08000000  # negative bit mask (lw)
set inf_mask,  0x02000000  # infinity bit mask (lw)
set z_mask,  0x04000000  # zero bit mask (lw)
set nan_mask,  0x01000000  # nan bit mask (lw)

set neg_bmask,  0x08   # negative bit mask (byte)
set inf_bmask,  0x02   # infinity bit mask (byte)
set z_bmask,  0x04   # zero bit mask (byte)
set nan_bmask,  0x01   # nan bit mask (byte)

set bsun_mask,  0x00008000  # bsun exception mask
set snan_mask,  0x00004000  # snan exception mask
set operr_mask,  0x00002000  # operr exception mask
set ovfl_mask,  0x00001000  # overflow exception mask
set unfl_mask,  0x00000800  # underflow exception mask
set dz_mask,  0x00000400  # dz exception mask
set inex2_mask,  0x00000200  # inex2 exception mask
set inex1_mask,  0x00000100  # inex1 exception mask

set aiop_mask,  0x00000080  # accrued illegal operation
set aovfl_mask,  0x00000040  # accrued overflow
set aunfl_mask,  0x00000020  # accrued underflow
set adz_mask,  0x00000010  # accrued divide by zero
set ainex_mask,  0x00000008  # accrued inexact

######################################
# FPSR combinations used in the FPSP #
######################################
set dzinf_mask,  inf_mask+dz_mask+adz_mask
set opnan_mask,  nan_mask+operr_mask+aiop_mask
set nzi_mask,  0x01ffffff  #clears N, Z, and I
set unfinx_mask, unfl_mask+inex2_mask+aunfl_mask+ainex_mask
set unf2inx_mask, unfl_mask+inex2_mask+ainex_mask
set ovfinx_mask, ovfl_mask+inex2_mask+aovfl_mask+ainex_mask
set inx1a_mask,  inex1_mask+ainex_mask
set inx2a_mask,  inex2_mask+ainex_mask
set snaniop_mask, nan_mask+snan_mask+aiop_mask
set snaniop2_mask, snan_mask+aiop_mask
set naniop_mask, nan_mask+aiop_mask
set neginf_mask, neg_mask+inf_mask
set infaiop_mask, inf_mask+aiop_mask
set negz_mask,  neg_mask+z_mask
set opaop_mask,  operr_mask+aiop_mask
set unfl_inx_mask, unfl_mask+aunfl_mask+ainex_mask
set ovfl_inx_mask, ovfl_mask+aovfl_mask+ainex_mask

#########
# misc. #
#########
set rnd_stky_bit, 29   # stky bit pos in longword

set sign_bit,  0x7   # sign bit
set signan_bit,  0x6   # signalling nan bit

set sgl_thresh,  0x3f81   # minimum sgl exponent
set dbl_thresh,  0x3c01   # minimum dbl exponent

set x_mode,  0x0   # extended precision
set s_mode,  0x4   # single precision
set d_mode,  0x8   # double precision

set rn_mode,  0x0   # round-to-nearest
set rz_mode,  0x1   # round-to-zero
set rm_mode,  0x2   # round-tp-minus-infinity
set rp_mode,  0x3   # round-to-plus-infinity

set mantissalen, 64   # length of mantissa in bits

set BYTE,  1   # len(byte) == 1 byte
set WORD,  2   # len(word) == 2 bytes
set LONG,  4   # len(longword) == 2 bytes

set BSUN_VEC,  0xc0   # bsun    vector offset
set INEX_VEC,  0xc4   # inexact vector offset
set DZ_VEC,  0xc8   # dz      vector offset
set UNFL_VEC,  0xcc   # unfl    vector offset
set OPERR_VEC,  0xd0   # operr   vector offset
set OVFL_VEC,  0xd4   # ovfl    vector offset
set SNAN_VEC,  0xd8   # snan    vector offset

###########################
# SPecial CONDition FLaGs #
###########################
set ftrapcc_flg, 0x01   # flag bit: ftrapcc exception
set fbsun_flg,  0x02   # flag bit: bsun exception
set mia7_flg,  0x04   # flag bit: (a7)+ <ea>
set mda7_flg,  0x08   # flag bit: -(a7) <ea>
set fmovm_flg,  0x40   # flag bit: fmovm instruction
set immed_flg,  0x80   # flag bit: &<data> <ea>

set ftrapcc_bit, 0x0
set fbsun_bit,  0x1
set mia7_bit,  0x2
set mda7_bit,  0x3
set immed_bit,  0x7

##################################
# TRANSCENDENTAL "LAST-OP" FLAGS #
##################################
set FMUL_OP,  0x0   # fmul instr performed last
set FDIV_OP,  0x1   # fdiv performed last
set FADD_OP,  0x2   # fadd performed last
set FMOV_OP,  0x3   # fmov performed last

#############
# CONSTANTS #
#############
T1: long  0x40C62D38,0xD3D64634 # 16381 LOG2 LEAD
T2: long  0x3D6F90AE,0xB1E75CC7 # 16381 LOG2 TRAIL

PI: long  0x40000000,0xC90FDAA2,0x2168C235,0x00000000
PIBY2: long  0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000

TWOBYPI:
 long  0x3FE45F30,0x6DC9C883

#########################################################################
# XDEF **************************************************************** #
# _fpsp_ovfl(): 060FPSP entry point for FP Overflow exception. #
#         #
# This handler should be the first code executed upon taking the #
# FP Overflow exception in an operating system.   #
#         #
# XREF **************************************************************** #
# _imem_read_long() - read instruction longword   #
# fix_skewed_ops() - adjust src operand in fsave frame  #
# set_tag_x() - determine optype of src/dst operands  #
# store_fpreg() - store opclass 0 or 2 result to FP regfile #
# unnorm_fix() - change UNNORM operands to NORM or ZERO  #
# load_fpn2() - load dst operand from FP regfile   #
# fout() - emulate an opclass 3 instruction   #
# tbl_unsupp - add of table of emulation routines for opclass 0,2 #
# _fpsp_done() - "callout" for 060FPSP exit (all work done!) #
# _real_ovfl() - "callout" for Overflow exception enabled code #
# _real_inex() - "callout" for Inexact exception enabled code #
# _real_trace() - "callout" for Trace exception code  #
#         #
# INPUT *************************************************************** #
# - The system stack contains the FP Ovfl exception stack frame #
# - The fsave frame contains the source operand   #
#         #
# OUTPUT ************************************************************** #
# Overflow Exception enabled:     #
# - The system stack is unchanged     #
# - The fsave frame contains the adjusted src op for opclass 0,2 #
# Overflow Exception disabled:     #
# - The system stack is unchanged     #
# - The "exception present" flag in the fsave frame is cleared #
#         #
# ALGORITHM *********************************************************** #
# On the 060, if an FP overflow is present as the result of any #
# instruction, the 060 will take an overflow exception whether the #
# exception is enabled or disabled in the FPCR. For the disabled case, #
# This handler emulates the instruction to determine what the correct #
# default result should be for the operation. This default result is #
# then stored in either the FP regfile, data regfile, or memory. #
# Finally, the handler exits through the "callout" _fpsp_done()  #
# denoting that no exceptional conditions exist within the machine. #
# If the exception is enabled, then this handler must create the #
# exceptional operand and plave it in the fsave state frame, and store #
# the default result (only if the instruction is opclass 3). For #
# exceptions enabled, this handler must exit through the "callout" #
# _real_ovfl() so that the operating system enabled overflow handler #
# can handle this case.       #
# Two other conditions exist. First, if overflow was disabled #
# but the inexact exception was enabled, this handler must exit  #
# through the "callout" _real_inex() regardless of whether the result #
# was inexact.        #
# Also, in the case of an opclass three instruction where  #
# overflow was disabled and the trace exception was enabled, this #
# handler must exit through the "callout" _real_trace().  #
#         #
#########################################################################

 global  _fpsp_ovfl
_fpsp_ovfl:

#$# sub.l  &24,%sp   # make room for src/dst

 link.w  %a6,&-LOCAL_SIZE # init stack frame

 fsave  FP_SRC(%a6)  # grab the "busy" frame

 movm.l  &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
 fmovm.l  %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
 fmovm.x  &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack

# the FPIAR holds the "current PC" of the faulting instruction
 mov.l  USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
 mov.l  EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
 addq.l  &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
 bsr.l  _imem_read_long  # fetch the instruction words
 mov.l  %d0,EXC_OPWORD(%a6)

##############################################################################

 btst  &0x5,EXC_CMDREG(%a6) # is instr an fmove out?
 bne.w  fovfl_out


 lea  FP_SRC(%a6),%a0  # pass: ptr to src op
 bsr.l  fix_skewed_ops  # fix src op

# since, I believe, only NORMs and DENORMs can come through here,
# maybe we can avoid the subroutine call.
 lea  FP_SRC(%a6),%a0  # pass: ptr to src op
 bsr.l  set_tag_x  # tag the operand type
 mov.b  %d0,STAG(%a6)  # maybe NORM,DENORM

# bit five of the fp extension word separates the monadic and dyadic operations
# that can pass through fpsp_ovfl(). remember that fcmp, ftst, and fsincos
# will never take this exception.
 btst  &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic?
 beq.b  fovfl_extract  # monadic

 bfextu  EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
 bsr.l  load_fpn2  # load dst into FP_DST

 lea  FP_DST(%a6),%a0  # pass: ptr to dst op
 bsr.l  set_tag_x  # tag the operand type
 cmpi.b  %d0,&UNNORM  # is operand an UNNORM?
 bne.b  fovfl_op2_done  # no
 bsr.l  unnorm_fix  # yes; convert to NORM,DENORM,or ZERO
fovfl_op2_done:
 mov.b  %d0,DTAG(%a6)  # save dst optype tag

fovfl_extract:

#$# mov.l  FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
#$# mov.l  FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
#$# mov.l  FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
#$# mov.l  FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6)
#$# mov.l  FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6)
#$# mov.l  FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6)

 clr.l  %d0
 mov.b  FPCR_MODE(%a6),%d0 # pass rnd prec/mode

 mov.b  1+EXC_CMDREG(%a6),%d1
 andi.w  &0x007f,%d1  # extract extension

 andi.l  &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field

 fmov.l  &0x0,%fpcr  # zero current control regs
 fmov.l  &0x0,%fpsr

 lea  FP_SRC(%a6),%a0
 lea  FP_DST(%a6),%a1

# maybe we can make these entry points ONLY the OVFL entry points of each routine.
 mov.l  (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
 jsr  (tbl_unsupp.l,%pc,%d1.l*1)

# the operation has been emulated. the result is in fp0.
# the EXOP, if an exception occurred, is in fp1.
# we must save the default result regardless of whether
# traps are enabled or disabled.
 bfextu  EXC_CMDREG(%a6){&6:&3},%d0
 bsr.l  store_fpreg

# the exceptional possibilities we have left ourselves with are ONLY overflow
# and inexact. and, the inexact is such that overflow occurred and was disabled
# but inexact was enabled.
 btst  &ovfl_bit,FPCR_ENABLE(%a6)
 bne.b  fovfl_ovfl_on

 btst  &inex2_bit,FPCR_ENABLE(%a6)
 bne.b  fovfl_inex_on

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 unlk  %a6
#$# add.l  &24,%sp
 bra.l  _fpsp_done

# overflow is enabled AND overflow, of course, occurred. so, we have the EXOP
# in fp1. now, simply jump to _real_ovfl()!
fovfl_ovfl_on:
 fmovm.x  &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack

 mov.w  &0xe005,2+FP_SRC(%a6) # save exc status

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 frestore FP_SRC(%a6)  # do this after fmovm,other f<op>s!

 unlk  %a6

 bra.l  _real_ovfl

# overflow occurred but is disabled. meanwhile, inexact is enabled. Therefore,
# we must jump to real_inex().
fovfl_inex_on:

 fmovm.x  &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack

 mov.b  &0xc4,1+EXC_VOFF(%a6) # vector offset = 0xc4
 mov.w  &0xe001,2+FP_SRC(%a6) # save exc status

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 frestore FP_SRC(%a6)  # do this after fmovm,other f<op>s!

 unlk  %a6

 bra.l  _real_inex

########################################################################
fovfl_out:


#$# mov.l  FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
#$# mov.l  FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
#$# mov.l  FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)

# the src operand is definitely a NORM(!), so tag it as such
 mov.b  &NORM,STAG(%a6)  # set src optype tag

 clr.l  %d0
 mov.b  FPCR_MODE(%a6),%d0 # pass rnd prec/mode

 and.l  &0xffff00ff,USER_FPSR(%a6) # zero all but accured field

 fmov.l  &0x0,%fpcr  # zero current control regs
 fmov.l  &0x0,%fpsr

 lea  FP_SRC(%a6),%a0  # pass ptr to src operand

 bsr.l  fout

 btst  &ovfl_bit,FPCR_ENABLE(%a6)
 bne.w  fovfl_ovfl_on

 btst  &inex2_bit,FPCR_ENABLE(%a6)
 bne.w  fovfl_inex_on

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 unlk  %a6
#$# add.l  &24,%sp

 btst  &0x7,(%sp)  # is trace on?
 beq.l  _fpsp_done  # no

 fmov.l  %fpiar,0x8(%sp)  # "Current PC" is in FPIAR
 mov.w  &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024
 bra.l  _real_trace

#########################################################################
# XDEF **************************************************************** #
# _fpsp_unfl(): 060FPSP entry point for FP Underflow exception. #
#         #
# This handler should be the first code executed upon taking the #
# FP Underflow exception in an operating system.   #
#         #
# XREF **************************************************************** #
# _imem_read_long() - read instruction longword   #
# fix_skewed_ops() - adjust src operand in fsave frame  #
# set_tag_x() - determine optype of src/dst operands  #
# store_fpreg() - store opclass 0 or 2 result to FP regfile #
# unnorm_fix() - change UNNORM operands to NORM or ZERO  #
# load_fpn2() - load dst operand from FP regfile   #
# fout() - emulate an opclass 3 instruction   #
# tbl_unsupp - add of table of emulation routines for opclass 0,2 #
# _fpsp_done() - "callout" for 060FPSP exit (all work done!) #
# _real_ovfl() - "callout" for Overflow exception enabled code #
# _real_inex() - "callout" for Inexact exception enabled code #
# _real_trace() - "callout" for Trace exception code  #
#         #
# INPUT *************************************************************** #
# - The system stack contains the FP Unfl exception stack frame #
# - The fsave frame contains the source operand   #
#         #
# OUTPUT ************************************************************** #
# Underflow Exception enabled:     #
# - The system stack is unchanged     #
# - The fsave frame contains the adjusted src op for opclass 0,2 #
# Underflow Exception disabled:     #
# - The system stack is unchanged     #
# - The "exception present" flag in the fsave frame is cleared #
#         #
# ALGORITHM *********************************************************** #
# On the 060, if an FP underflow is present as the result of any #
# instruction, the 060 will take an underflow exception whether the #
# exception is enabled or disabled in the FPCR. For the disabled case, #
# This handler emulates the instruction to determine what the correct #
# default result should be for the operation. This default result is #
# then stored in either the FP regfile, data regfile, or memory. #
# Finally, the handler exits through the "callout" _fpsp_done()  #
# denoting that no exceptional conditions exist within the machine. #
# If the exception is enabled, then this handler must create the #
# exceptional operand and plave it in the fsave state frame, and store #
# the default result (only if the instruction is opclass 3). For #
# exceptions enabled, this handler must exit through the "callout" #
# _real_unfl() so that the operating system enabled overflow handler #
# can handle this case.       #
# Two other conditions exist. First, if underflow was disabled #
# but the inexact exception was enabled and the result was inexact, #
# this handler must exit through the "callout" _real_inex().  #
# was inexact.        #
# Also, in the case of an opclass three instruction where  #
# underflow was disabled and the trace exception was enabled, this #
# handler must exit through the "callout" _real_trace().  #
#         #
#########################################################################

 global  _fpsp_unfl
_fpsp_unfl:

#$# sub.l  &24,%sp   # make room for src/dst

 link.w  %a6,&-LOCAL_SIZE # init stack frame

 fsave  FP_SRC(%a6)  # grab the "busy" frame

 movm.l  &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
 fmovm.l  %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
 fmovm.x  &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack

# the FPIAR holds the "current PC" of the faulting instruction
 mov.l  USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
 mov.l  EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
 addq.l  &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
 bsr.l  _imem_read_long  # fetch the instruction words
 mov.l  %d0,EXC_OPWORD(%a6)

##############################################################################

 btst  &0x5,EXC_CMDREG(%a6) # is instr an fmove out?
 bne.w  funfl_out


 lea  FP_SRC(%a6),%a0  # pass: ptr to src op
 bsr.l  fix_skewed_ops  # fix src op

 lea  FP_SRC(%a6),%a0  # pass: ptr to src op
 bsr.l  set_tag_x  # tag the operand type
 mov.b  %d0,STAG(%a6)  # maybe NORM,DENORM

# bit five of the fp ext word separates the monadic and dyadic operations
# that can pass through fpsp_unfl(). remember that fcmp, and ftst
# will never take this exception.
 btst  &0x5,1+EXC_CMDREG(%a6) # is op monadic or dyadic?
 beq.b  funfl_extract  # monadic

# now, what's left that's not dyadic is fsincos. we can distinguish it
# from all dyadics by the '0110xxx pattern
 btst  &0x4,1+EXC_CMDREG(%a6) # is op an fsincos?
 bne.b  funfl_extract  # yes

 bfextu  EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
 bsr.l  load_fpn2  # load dst into FP_DST

 lea  FP_DST(%a6),%a0  # pass: ptr to dst op
 bsr.l  set_tag_x  # tag the operand type
 cmpi.b  %d0,&UNNORM  # is operand an UNNORM?
 bne.b  funfl_op2_done  # no
 bsr.l  unnorm_fix  # yes; convert to NORM,DENORM,or ZERO
funfl_op2_done:
 mov.b  %d0,DTAG(%a6)  # save dst optype tag

funfl_extract:

#$# mov.l  FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
#$# mov.l  FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
#$# mov.l  FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
#$# mov.l  FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6)
#$# mov.l  FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6)
#$# mov.l  FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6)

 clr.l  %d0
 mov.b  FPCR_MODE(%a6),%d0 # pass rnd prec/mode

 mov.b  1+EXC_CMDREG(%a6),%d1
 andi.w  &0x007f,%d1  # extract extension

 andi.l  &0x00ff01ff,USER_FPSR(%a6)

 fmov.l  &0x0,%fpcr  # zero current control regs
 fmov.l  &0x0,%fpsr

 lea  FP_SRC(%a6),%a0
 lea  FP_DST(%a6),%a1

# maybe we can make these entry points ONLY the OVFL entry points of each routine.
 mov.l  (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
 jsr  (tbl_unsupp.l,%pc,%d1.l*1)

 bfextu  EXC_CMDREG(%a6){&6:&3},%d0
 bsr.l  store_fpreg

# The `060 FPU multiplier hardware is such that if the result of a
# multiply operation is the smallest possible normalized number
# (0x00000000_80000000_00000000), then the machine will take an
# underflow exception. Since this is incorrect, we need to check
# if our emulation, after re-doing the operation, decided that
# no underflow was called for. We do these checks only in
# funfl_{unfl,inex}_on() because w/ both exceptions disabled, this
# special case will simply exit gracefully with the correct result.

# the exceptional possibilities we have left ourselves with are ONLY overflow
# and inexact. and, the inexact is such that overflow occurred and was disabled
# but inexact was enabled.
 btst  &unfl_bit,FPCR_ENABLE(%a6)
 bne.b  funfl_unfl_on

funfl_chkinex:
 btst  &inex2_bit,FPCR_ENABLE(%a6)
 bne.b  funfl_inex_on

funfl_exit:
 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 unlk  %a6
#$# add.l  &24,%sp
 bra.l  _fpsp_done

# overflow is enabled AND overflow, of course, occurred. so, we have the EXOP
# in fp1 (don't forget to save fp0). what to do now?
# well, we simply have to get to go to _real_unfl()!
funfl_unfl_on:

# The `060 FPU multiplier hardware is such that if the result of a
# multiply operation is the smallest possible normalized number
# (0x00000000_80000000_00000000), then the machine will take an
# underflow exception. Since this is incorrect, we check here to see
# if our emulation, after re-doing the operation, decided that
# no underflow was called for.
 btst  &unfl_bit,FPSR_EXCEPT(%a6)
 beq.w  funfl_chkinex

funfl_unfl_on2:
 fmovm.x  &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack

 mov.w  &0xe003,2+FP_SRC(%a6) # save exc status

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 frestore FP_SRC(%a6)  # do this after fmovm,other f<op>s!

 unlk  %a6

 bra.l  _real_unfl

# underflow occurred but is disabled. meanwhile, inexact is enabled. Therefore,
# we must jump to real_inex().
funfl_inex_on:

# The `060 FPU multiplier hardware is such that if the result of a
# multiply operation is the smallest possible normalized number
# (0x00000000_80000000_00000000), then the machine will take an
# underflow exception.
# But, whether bogus or not, if inexact is enabled AND it occurred,
# then we have to branch to real_inex.

 btst  &inex2_bit,FPSR_EXCEPT(%a6)
 beq.w  funfl_exit

funfl_inex_on2:

 fmovm.x  &0x40,FP_SRC(%a6) # save EXOP to stack

 mov.b  &0xc4,1+EXC_VOFF(%a6) # vector offset = 0xc4
 mov.w  &0xe001,2+FP_SRC(%a6) # save exc status

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 frestore FP_SRC(%a6)  # do this after fmovm,other f<op>s!

 unlk  %a6

 bra.l  _real_inex

#######################################################################
funfl_out:


#$# mov.l  FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
#$# mov.l  FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
#$# mov.l  FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)

# the src operand is definitely a NORM(!), so tag it as such
 mov.b  &NORM,STAG(%a6)  # set src optype tag

 clr.l  %d0
 mov.b  FPCR_MODE(%a6),%d0 # pass rnd prec/mode

 and.l  &0xffff00ff,USER_FPSR(%a6) # zero all but accured field

 fmov.l  &0x0,%fpcr  # zero current control regs
 fmov.l  &0x0,%fpsr

 lea  FP_SRC(%a6),%a0  # pass ptr to src operand

 bsr.l  fout

 btst  &unfl_bit,FPCR_ENABLE(%a6)
 bne.w  funfl_unfl_on2

 btst  &inex2_bit,FPCR_ENABLE(%a6)
 bne.w  funfl_inex_on2

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 unlk  %a6
#$# add.l  &24,%sp

 btst  &0x7,(%sp)  # is trace on?
 beq.l  _fpsp_done  # no

 fmov.l  %fpiar,0x8(%sp)  # "Current PC" is in FPIAR
 mov.w  &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024
 bra.l  _real_trace

#########################################################################
# XDEF **************************************************************** #
# _fpsp_unsupp(): 060FPSP entry point for FP "Unimplemented #
#          Data Type" exception. #
#         #
# This handler should be the first code executed upon taking the #
# FP Unimplemented Data Type exception in an operating system. #
#         #
# XREF **************************************************************** #
# _imem_read_{word,long}() - read instruction word/longword #
# fix_skewed_ops() - adjust src operand in fsave frame  #
# set_tag_x() - determine optype of src/dst operands  #
# store_fpreg() - store opclass 0 or 2 result to FP regfile #
# unnorm_fix() - change UNNORM operands to NORM or ZERO  #
# load_fpn2() - load dst operand from FP regfile   #
# load_fpn1() - load src operand from FP regfile   #
# fout() - emulate an opclass 3 instruction   #
# tbl_unsupp - add of table of emulation routines for opclass 0,2 #
# _real_inex() - "callout" to operating system inexact handler #
# _fpsp_done() - "callout" for exit; work all done  #
# _real_trace() - "callout" for Trace enabled exception  #
# funimp_skew() - adjust fsave src ops to "incorrect" value #
# _real_snan() - "callout" for SNAN exception   #
# _real_operr() - "callout" for OPERR exception   #
# _real_ovfl() - "callout" for OVFL exception   #
# _real_unfl() - "callout" for UNFL exception   #
# get_packed() - fetch packed operand from memory   #
#         #
# INPUT *************************************************************** #
# - The system stack contains the "Unimp Data Type" stk frame #
# - The fsave frame contains the ssrc op (for UNNORM/DENORM) #
#         #
# OUTPUT ************************************************************** #
# If Inexact exception (opclass 3):    #
# - The system stack is changed to an Inexact exception stk frame #
# If SNAN exception (opclass 3):     #
# - The system stack is changed to an SNAN exception stk frame #
# If OPERR exception (opclass 3):     #
# - The system stack is changed to an OPERR exception stk frame #
# If OVFL exception (opclass 3):     #
# - The system stack is changed to an OVFL exception stk frame #
# If UNFL exception (opclass 3):     #
# - The system stack is changed to an UNFL exception stack frame #
# If Trace exception enabled:     #
# - The system stack is changed to a Trace exception stack frame #
# Else: (normal case)      #
# - Correct result has been stored as appropriate   #
#         #
# ALGORITHM *********************************************************** #
# Two main instruction types can enter here: (1) DENORM or UNNORM #
# unimplemented data types. These can be either opclass 0,2 or 3 #
# instructions, and (2) PACKED unimplemented data format instructions #
# also of opclasses 0,2, or 3.      #
# For UNNORM/DENORM opclass 0 and 2, the handler fetches the src #
# operand from the fsave state frame and the dst operand (if dyadic) #
# from the FP register file. The instruction is then emulated by #
# choosing an emulation routine from a table of routines indexed by #
# instruction type. Once the instruction has been emulated and result #
# saved, then we check to see if any enabled exceptions resulted from #
# instruction emulation. If none, then we exit through the "callout" #
# _fpsp_done(). If there is an enabled FP exception, then we insert #
# this exception into the FPU in the fsave state frame and then exit #
# through _fpsp_done().       #
# PACKED opclass 0 and 2 is similar in how the instruction is #
# emulated and exceptions handled. The differences occur in how the #
# handler loads the packed op (by calling get_packed() routine) and #
# by the fact that a Trace exception could be pending for PACKED ops. #
# If a Trace exception is pending, then the current exception stack #
# frame is changed to a Trace exception stack frame and an exit is #
# made through _real_trace().      #
# For UNNORM/DENORM opclass 3, the actual move out to memory is #
# performed by calling the routine fout(). If no exception should occur #
# as the result of emulation, then an exit either occurs through #
# _fpsp_done() or through _real_trace() if a Trace exception is pending #
# (a Trace stack frame must be created here, too). If an FP exception #
# should occur, then we must create an exception stack frame of that #
# type and jump to either _real_snan(), _real_operr(), _real_inex(), #
# _real_unfl(), or _real_ovfl() as appropriate. PACKED opclass 3 #
# emulation is performed in a similar manner.    #
#         #
#########################################################################

#
# (1) DENORM and UNNORM (unimplemented) data types:
#
#    post-instruction
#    *****************
#    *      EA *
#  pre-instruction *  *
# ***************** *****************
# * 0x0 *  0x0dc  * * 0x3 *  0x0dc  *
# ***************** *****************
# *     Next * *     Next *
# *      PC * *      PC *
# ***************** *****************
# *      SR * *      SR *
# ***************** *****************
#
# (2) PACKED format (unsupported) opclasses two and three:
# *****************
# *      EA *
# *  *
# *****************
# * 0x2 *  0x0dc *
# *****************
# *     Next *
# *      PC *
# *****************
# *      SR *
# *****************
#
 global  _fpsp_unsupp
_fpsp_unsupp:

 link.w  %a6,&-LOCAL_SIZE # init stack frame

 fsave  FP_SRC(%a6)  # save fp state

 movm.l  &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
 fmovm.l  %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
 fmovm.x  &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack

 btst  &0x5,EXC_SR(%a6) # user or supervisor mode?
 bne.b  fu_s
fu_u:
 mov.l  %usp,%a0  # fetch user stack pointer
 mov.l  %a0,EXC_A7(%a6)  # save on stack
 bra.b  fu_cont
# if the exception is an opclass zero or two unimplemented data type
# exception, then the a7' calculated here is wrong since it doesn't
# stack an ea. however, we don't need an a7' for this case anyways.
fu_s:
 lea  0x4+EXC_EA(%a6),%a0 # load old a7'
 mov.l  %a0,EXC_A7(%a6)  # save on stack

fu_cont:

# the FPIAR holds the "current PC" of the faulting instruction
# the FPIAR should be set correctly for ALL exceptions passing through
# this point.
 mov.l  USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
 mov.l  EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
 addq.l  &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
 bsr.l  _imem_read_long  # fetch the instruction words
 mov.l  %d0,EXC_OPWORD(%a6) # store OPWORD and EXTWORD

############################

 clr.b  SPCOND_FLG(%a6)  # clear special condition flag

# Separate opclass three (fpn-to-mem) ops since they have a different
# stack frame and protocol.
 btst  &0x5,EXC_CMDREG(%a6) # is it an fmove out?
 bne.w  fu_out   # yes

# Separate packed opclass two instructions.
 bfextu  EXC_CMDREG(%a6){&0:&6},%d0
 cmpi.b  %d0,&0x13
 beq.w  fu_in_pack


# I'm not sure at this point what FPSR bits are valid for this instruction.
# so, since the emulation routines re-create them anyways, zero exception field
 andi.l  &0x00ff00ff,USER_FPSR(%a6) # zero exception field

 fmov.l  &0x0,%fpcr  # zero current control regs
 fmov.l  &0x0,%fpsr

# Opclass two w/ memory-to-fpn operation will have an incorrect extended
# precision format if the src format was single or double and the
# source data type was an INF, NAN, DENORM, or UNNORM
 lea  FP_SRC(%a6),%a0  # pass ptr to input
 bsr.l  fix_skewed_ops

# we don't know whether the src operand or the dst operand (or both) is the
# UNNORM or DENORM. call the function that tags the operand type. if the
# input is an UNNORM, then convert it to a NORM, DENORM, or ZERO.
 lea  FP_SRC(%a6),%a0  # pass: ptr to src op
 bsr.l  set_tag_x  # tag the operand type
 cmpi.b  %d0,&UNNORM  # is operand an UNNORM?
 bne.b  fu_op2   # no
 bsr.l  unnorm_fix  # yes; convert to NORM,DENORM,or ZERO

fu_op2:
 mov.b  %d0,STAG(%a6)  # save src optype tag

 bfextu  EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg

# bit five of the fp extension word separates the monadic and dyadic operations
# at this point
 btst  &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic?
 beq.b  fu_extract  # monadic
 cmpi.b  1+EXC_CMDREG(%a6),&0x3a # is operation an ftst?
 beq.b  fu_extract  # yes, so it's monadic, too

 bsr.l  load_fpn2  # load dst into FP_DST

 lea  FP_DST(%a6),%a0  # pass: ptr to dst op
 bsr.l  set_tag_x  # tag the operand type
 cmpi.b  %d0,&UNNORM  # is operand an UNNORM?
 bne.b  fu_op2_done  # no
 bsr.l  unnorm_fix  # yes; convert to NORM,DENORM,or ZERO
fu_op2_done:
 mov.b  %d0,DTAG(%a6)  # save dst optype tag

fu_extract:
 clr.l  %d0
 mov.b  FPCR_MODE(%a6),%d0 # fetch rnd mode/prec

 bfextu  1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension

 lea  FP_SRC(%a6),%a0
 lea  FP_DST(%a6),%a1

 mov.l  (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr
 jsr  (tbl_unsupp.l,%pc,%d1.l*1)

#
# Exceptions in order of precedence:
# BSUN : none
# SNAN : all dyadic ops
# OPERR : fsqrt(-NORM)
# OVFL : all except ftst,fcmp
# UNFL : all except ftst,fcmp
# DZ : fdiv
# INEX2 : all except ftst,fcmp
# INEX1 : none (packed doesn't go through here)
#

# we determine the highest priority exception(if any) set by the
# emulation routine that has also been enabled by the user.
 mov.b  FPCR_ENABLE(%a6),%d0 # fetch exceptions set
 bne.b  fu_in_ena  # some are enabled

fu_in_cont:
# fcmp and ftst do not store any result.
 mov.b  1+EXC_CMDREG(%a6),%d0 # fetch extension
 andi.b  &0x38,%d0  # extract bits 3-5
 cmpi.b  %d0,&0x38  # is instr fcmp or ftst?
 beq.b  fu_in_exit  # yes

 bfextu  EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
 bsr.l  store_fpreg  # store the result

fu_in_exit:

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 unlk  %a6

 bra.l  _fpsp_done

fu_in_ena:
 and.b  FPSR_EXCEPT(%a6),%d0 # keep only ones enabled
 bfffo  %d0{&24:&8},%d0  # find highest priority exception
 bne.b  fu_in_exc  # there is at least one set

#
# No exceptions occurred that were also enabled. Now:
#
# if (OVFL && ovfl_disabled && inexact_enabled) {
#     branch to _real_inex() (even if the result was exact!);
# } else {
#     save the result in the proper fp reg (unless the op is fcmp or ftst);
#     return;
# }
#
 btst  &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
 beq.b  fu_in_cont  # no

fu_in_ovflchk:
 btst  &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
 beq.b  fu_in_cont  # no
 bra.w  fu_in_exc_ovfl  # go insert overflow frame

#
# An exception occurred and that exception was enabled:
#
# shift enabled exception field into lo byte of d0;
# if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) ||
#     ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) {
#  /*
#  * this is the case where we must call _real_inex() now or else
#  * there will be no other way to pass it the exceptional operand
#  */

#  call _real_inex();
# } else {
#  restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU;
# }
#
fu_in_exc:
 subi.l  &24,%d0   # fix offset to be 0-8
 cmpi.b  %d0,&0x6  # is exception INEX? (6)
 bne.b  fu_in_exc_exit  # no

# the enabled exception was inexact
 btst  &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur?
 bne.w  fu_in_exc_unfl  # yes
 btst  &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur?
 bne.w  fu_in_exc_ovfl  # yes

# here, we insert the correct fsave status value into the fsave frame for the
# corresponding exception. the operand in the fsave frame should be the original
# src operand.
fu_in_exc_exit:
 mov.l  %d0,-(%sp)  # save d0
 bsr.l  funimp_skew  # skew sgl or dbl inputs
 mov.l  (%sp)+,%d0  # restore d0

 mov.w  (tbl_except.b,%pc,%d0.w*2),2+FP_SRC(%a6) # create exc status

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 frestore FP_SRC(%a6)  # restore src op

 unlk  %a6

 bra.l  _fpsp_done

tbl_except:
 short  0xe000,0xe006,0xe004,0xe005
 short  0xe003,0xe002,0xe001,0xe001

fu_in_exc_unfl:
 mov.w  &0x4,%d0
 bra.b  fu_in_exc_exit
fu_in_exc_ovfl:
 mov.w  &0x03,%d0
 bra.b  fu_in_exc_exit

# If the input operand to this operation was opclass two and a single
# or double precision denorm, inf, or nan, the operand needs to be
"corrected" in order to have the proper equivalent extended precision
# number.
 global  fix_skewed_ops
fix_skewed_ops:
 bfextu  EXC_CMDREG(%a6){&0:&6},%d0 # extract opclass,src fmt
 cmpi.b  %d0,&0x11  # is class = 2 & fmt = sgl?
 beq.b  fso_sgl   # yes
 cmpi.b  %d0,&0x15  # is class = 2 & fmt = dbl?
 beq.b  fso_dbl   # yes
 rts     # no

fso_sgl:
 mov.w  LOCAL_EX(%a0),%d0 # fetch src exponent
 andi.w  &0x7fff,%d0  # strip sign
 cmpi.w  %d0,&0x3f80  # is |exp| == $3f80?
 beq.b  fso_sgl_dnrm_zero # yes
 cmpi.w  %d0,&0x407f  # no; is |exp| == $407f?
 beq.b  fso_infnan  # yes
 rts     # no

fso_sgl_dnrm_zero:
 andi.l  &0x7fffffff,LOCAL_HI(%a0) # clear j-bit
 beq.b  fso_zero  # it's a skewed zero
fso_sgl_dnrm:
# here, we count on norm not to alter a0...
 bsr.l  norm   # normalize mantissa
 neg.w  %d0   # -shft amt
 addi.w  &0x3f81,%d0  # adjust new exponent
 andi.w  &0x8000,LOCAL_EX(%a0) # clear old exponent
 or.w  %d0,LOCAL_EX(%a0) # insert new exponent
 rts

fso_zero:
 andi.w  &0x8000,LOCAL_EX(%a0) # clear bogus exponent
 rts

fso_infnan:
 andi.b  &0x7f,LOCAL_HI(%a0) # clear j-bit
 ori.w  &0x7fff,LOCAL_EX(%a0) # make exponent = $7fff
 rts

fso_dbl:
 mov.w  LOCAL_EX(%a0),%d0 # fetch src exponent
 andi.w  &0x7fff,%d0  # strip sign
 cmpi.w  %d0,&0x3c00  # is |exp| == $3c00?
 beq.b  fso_dbl_dnrm_zero # yes
 cmpi.w  %d0,&0x43ff  # no; is |exp| == $43ff?
 beq.b  fso_infnan  # yes
 rts     # no

fso_dbl_dnrm_zero:
 andi.l  &0x7fffffff,LOCAL_HI(%a0) # clear j-bit
 bne.b  fso_dbl_dnrm  # it's a skewed denorm
 tst.l  LOCAL_LO(%a0)  # is it a zero?
 beq.b  fso_zero  # yes
fso_dbl_dnrm:
# here, we count on norm not to alter a0...
 bsr.l  norm   # normalize mantissa
 neg.w  %d0   # -shft amt
 addi.w  &0x3c01,%d0  # adjust new exponent
 andi.w  &0x8000,LOCAL_EX(%a0) # clear old exponent
 or.w  %d0,LOCAL_EX(%a0) # insert new exponent
 rts

#################################################################

# fmove out took an unimplemented data type exception.
# the src operand is in FP_SRC. Call _fout() to write out the result and
# to determine which exceptions, if any, to take.
fu_out:

# Separate packed move outs from the UNNORM and DENORM move outs.
 bfextu  EXC_CMDREG(%a6){&3:&3},%d0
 cmpi.b  %d0,&0x3
 beq.w  fu_out_pack
 cmpi.b  %d0,&0x7
 beq.w  fu_out_pack


# I'm not sure at this point what FPSR bits are valid for this instruction.
# so, since the emulation routines re-create them anyways, zero exception field.
# fmove out doesn't affect ccodes.
 and.l  &0xffff00ff,USER_FPSR(%a6) # zero exception field

 fmov.l  &0x0,%fpcr  # zero current control regs
 fmov.l  &0x0,%fpsr

# the src can ONLY be a DENORM or an UNNORM! so, don't make any big subroutine
# call here. just figure out what it is...
 mov.w  FP_SRC_EX(%a6),%d0 # get exponent
 andi.w  &0x7fff,%d0  # strip sign
 beq.b  fu_out_denorm  # it's a DENORM

 lea  FP_SRC(%a6),%a0
 bsr.l  unnorm_fix  # yes; fix it

 mov.b  %d0,STAG(%a6)

 bra.b  fu_out_cont
fu_out_denorm:
 mov.b  &DENORM,STAG(%a6)
fu_out_cont:

 clr.l  %d0
 mov.b  FPCR_MODE(%a6),%d0 # fetch rnd mode/prec

 lea  FP_SRC(%a6),%a0  # pass ptr to src operand

 mov.l  (%a6),EXC_A6(%a6) # in case a6 changes
 bsr.l  fout   # call fmove out routine

# Exceptions in order of precedence:
# BSUN : none
# SNAN : none
# OPERR : fmove.{b,w,l} out of large UNNORM
# OVFL : fmove.{s,d}
# UNFL : fmove.{s,d,x}
# DZ : none
# INEX2 : all
# INEX1 : none (packed doesn't travel through here)

# determine the highest priority exception(if any) set by the
# emulation routine that has also been enabled by the user.
 mov.b  FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled
 bne.w  fu_out_ena  # some are enabled

fu_out_done:

 mov.l  EXC_A6(%a6),(%a6) # in case a6 changed

# on extended precision opclass three instructions using pre-decrement or
# post-increment addressing mode, the address register is not updated. is the
# address register was the stack pointer used from user mode, then let's update
# it here. if it was used from supervisor mode, then we have to handle this
# as a special case.
 btst  &0x5,EXC_SR(%a6)
 bne.b  fu_out_done_s

 mov.l  EXC_A7(%a6),%a0  # restore a7
 mov.l  %a0,%usp

fu_out_done_cont:
 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 unlk  %a6

 btst  &0x7,(%sp)  # is trace on?
 bne.b  fu_out_trace  # yes

 bra.l  _fpsp_done

# is the ea mode pre-decrement of the stack pointer from supervisor mode?
# ("fmov.x fpm,-(a7)") if so,
fu_out_done_s:
 cmpi.b  SPCOND_FLG(%a6),&mda7_flg
 bne.b  fu_out_done_cont

# the extended precision result is still in fp0. but, we need to save it
# somewhere on the stack until we can copy it to its final resting place.
# here, we're counting on the top of the stack to be the old place-holders
# for fp0/fp1 which have already been restored. that way, we can write
# over those destinations with the shifted stack frame.
 fmovm.x  &0x80,FP_SRC(%a6) # put answer on stack

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 mov.l  (%a6),%a6  # restore frame pointer

 mov.l  LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
 mov.l  LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)

# now, copy the result to the proper place on the stack
 mov.l  LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
 mov.l  LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
 mov.l  LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)

 add.l  &LOCAL_SIZE-0x8,%sp

 btst  &0x7,(%sp)
 bne.b  fu_out_trace

 bra.l  _fpsp_done

fu_out_ena:
 and.b  FPSR_EXCEPT(%a6),%d0 # keep only ones enabled
 bfffo  %d0{&24:&8},%d0  # find highest priority exception
 bne.b  fu_out_exc  # there is at least one set

# no exceptions were set.
# if a disabled overflow occurred and inexact was enabled but the result
# was exact, then a branch to _real_inex() is made.
 btst  &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
 beq.w  fu_out_done  # no

fu_out_ovflchk:
 btst  &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
 beq.w  fu_out_done  # no
 bra.w  fu_inex   # yes

#
# The fp move out that took the "Unimplemented Data Type" exception was
# being traced. Since the stack frames are similar, get the "current" PC
# from FPIAR and put it in the trace stack frame then jump to _real_trace().
#
#    UNSUPP FRAME     TRACE FRAME
#  ***************** *****************
#  *      EA * *    Current *
#  *  * *      PC *
#  ***************** *****************
#  * 0x3 *  0x0dc * * 0x2 *  0x024 *
#  ***************** *****************
#  *     Next * *     Next *
#  *      PC * *      PC *
#  ***************** *****************
#  *      SR * *      SR *
#  ***************** *****************
#
fu_out_trace:
 mov.w  &0x2024,0x6(%sp)
 fmov.l  %fpiar,0x8(%sp)
 bra.l  _real_trace

# an exception occurred and that exception was enabled.
fu_out_exc:
 subi.l  &24,%d0   # fix offset to be 0-8

# we don't mess with the existing fsave frame. just re-insert it and
# jump to the "_real_{}()" handler...
 mov.w  (tbl_fu_out.b,%pc,%d0.w*2),%d0
 jmp  (tbl_fu_out.b,%pc,%d0.w*1)

 swbeg  &0x8
tbl_fu_out:
 short  tbl_fu_out - tbl_fu_out # BSUN can't happen
 short  tbl_fu_out - tbl_fu_out # SNAN can't happen
 short  fu_operr - tbl_fu_out # OPERR
 short  fu_ovfl  - tbl_fu_out # OVFL
 short  fu_unfl  - tbl_fu_out # UNFL
 short  tbl_fu_out - tbl_fu_out # DZ can't happen
 short  fu_inex  - tbl_fu_out # INEX2
 short  tbl_fu_out - tbl_fu_out # INEX1 won't make it here

# for snan,operr,ovfl,unfl, src op is still in FP_SRC so just
# frestore it.
fu_snan:
 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 mov.w  &0x30d8,EXC_VOFF(%a6) # vector offset = 0xd8
 mov.w  &0xe006,2+FP_SRC(%a6)

 frestore FP_SRC(%a6)

 unlk  %a6


 bra.l  _real_snan

fu_operr:
 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 mov.w  &0x30d0,EXC_VOFF(%a6) # vector offset = 0xd0
 mov.w  &0xe004,2+FP_SRC(%a6)

 frestore FP_SRC(%a6)

 unlk  %a6


 bra.l  _real_operr

fu_ovfl:
 fmovm.x  &0x40,FP_SRC(%a6) # save EXOP to the stack

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 mov.w  &0x30d4,EXC_VOFF(%a6) # vector offset = 0xd4
 mov.w  &0xe005,2+FP_SRC(%a6)

 frestore FP_SRC(%a6)  # restore EXOP

 unlk  %a6

 bra.l  _real_ovfl

# underflow can happen for extended precision. extended precision opclass
# three instruction exceptions don't update the stack pointer. so, if the
# exception occurred from user mode, then simply update a7 and exit normally.
# if the exception occurred from supervisor mode, check if
fu_unfl:
 mov.l  EXC_A6(%a6),(%a6) # restore a6

 btst  &0x5,EXC_SR(%a6)
 bne.w  fu_unfl_s

 mov.l  EXC_A7(%a6),%a0  # restore a7 whether we need
 mov.l  %a0,%usp  # to or not...

fu_unfl_cont:
 fmovm.x  &0x40,FP_SRC(%a6) # save EXOP to the stack

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 mov.w  &0x30cc,EXC_VOFF(%a6) # vector offset = 0xcc
 mov.w  &0xe003,2+FP_SRC(%a6)

 frestore FP_SRC(%a6)  # restore EXOP

 unlk  %a6

 bra.l  _real_unfl

fu_unfl_s:
 cmpi.b  SPCOND_FLG(%a6),&mda7_flg # was the <ea> mode -(sp)?
 bne.b  fu_unfl_cont

# the extended precision result is still in fp0. but, we need to save it
# somewhere on the stack until we can copy it to its final resting place
# (where the exc frame is currently). make sure it's not at the top of the
# frame or it will get overwritten when the exc stack frame is shifted "down".
 fmovm.x  &0x80,FP_SRC(%a6) # put answer on stack
 fmovm.x  &0x40,FP_DST(%a6) # put EXOP on stack

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 mov.w  &0x30cc,EXC_VOFF(%a6) # vector offset = 0xcc
 mov.w  &0xe003,2+FP_DST(%a6)

 frestore FP_DST(%a6)  # restore EXOP

 mov.l  (%a6),%a6  # restore frame pointer

 mov.l  LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
 mov.l  LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
 mov.l  LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)

# now, copy the result to the proper place on the stack
 mov.l  LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
 mov.l  LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
 mov.l  LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)

 add.l  &LOCAL_SIZE-0x8,%sp

 bra.l  _real_unfl

# fmove in and out enter here.
fu_inex:
 fmovm.x  &0x40,FP_SRC(%a6) # save EXOP to the stack

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 mov.w  &0x30c4,EXC_VOFF(%a6) # vector offset = 0xc4
 mov.w  &0xe001,2+FP_SRC(%a6)

 frestore FP_SRC(%a6)  # restore EXOP

 unlk  %a6


 bra.l  _real_inex

#########################################################################
#########################################################################
fu_in_pack:


# I'm not sure at this point what FPSR bits are valid for this instruction.
# so, since the emulation routines re-create them anyways, zero exception field
 andi.l  &0x0ff00ff,USER_FPSR(%a6) # zero exception field

 fmov.l  &0x0,%fpcr  # zero current control regs
 fmov.l  &0x0,%fpsr

 bsr.l  get_packed  # fetch packed src operand

 lea  FP_SRC(%a6),%a0  # pass ptr to src
 bsr.l  set_tag_x  # set src optype tag

 mov.b  %d0,STAG(%a6)  # save src optype tag

 bfextu  EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg

# bit five of the fp extension word separates the monadic and dyadic operations
# at this point
 btst  &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic?
 beq.b  fu_extract_p  # monadic
 cmpi.b  1+EXC_CMDREG(%a6),&0x3a # is operation an ftst?
 beq.b  fu_extract_p  # yes, so it's monadic, too

 bsr.l  load_fpn2  # load dst into FP_DST

 lea  FP_DST(%a6),%a0  # pass: ptr to dst op
 bsr.l  set_tag_x  # tag the operand type
 cmpi.b  %d0,&UNNORM  # is operand an UNNORM?
 bne.b  fu_op2_done_p  # no
 bsr.l  unnorm_fix  # yes; convert to NORM,DENORM,or ZERO
fu_op2_done_p:
 mov.b  %d0,DTAG(%a6)  # save dst optype tag

fu_extract_p:
 clr.l  %d0
 mov.b  FPCR_MODE(%a6),%d0 # fetch rnd mode/prec

 bfextu  1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension

 lea  FP_SRC(%a6),%a0
 lea  FP_DST(%a6),%a1

 mov.l  (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr
 jsr  (tbl_unsupp.l,%pc,%d1.l*1)

#
# Exceptions in order of precedence:
# BSUN : none
# SNAN : all dyadic ops
# OPERR : fsqrt(-NORM)
# OVFL : all except ftst,fcmp
# UNFL : all except ftst,fcmp
# DZ : fdiv
# INEX2 : all except ftst,fcmp
# INEX1 : all
#

# we determine the highest priority exception(if any) set by the
# emulation routine that has also been enabled by the user.
 mov.b  FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled
 bne.w  fu_in_ena_p  # some are enabled

fu_in_cont_p:
# fcmp and ftst do not store any result.
 mov.b  1+EXC_CMDREG(%a6),%d0 # fetch extension
 andi.b  &0x38,%d0  # extract bits 3-5
 cmpi.b  %d0,&0x38  # is instr fcmp or ftst?
 beq.b  fu_in_exit_p  # yes

 bfextu  EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
 bsr.l  store_fpreg  # store the result

fu_in_exit_p:

 btst  &0x5,EXC_SR(%a6) # user or supervisor?
 bne.w  fu_in_exit_s_p  # supervisor

 mov.l  EXC_A7(%a6),%a0  # update user a7
 mov.l  %a0,%usp

fu_in_exit_cont_p:
 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 unlk  %a6   # unravel stack frame

 btst  &0x7,(%sp)  # is trace on?
 bne.w  fu_trace_p  # yes

 bra.l  _fpsp_done  # exit to os

# the exception occurred in supervisor mode. check to see if the
# addressing mode was (a7)+. if so, we'll need to shift the
# stack frame "up".
fu_in_exit_s_p:
 btst  &mia7_bit,SPCOND_FLG(%a6) # was ea mode (a7)+
 beq.b  fu_in_exit_cont_p # no

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 unlk  %a6   # unravel stack frame

# shift the stack frame "up". we don't really care about the field.
 mov.l  0x4(%sp),0x10(%sp)
 mov.l  0x0(%sp),0xc(%sp)
 add.l  &0xc,%sp

 btst  &0x7,(%sp)  # is trace on?
 bne.w  fu_trace_p  # yes

 bra.l  _fpsp_done  # exit to os

fu_in_ena_p:
 and.b  FPSR_EXCEPT(%a6),%d0 # keep only ones enabled & set
 bfffo  %d0{&24:&8},%d0  # find highest priority exception
 bne.b  fu_in_exc_p  # at least one was set

#
# No exceptions occurred that were also enabled. Now:
#
# if (OVFL && ovfl_disabled && inexact_enabled) {
#     branch to _real_inex() (even if the result was exact!);
# } else {
#     save the result in the proper fp reg (unless the op is fcmp or ftst);
#     return;
# }
#
 btst  &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
 beq.w  fu_in_cont_p  # no

fu_in_ovflchk_p:
 btst  &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
 beq.w  fu_in_cont_p  # no
 bra.w  fu_in_exc_ovfl_p # do _real_inex() now

#
# An exception occurred and that exception was enabled:
#
# shift enabled exception field into lo byte of d0;
# if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) ||
#     ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) {
#  /*
#  * this is the case where we must call _real_inex() now or else
#  * there will be no other way to pass it the exceptional operand
#  */

#  call _real_inex();
# } else {
#  restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU;
# }
#
fu_in_exc_p:
 subi.l  &24,%d0   # fix offset to be 0-8
 cmpi.b  %d0,&0x6  # is exception INEX? (6 or 7)
 blt.b  fu_in_exc_exit_p # no

# the enabled exception was inexact
 btst  &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur?
 bne.w  fu_in_exc_unfl_p # yes
 btst  &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur?
 bne.w  fu_in_exc_ovfl_p # yes

# here, we insert the correct fsave status value into the fsave frame for the
# corresponding exception. the operand in the fsave frame should be the original
# src operand.
# as a reminder for future predicted pain and agony, we are passing in fsave the
"non-skewed" operand for cases of sgl and dbl src INFs,NANs, and DENORMs.
# this is INCORRECT for enabled SNAN which would give to the user the skewed SNAN!!!
fu_in_exc_exit_p:
 btst  &0x5,EXC_SR(%a6) # user or supervisor?
 bne.w  fu_in_exc_exit_s_p # supervisor

 mov.l  EXC_A7(%a6),%a0  # update user a7
 mov.l  %a0,%usp

fu_in_exc_exit_cont_p:
 mov.w  (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6)

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

 frestore FP_SRC(%a6)  # restore src op

 unlk  %a6

 btst  &0x7,(%sp)  # is trace enabled?
 bne.w  fu_trace_p  # yes

 bra.l  _fpsp_done

tbl_except_p:
 short  0xe000,0xe006,0xe004,0xe005
 short  0xe003,0xe002,0xe001,0xe001

fu_in_exc_ovfl_p:
 mov.w  &0x3,%d0
 bra.w  fu_in_exc_exit_p

fu_in_exc_unfl_p:
 mov.w  &0x4,%d0
 bra.w  fu_in_exc_exit_p

fu_in_exc_exit_s_p:
 btst  &mia7_bit,SPCOND_FLG(%a6)
 beq.b  fu_in_exc_exit_cont_p

 mov.w  (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6)

 fmovm.x  EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
 fmovm.l  USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 movm.l  EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=100 H=100 G=100

¤ Dauer der Verarbeitung: 0.19 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.