/kern_oII/arch/m68k/ifpsp060/src/pfpsp.S
http://omnia2droid.googlecode.com/ · Assembly · 14745 lines · 13546 code · 1193 blank · 6 comment · 323 complexity · e3acf523978f068fa9c0039c051d6211 MD5 · raw file
Large files are truncated click here to view the full file
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 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
- # undeflow 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 s…