* $NetBSD: do_func.sa,v 1.3 2001/12/09 01:43:13 briggs Exp $ * MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP * M68000 Hi-Performance Microprocessor Division * M68040 Software Package * * M68040 Software Package Copyright (c) 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. * * do_func.sa 3.4 2/18/91 * * Do_func performs the unimplemented operation. The operation * to be performed is determined from the lower 7 bits of the * extension word (except in the case of fmovecr and fsincos). * The opcode and tag bits form an index into a jump table in * tbldo.sa. Cases of zero, infinity and NaN are handled in * do_func by forcing the default result. Normalized and * denormalized (there are no unnormalized numbers at this * point) are passed onto the emulation code. * * CMDREG1B and STAG are extracted from the fsave frame * and combined to form the table index. The function called * will start with a0 pointing to the ETEMP operand. Dyadic * functions can find FPTEMP at -12(a0). * * Called functions return their result in fp0. Sincos returns * sin(x) in fp0 and cos(x) in fp1. * DO_FUNC IDNT 2,1 Motorola 040 Floating Point Software Package section 8 include fpsp.h xref t_dz2 xref t_operr xref t_inx2 xref t_resdnrm xref dst_nan xref src_nan xref nrm_set xref sto_cos xref tblpre xref slognp1,slogn,slog10,slog2 xref slognd,slog10d,slog2d xref smod,srem xref sscale xref smovcr PONE dc.l $3fff0000,$80000000,$00000000 ;+1 MONE dc.l $bfff0000,$80000000,$00000000 ;-1 PZERO dc.l $00000000,$00000000,$00000000 ;+0 MZERO dc.l $80000000,$00000000,$00000000 ;-0 PINF dc.l $7fff0000,$00000000,$00000000 ;+inf MINF dc.l $ffff0000,$00000000,$00000000 ;-inf QNAN dc.l $7fff0000,$ffffffff,$ffffffff ;non-signaling nan PPIBY2 dc.l $3FFF0000,$C90FDAA2,$2168C235 ;+PI/2 MPIBY2 dc.l $bFFF0000,$C90FDAA2,$2168C235 ;-PI/2 xdef do_func do_func: clr.b CU_ONLY(a6) * * Check for fmovecr. It does not follow the format of fp gen * unimplemented instructions. The test is on the upper 6 bits; * if they are $17, the inst is fmovecr. Call entry smovcr * directly. * bfextu CMDREG1B(a6){0:6},d0 ;get opclass and src fields cmpi.l #$17,d0 ;if op class and size fields are $17, * ;it is FMOVECR; if not, continue bne.b not_fmovecr jmp smovcr ;fmovecr; jmp directly to emulation not_fmovecr: move.w CMDREG1B(a6),d0 and.l #$7F,d0 cmpi.l #$38,d0 ;if the extension is >= $38, bge.b short_serror ;it is illegal bfextu STAG(a6){0:3},d1 lsl.l #3,d0 ;make room for STAG add.l d1,d0 ;combine for final index into table lea.l tblpre,a1 ;start of monster jump table move.l (a1,d0.w*4),a1 ;real target address lea.l ETEMP(a6),a0 ;a0 is pointer to src op move.l USER_FPCR(a6),d1 and.l #$FF,d1 ; discard all but rounding mode/prec fmove.l #0,fpcr jmp (a1) * * ERROR * xdef serror serror: short_serror: st.b STORE_FLG(a6) rts * * These routines load forced values into fp0. They are called * by index into tbldo. * * Load a signed zero to fp0 and set inex2/ainex * xdef snzrinx snzrinx: btst.b #sign_bit,LOCAL_EX(a0) ;get sign of source operand bne.b ld_mzinx ;if negative, branch bsr ld_pzero ;bsr so we can return and set inx bra t_inx2 ;now, set the inx for the next inst ld_mzinx: bsr ld_mzero ;if neg, load neg zero, return here bra t_inx2 ;now, set the inx for the next inst * * Load a signed zero to fp0; do not set inex2/ainex * xdef szero szero: btst.b #sign_bit,LOCAL_EX(a0) ;get sign of source operand bne ld_mzero ;if neg, load neg zero bra ld_pzero ;load positive zero * * Load a signed infinity to fp0; do not set inex2/ainex * xdef sinf sinf: btst.b #sign_bit,LOCAL_EX(a0) ;get sign of source operand bne ld_minf ;if negative branch bra ld_pinf * * Load a signed one to fp0; do not set inex2/ainex * xdef sone sone: btst.b #sign_bit,LOCAL_EX(a0) ;check sign of source bne ld_mone bra ld_pone * * Load a signed pi/2 to fp0; do not set inex2/ainex * xdef spi_2 spi_2: btst.b #sign_bit,LOCAL_EX(a0) ;check sign of source bne ld_mpi2 bra ld_ppi2 * * Load either a +0 or +inf for plus/minus operand * xdef szr_inf szr_inf: btst.b #sign_bit,LOCAL_EX(a0) ;check sign of source bne ld_pzero bra ld_pinf * * Result is either an operr or +inf for plus/minus operand * [Used by slogn, slognp1, slog10, and slog2] * xdef sopr_inf sopr_inf: btst.b #sign_bit,LOCAL_EX(a0) ;check sign of source bne t_operr bra ld_pinf * * FLOGNP1 * xdef sslognp1 sslognp1: fmovem.x (a0),fp0 fcmp.b #-1,fp0 fbgt slognp1 fbeq t_dz2 ;if = -1, divide by zero exception fmove.l #0,FPSR ;clr N flag bra t_operr ;take care of operands < -1 * * FETOXM1 * xdef setoxm1i setoxm1i: btst.b #sign_bit,LOCAL_EX(a0) ;check sign of source bne ld_mone bra ld_pinf * * FLOGN * * Test for 1.0 as an input argument, returning +zero. Also check * the sign and return operr if negative. * xdef sslogn sslogn: btst.b #sign_bit,LOCAL_EX(a0) bne t_operr ;take care of operands < 0 cmpi.w #$3fff,LOCAL_EX(a0) ;test for 1.0 input bne slogn cmpi.l #$80000000,LOCAL_HI(a0) bne slogn tst.l LOCAL_LO(a0) bne slogn fmove.x PZERO,fp0 rts xdef sslognd sslognd: btst.b #sign_bit,LOCAL_EX(a0) beq slognd bra t_operr ;take care of operands < 0 * * FLOG10 * xdef sslog10 sslog10: btst.b #sign_bit,LOCAL_EX(a0) bne t_operr ;take care of operands < 0 cmpi.w #$3fff,LOCAL_EX(a0) ;test for 1.0 input bne slog10 cmpi.l #$80000000,LOCAL_HI(a0) bne slog10 tst.l LOCAL_LO(a0) bne slog10 fmove.x PZERO,fp0 rts xdef sslog10d sslog10d: btst.b #sign_bit,LOCAL_EX(a0) beq slog10d bra t_operr ;take care of operands < 0 * * FLOG2 * xdef sslog2 sslog2: btst.b #sign_bit,LOCAL_EX(a0) bne t_operr ;take care of operands < 0 cmpi.w #$3fff,LOCAL_EX(a0) ;test for 1.0 input bne slog2 cmpi.l #$80000000,LOCAL_HI(a0) bne slog2 tst.l LOCAL_LO(a0) bne slog2 fmove.x PZERO,fp0 rts xdef sslog2d sslog2d: btst.b #sign_bit,LOCAL_EX(a0) beq slog2d bra t_operr ;take care of operands < 0 * * FMOD * pmodt: * ;$21 fmod * ;dtag,stag dc.l smod ; 00,00 norm,norm = normal dc.l smod_oper ; 00,01 norm,zero = nan with operr dc.l smod_fpn ; 00,10 norm,inf = fpn dc.l smod_snan ; 00,11 norm,nan = nan dc.l smod_zro ; 01,00 zero,norm = +-zero dc.l smod_oper ; 01,01 zero,zero = nan with operr dc.l smod_zro ; 01,10 zero,inf = +-zero dc.l smod_snan ; 01,11 zero,nan = nan dc.l smod_oper ; 10,00 inf,norm = nan with operr dc.l smod_oper ; 10,01 inf,zero = nan with operr dc.l smod_oper ; 10,10 inf,inf = nan with operr dc.l smod_snan ; 10,11 inf,nan = nan dc.l smod_dnan ; 11,00 nan,norm = nan dc.l smod_dnan ; 11,01 nan,zero = nan dc.l smod_dnan ; 11,10 nan,inf = nan dc.l smod_dnan ; 11,11 nan,nan = nan xdef pmod pmod: clr.b FPSR_QBYTE(a6) ; clear quotient field bfextu STAG(a6){0:3},d0 ;stag = d0 bfextu DTAG(a6){0:3},d1 ;dtag = d1 * * Alias extended denorms to norms for the jump table. * bclr.l #2,d0 bclr.l #2,d1 lsl.b #2,d1 or.b d0,d1 ;d1{3:2} = dtag, d1{1:0} = stag * ;Tag values: * ;00 = norm or denorm * ;01 = zero * ;10 = inf * ;11 = nan lea pmodt,a1 move.l (a1,d1.w*4),a1 jmp (a1) smod_snan: bra src_nan smod_dnan: bra dst_nan smod_oper: bra t_operr smod_zro: move.b ETEMP(a6),d1 ;get sign of src op move.b FPTEMP(a6),d0 ;get sign of dst op eor.b d0,d1 ;get exor of sign bits btst.l #7,d1 ;test for sign beq.b smod_zsn ;if clr, do not set sign big bset.b #q_sn_bit,FPSR_QBYTE(a6) ;set q-byte sign bit smod_zsn: btst.l #7,d0 ;test if + or - beq ld_pzero ;if pos then load +0 bra ld_mzero ;else neg load -0 smod_fpn: move.b ETEMP(a6),d1 ;get sign of src op move.b FPTEMP(a6),d0 ;get sign of dst op eor.b d0,d1 ;get exor of sign bits btst.l #7,d1 ;test for sign beq.b smod_fsn ;if clr, do not set sign big bset.b #q_sn_bit,FPSR_QBYTE(a6) ;set q-byte sign bit smod_fsn: tst.b DTAG(a6) ;filter out denormal destination case bpl.b smod_nrm ; lea.l FPTEMP(a6),a0 ;a0<- addr(FPTEMP) bra t_resdnrm ;force UNFL(but exact) result smod_nrm: fmove.l USER_FPCR(a6),fpcr ;use user's rmode and precision fmove.x FPTEMP(a6),fp0 ;return dest to fp0 rts * * FREM * premt: * ;$25 frem * ;dtag,stag dc.l srem ; 00,00 norm,norm = normal dc.l srem_oper ; 00,01 norm,zero = nan with operr dc.l srem_fpn ; 00,10 norm,inf = fpn dc.l srem_snan ; 00,11 norm,nan = nan dc.l srem_zro ; 01,00 zero,norm = +-zero dc.l srem_oper ; 01,01 zero,zero = nan with operr dc.l srem_zro ; 01,10 zero,inf = +-zero dc.l srem_snan ; 01,11 zero,nan = nan dc.l srem_oper ; 10,00 inf,norm = nan with operr dc.l srem_oper ; 10,01 inf,zero = nan with operr dc.l srem_oper ; 10,10 inf,inf = nan with operr dc.l srem_snan ; 10,11 inf,nan = nan dc.l srem_dnan ; 11,00 nan,norm = nan dc.l srem_dnan ; 11,01 nan,zero = nan dc.l srem_dnan ; 11,10 nan,inf = nan dc.l srem_dnan ; 11,11 nan,nan = nan xdef prem prem: clr.b FPSR_QBYTE(a6) ;clear quotient field bfextu STAG(a6){0:3},d0 ;stag = d0 bfextu DTAG(a6){0:3},d1 ;dtag = d1 * * Alias extended denorms to norms for the jump table. * bclr #2,d0 bclr #2,d1 lsl.b #2,d1 or.b d0,d1 ;d1{3:2} = dtag, d1{1:0} = stag * ;Tag values: * ;00 = norm or denorm * ;01 = zero * ;10 = inf * ;11 = nan lea premt,a1 move.l (a1,d1.w*4),a1 jmp (a1) srem_snan: bra src_nan srem_dnan: bra dst_nan srem_oper: bra t_operr srem_zro: move.b ETEMP(a6),d1 ;get sign of src op move.b FPTEMP(a6),d0 ;get sign of dst op eor.b d0,d1 ;get exor of sign bits btst.l #7,d1 ;test for sign beq.b srem_zsn ;if clr, do not set sign big bset.b #q_sn_bit,FPSR_QBYTE(a6) ;set q-byte sign bit srem_zsn: btst.l #7,d0 ;test if + or - beq ld_pzero ;if pos then load +0 bra ld_mzero ;else neg load -0 srem_fpn: move.b ETEMP(a6),d1 ;get sign of src op move.b FPTEMP(a6),d0 ;get sign of dst op eor.b d0,d1 ;get exor of sign bits btst.l #7,d1 ;test for sign beq.b srem_fsn ;if clr, do not set sign big bset.b #q_sn_bit,FPSR_QBYTE(a6) ;set q-byte sign bit srem_fsn: tst.b DTAG(a6) ;filter out denormal destination case bpl.b srem_nrm ; lea.l FPTEMP(a6),a0 ;a0<- addr(FPTEMP) bra t_resdnrm ;force UNFL(but exact) result srem_nrm: fmove.l USER_FPCR(a6),fpcr ;use user's rmode and precision fmove.x FPTEMP(a6),fp0 ;return dest to fp0 rts * * FSCALE * pscalet: * ;$26 fscale * ;dtag,stag dc.l sscale ; 00,00 norm,norm = result dc.l sscale ; 00,01 norm,zero = fpn dc.l scl_opr ; 00,10 norm,inf = nan with operr dc.l scl_snan ; 00,11 norm,nan = nan dc.l scl_zro ; 01,00 zero,norm = +-zero dc.l scl_zro ; 01,01 zero,zero = +-zero dc.l scl_opr ; 01,10 zero,inf = nan with operr dc.l scl_snan ; 01,11 zero,nan = nan dc.l scl_inf ; 10,00 inf,norm = +-inf dc.l scl_inf ; 10,01 inf,zero = +-inf dc.l scl_opr ; 10,10 inf,inf = nan with operr dc.l scl_snan ; 10,11 inf,nan = nan dc.l scl_dnan ; 11,00 nan,norm = nan dc.l scl_dnan ; 11,01 nan,zero = nan dc.l scl_dnan ; 11,10 nan,inf = nan dc.l scl_dnan ; 11,11 nan,nan = nan xdef pscale pscale: bfextu STAG(a6){0:3},d0 ;stag in d0 bfextu DTAG(a6){0:3},d1 ;dtag in d1 bclr.l #2,d0 ;alias denorm into norm bclr.l #2,d1 ;alias denorm into norm lsl.b #2,d1 or.b d0,d1 ;d1{4:2} = dtag, d1{1:0} = stag * ;dtag values stag values: * ;000 = norm 00 = norm * ;001 = zero 01 = zero * ;010 = inf 10 = inf * ;011 = nan 11 = nan * ;100 = dnrm * * lea.l pscalet,a1 ;load start of jump table move.l (a1,d1.w*4),a1 ;load a1 with label depending on tag jmp (a1) ;go to the routine scl_opr: bra t_operr scl_dnan: bra dst_nan scl_zro: btst.b #sign_bit,FPTEMP_EX(a6) ;test if + or - beq ld_pzero ;if pos then load +0 bra ld_mzero ;if neg then load -0 scl_inf: btst.b #sign_bit,FPTEMP_EX(a6) ;test if + or - beq ld_pinf ;if pos then load +inf bra ld_minf ;else neg load -inf scl_snan: bra src_nan * * FSINCOS * xdef ssincosz ssincosz: btst.b #sign_bit,ETEMP(a6) ;get sign beq.b sincosp fmove.x MZERO,fp0 bra.b sincoscom sincosp: fmove.x PZERO,fp0 sincoscom: fmovem.x PONE,fp1 ;do not allow FPSR to be affected bra sto_cos ;store cosine result xdef ssincosi ssincosi: fmove.x QNAN,fp1 ;load NAN bsr sto_cos ;store cosine result fmove.x QNAN,fp0 ;load NAN bra t_operr xdef ssincosnan ssincosnan: move.l ETEMP_EX(a6),FP_SCR1(a6) move.l ETEMP_HI(a6),FP_SCR1+4(a6) move.l ETEMP_LO(a6),FP_SCR1+8(a6) bset.b #signan_bit,FP_SCR1+4(a6) fmovem.x FP_SCR1(a6),fp1 bsr sto_cos bra src_nan * * This code forces default values for the zero, inf, and nan cases * in the transcendentals code. The CC bits must be set in the * stacked FPSR to be correctly reported. * ***Returns +PI/2 xdef ld_ppi2 ld_ppi2: fmove.x PPIBY2,fp0 ;load +pi/2 bra t_inx2 ;set inex2 exc ***Returns -PI/2 xdef ld_mpi2 ld_mpi2: fmove.x MPIBY2,fp0 ;load -pi/2 or.l #neg_mask,USER_FPSR(a6) ;set N bit bra t_inx2 ;set inex2 exc ***Returns +inf xdef ld_pinf ld_pinf: fmove.x PINF,fp0 ;load +inf or.l #inf_mask,USER_FPSR(a6) ;set I bit rts ***Returns -inf xdef ld_minf ld_minf: fmove.x MINF,fp0 ;load -inf or.l #neg_mask+inf_mask,USER_FPSR(a6) ;set N and I bits rts ***Returns +1 xdef ld_pone ld_pone: fmove.x PONE,fp0 ;load +1 rts ***Returns -1 xdef ld_mone ld_mone: fmove.x MONE,fp0 ;load -1 or.l #neg_mask,USER_FPSR(a6) ;set N bit rts ***Returns +0 xdef ld_pzero ld_pzero: fmove.x PZERO,fp0 ;load +0 or.l #z_mask,USER_FPSR(a6) ;set Z bit rts ***Returns -0 xdef ld_mzero ld_mzero: fmove.x MZERO,fp0 ;load -0 or.l #neg_mask+z_mask,USER_FPSR(a6) ;set N and Z bits rts end