📄 pfpsp.s
字号:
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 stackfu_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 ZEROfu_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 ZEROfu_op2_done: mov.b %d0,DTAG(%a6) # save dst optype tagfu_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 enabledfu_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 resultfu_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_donefu_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 # nofu_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_donetbl_except: short 0xe000,0xe006,0xe004,0xe005 short 0xe003,0xe002,0xe001,0xe001fu_in_exc_unfl: mov.w &0x4,%d0 bra.b fu_in_exc_exitfu_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_opsfix_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 # nofso_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 # nofso_sgl_dnrm_zero: andi.l &0x7fffffff,LOCAL_HI(%a0) # clear j-bit beq.b fso_zero # it's a skewed zerofso_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 rtsfso_zero: andi.w &0x8000,LOCAL_EX(%a0) # clear bogus exponent rtsfso_infnan: andi.b &0x7f,LOCAL_HI(%a0) # clear j-bit ori.w &0x7fff,LOCAL_EX(%a0) # make exponent = $7fff rtsfso_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 # nofso_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 # yesfso_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_contfu_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 enabledfu_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,%uspfu_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_donefu_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -