File indexing completed on 2025-05-11 08:23:48
0001 #include "fpsp-namespace.h"
0002 //
0003 //
0004 // res_func.sa 3.9 7/29/91
0005 //
0006 // Normalizes denormalized numbers if necessary and updates the
0007 // stack frame. The function is then restored back into the
0008 // machine and the 040 completes the operation. This routine
0009 // is only used by the unsupported data type/format handler.
0010 // (Exception vector 55).
0011 //
0012 // For packed move out (fmove.p fpm,<ea>) the operation is
0013 // completed here; data is packed and moved to user memory.
0014 // The stack is restored to the 040 only in the case of a
0015 // reportable exception in the conversion.
0016 //
0017 //
0018 // Copyright (C) Motorola, Inc. 1990
0019 // All Rights Reserved
0020 //
0021 // THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
0022 // The copyright notice above does not evidence any
0023 // actual or intended publication of such source code.
0024
0025 RES_FUNC: //idnt 2,1 | Motorola 040 Floating Point Software Package
0026
0027 |section 8
0028
0029 #include "fpsp.defs"
0030
0031 sp_bnds: .short 0x3f81,0x407e
0032 .short 0x3f6a,0x0000
0033 dp_bnds: .short 0x3c01,0x43fe
0034 .short 0x3bcd,0x0000
0035
0036 |xref mem_write
0037 |xref bindec
0038 |xref get_fline
0039 |xref round
0040 |xref denorm
0041 |xref dest_ext
0042 |xref dest_dbl
0043 |xref dest_sgl
0044 |xref unf_sub
0045 |xref nrm_set
0046 |xref dnrm_lp
0047 |xref ovf_res
0048 |xref reg_dest
0049 |xref t_ovfl
0050 |xref t_unfl
0051
0052 .global res_func
0053 .global p_move
0054
0055 res_func:
0056 clrb DNRM_FLG(%a6)
0057 clrb RES_FLG(%a6)
0058 clrb CU_ONLY(%a6)
0059 tstb DY_MO_FLG(%a6)
0060 beqs monadic
0061 dyadic:
0062 btstb #7,DTAG(%a6) //if dop = norm=000, zero=001,
0063 // ;inf=010 or nan=011
0064 beqs monadic //then branch
0065 // ;else denorm
0066 // HANDLE DESTINATION DENORM HERE
0067 // ;set dtag to norm
0068 // ;write the tag & fpte15 to the fstack
0069 leal FPTEMP(%a6),%a0
0070
0071 bclrb #sign_bit,LOCAL_EX(%a0)
0072 sne LOCAL_SGN(%a0)
0073
0074 bsr nrm_set //normalize number (exp will go negative)
0075 bclrb #sign_bit,LOCAL_EX(%a0) //get rid of false sign
0076 bfclr LOCAL_SGN(%a0){#0:#8} //change back to IEEE ext format
0077 beqs dpos
0078 bsetb #sign_bit,LOCAL_EX(%a0)
0079 dpos:
0080 bfclr DTAG(%a6){#0:#4} //set tag to normalized, FPTE15 = 0
0081 bsetb #4,DTAG(%a6) //set FPTE15
0082 orb #0x0f,DNRM_FLG(%a6)
0083 monadic:
0084 leal ETEMP(%a6),%a0
0085 btstb #direction_bit,CMDREG1B(%a6) //check direction
0086 bne opclass3 //it is a mv out
0087 //
0088 // At this point, only opclass 0 and 2 possible
0089 //
0090 btstb #7,STAG(%a6) //if sop = norm=000, zero=001,
0091 // ;inf=010 or nan=011
0092 bne mon_dnrm //else denorm
0093 tstb DY_MO_FLG(%a6) //all cases of dyadic instructions would
0094 bne normal //require normalization of denorm
0095
0096 // At this point:
0097 // monadic instructions: fabs = $18 fneg = $1a ftst = $3a
0098 // fmove = $00 fsmove = $40 fdmove = $44
0099 // fsqrt = $05* fssqrt = $41 fdsqrt = $45
0100 // (*fsqrt reencoded to $05)
0101 //
0102 movew CMDREG1B(%a6),%d0 //get command register
0103 andil #0x7f,%d0 //strip to only command word
0104 //
0105 // At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
0106 // fdsqrt are possible.
0107 // For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
0108 // For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
0109 //
0110 btstl #0,%d0
0111 bne normal //weed out fsqrt instructions
0112 //
0113 // cu_norm handles fmove in instructions with normalized inputs.
0114 // The routine round is used to correctly round the input for the
0115 // destination precision and mode.
0116 //
0117 cu_norm:
0118 st CU_ONLY(%a6) //set cu-only inst flag
0119 movew CMDREG1B(%a6),%d0
0120 andib #0x3b,%d0 //isolate bits to select inst
0121 tstb %d0
0122 beql cu_nmove //if zero, it is an fmove
0123 cmpib #0x18,%d0
0124 beql cu_nabs //if $18, it is fabs
0125 cmpib #0x1a,%d0
0126 beql cu_nneg //if $1a, it is fneg
0127 //
0128 // Inst is ftst. Check the source operand and set the cc's accordingly.
0129 // No write is done, so simply rts.
0130 //
0131 cu_ntst:
0132 movew LOCAL_EX(%a0),%d0
0133 bclrl #15,%d0
0134 sne LOCAL_SGN(%a0)
0135 beqs cu_ntpo
0136 orl #neg_mask,USER_FPSR(%a6) //set N
0137 cu_ntpo:
0138 cmpiw #0x7fff,%d0 //test for inf/nan
0139 bnes cu_ntcz
0140 tstl LOCAL_HI(%a0)
0141 bnes cu_ntn
0142 tstl LOCAL_LO(%a0)
0143 bnes cu_ntn
0144 orl #inf_mask,USER_FPSR(%a6)
0145 rts
0146 cu_ntn:
0147 orl #nan_mask,USER_FPSR(%a6)
0148 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) //set up fptemp sign for
0149 // ;snan handler
0150
0151 rts
0152 cu_ntcz:
0153 tstl LOCAL_HI(%a0)
0154 bnel cu_ntsx
0155 tstl LOCAL_LO(%a0)
0156 bnel cu_ntsx
0157 orl #z_mask,USER_FPSR(%a6)
0158 cu_ntsx:
0159 rts
0160 //
0161 // Inst is fabs. Execute the absolute value function on the input.
0162 // Branch to the fmove code. If the operand is NaN, do nothing.
0163 //
0164 cu_nabs:
0165 moveb STAG(%a6),%d0
0166 btstl #5,%d0 //test for NaN or zero
0167 bne wr_etemp //if either, simply write it
0168 bclrb #7,LOCAL_EX(%a0) //do abs
0169 bras cu_nmove //fmove code will finish
0170 //
0171 // Inst is fneg. Execute the negate value function on the input.
0172 // Fall though to the fmove code. If the operand is NaN, do nothing.
0173 //
0174 cu_nneg:
0175 moveb STAG(%a6),%d0
0176 btstl #5,%d0 //test for NaN or zero
0177 bne wr_etemp //if either, simply write it
0178 bchgb #7,LOCAL_EX(%a0) //do neg
0179 //
0180 // Inst is fmove. This code also handles all result writes.
0181 // If bit 2 is set, round is forced to double. If it is clear,
0182 // and bit 6 is set, round is forced to single. If both are clear,
0183 // the round precision is found in the fpcr. If the rounding precision
0184 // is double or single, round the result before the write.
0185 //
0186 cu_nmove:
0187 moveb STAG(%a6),%d0
0188 andib #0xe0,%d0 //isolate stag bits
0189 bne wr_etemp //if not norm, simply write it
0190 btstb #2,CMDREG1B+1(%a6) //check for rd
0191 bne cu_nmrd
0192 btstb #6,CMDREG1B+1(%a6) //check for rs
0193 bne cu_nmrs
0194 //
0195 // The move or operation is not with forced precision. Test for
0196 // nan or inf as the input; if so, simply write it to FPn. Use the
0197 // FPCR_MODE byte to get rounding on norms and zeros.
0198 //
0199 cu_nmnr:
0200 bfextu FPCR_MODE(%a6){#0:#2},%d0
0201 tstb %d0 //check for extended
0202 beq cu_wrexn //if so, just write result
0203 cmpib #1,%d0 //check for single
0204 beq cu_nmrs //fall through to double
0205 //
0206 // The move is fdmove or round precision is double.
0207 //
0208 cu_nmrd:
0209 movel #2,%d0 //set up the size for denorm
0210 movew LOCAL_EX(%a0),%d1 //compare exponent to double threshold
0211 andw #0x7fff,%d1
0212 cmpw #0x3c01,%d1
0213 bls cu_nunfl
0214 bfextu FPCR_MODE(%a6){#2:#2},%d1 //get rmode
0215 orl #0x00020000,%d1 //or in rprec (double)
0216 clrl %d0 //clear g,r,s for round
0217 bclrb #sign_bit,LOCAL_EX(%a0) //convert to internal format
0218 sne LOCAL_SGN(%a0)
0219 bsrl round
0220 bfclr LOCAL_SGN(%a0){#0:#8}
0221 beqs cu_nmrdc
0222 bsetb #sign_bit,LOCAL_EX(%a0)
0223 cu_nmrdc:
0224 movew LOCAL_EX(%a0),%d1 //check for overflow
0225 andw #0x7fff,%d1
0226 cmpw #0x43ff,%d1
0227 bge cu_novfl //take care of overflow case
0228 bra cu_wrexn
0229 //
0230 // The move is fsmove or round precision is single.
0231 //
0232 cu_nmrs:
0233 movel #1,%d0
0234 movew LOCAL_EX(%a0),%d1
0235 andw #0x7fff,%d1
0236 cmpw #0x3f81,%d1
0237 bls cu_nunfl
0238 bfextu FPCR_MODE(%a6){#2:#2},%d1
0239 orl #0x00010000,%d1
0240 clrl %d0
0241 bclrb #sign_bit,LOCAL_EX(%a0)
0242 sne LOCAL_SGN(%a0)
0243 bsrl round
0244 bfclr LOCAL_SGN(%a0){#0:#8}
0245 beqs cu_nmrsc
0246 bsetb #sign_bit,LOCAL_EX(%a0)
0247 cu_nmrsc:
0248 movew LOCAL_EX(%a0),%d1
0249 andw #0x7FFF,%d1
0250 cmpw #0x407f,%d1
0251 blt cu_wrexn
0252 //
0253 // The operand is above precision boundaries. Use t_ovfl to
0254 // generate the correct value.
0255 //
0256 cu_novfl:
0257 bsr t_ovfl
0258 bra cu_wrexn
0259 //
0260 // The operand is below precision boundaries. Use denorm to
0261 // generate the correct value.
0262 //
0263 cu_nunfl:
0264 bclrb #sign_bit,LOCAL_EX(%a0)
0265 sne LOCAL_SGN(%a0)
0266 bsr denorm
0267 bfclr LOCAL_SGN(%a0){#0:#8} //change back to IEEE ext format
0268 beqs cu_nucont
0269 bsetb #sign_bit,LOCAL_EX(%a0)
0270 cu_nucont:
0271 bfextu FPCR_MODE(%a6){#2:#2},%d1
0272 btstb #2,CMDREG1B+1(%a6) //check for rd
0273 bne inst_d
0274 btstb #6,CMDREG1B+1(%a6) //check for rs
0275 bne inst_s
0276 swap %d1
0277 moveb FPCR_MODE(%a6),%d1
0278 lsrb #6,%d1
0279 swap %d1
0280 bra inst_sd
0281 inst_d:
0282 orl #0x00020000,%d1
0283 bra inst_sd
0284 inst_s:
0285 orl #0x00010000,%d1
0286 inst_sd:
0287 bclrb #sign_bit,LOCAL_EX(%a0)
0288 sne LOCAL_SGN(%a0)
0289 bsrl round
0290 bfclr LOCAL_SGN(%a0){#0:#8}
0291 beqs cu_nuflp
0292 bsetb #sign_bit,LOCAL_EX(%a0)
0293 cu_nuflp:
0294 btstb #inex2_bit,FPSR_EXCEPT(%a6)
0295 beqs cu_nuninx
0296 orl #aunfl_mask,USER_FPSR(%a6) //if the round was inex, set AUNFL
0297 cu_nuninx:
0298 tstl LOCAL_HI(%a0) //test for zero
0299 bnes cu_nunzro
0300 tstl LOCAL_LO(%a0)
0301 bnes cu_nunzro
0302 //
0303 // The mantissa is zero from the denorm loop. Check sign and rmode
0304 // to see if rounding should have occurred which would leave the lsb.
0305 //
0306 movel USER_FPCR(%a6),%d0
0307 andil #0x30,%d0 //isolate rmode
0308 cmpil #0x20,%d0
0309 blts cu_nzro
0310 bnes cu_nrp
0311 cu_nrm:
0312 tstw LOCAL_EX(%a0) //if positive, set lsb
0313 bges cu_nzro
0314 btstb #7,FPCR_MODE(%a6) //check for double
0315 beqs cu_nincs
0316 bras cu_nincd
0317 cu_nrp:
0318 tstw LOCAL_EX(%a0) //if positive, set lsb
0319 blts cu_nzro
0320 btstb #7,FPCR_MODE(%a6) //check for double
0321 beqs cu_nincs
0322 cu_nincd:
0323 orl #0x800,LOCAL_LO(%a0) //inc for double
0324 bra cu_nunzro
0325 cu_nincs:
0326 orl #0x100,LOCAL_HI(%a0) //inc for single
0327 bra cu_nunzro
0328 cu_nzro:
0329 orl #z_mask,USER_FPSR(%a6)
0330 moveb STAG(%a6),%d0
0331 andib #0xe0,%d0
0332 cmpib #0x40,%d0 //check if input was tagged zero
0333 beqs cu_numv
0334 cu_nunzro:
0335 orl #unfl_mask,USER_FPSR(%a6) //set unfl
0336 cu_numv:
0337 movel (%a0),ETEMP(%a6)
0338 movel 4(%a0),ETEMP_HI(%a6)
0339 movel 8(%a0),ETEMP_LO(%a6)
0340 //
0341 // Write the result to memory, setting the fpsr cc bits. NaN and Inf
0342 // bypass cu_wrexn.
0343 //
0344 cu_wrexn:
0345 tstw LOCAL_EX(%a0) //test for zero
0346 beqs cu_wrzero
0347 cmpw #0x8000,LOCAL_EX(%a0) //test for zero
0348 bnes cu_wreon
0349 cu_wrzero:
0350 orl #z_mask,USER_FPSR(%a6) //set Z bit
0351 cu_wreon:
0352 tstw LOCAL_EX(%a0)
0353 bpl wr_etemp
0354 orl #neg_mask,USER_FPSR(%a6)
0355 bra wr_etemp
0356
0357 //
0358 // HANDLE SOURCE DENORM HERE
0359 //
0360 // ;clear denorm stag to norm
0361 // ;write the new tag & ete15 to the fstack
0362 mon_dnrm:
0363 //
0364 // At this point, check for the cases in which normalizing the
0365 // denorm produces incorrect results.
0366 //
0367 tstb DY_MO_FLG(%a6) //all cases of dyadic instructions would
0368 bnes nrm_src //require normalization of denorm
0369
0370 // At this point:
0371 // monadic instructions: fabs = $18 fneg = $1a ftst = $3a
0372 // fmove = $00 fsmove = $40 fdmove = $44
0373 // fsqrt = $05* fssqrt = $41 fdsqrt = $45
0374 // (*fsqrt reencoded to $05)
0375 //
0376 movew CMDREG1B(%a6),%d0 //get command register
0377 andil #0x7f,%d0 //strip to only command word
0378 //
0379 // At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
0380 // fdsqrt are possible.
0381 // For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
0382 // For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
0383 //
0384 btstl #0,%d0
0385 bnes nrm_src //weed out fsqrt instructions
0386 st CU_ONLY(%a6) //set cu-only inst flag
0387 bra cu_dnrm //fmove, fabs, fneg, ftst
0388 // ;cases go to cu_dnrm
0389 nrm_src:
0390 bclrb #sign_bit,LOCAL_EX(%a0)
0391 sne LOCAL_SGN(%a0)
0392 bsr nrm_set //normalize number (exponent will go
0393 // ; negative)
0394 bclrb #sign_bit,LOCAL_EX(%a0) //get rid of false sign
0395
0396 bfclr LOCAL_SGN(%a0){#0:#8} //change back to IEEE ext format
0397 beqs spos
0398 bsetb #sign_bit,LOCAL_EX(%a0)
0399 spos:
0400 bfclr STAG(%a6){#0:#4} //set tag to normalized, FPTE15 = 0
0401 bsetb #4,STAG(%a6) //set ETE15
0402 orb #0xf0,DNRM_FLG(%a6)
0403 normal:
0404 tstb DNRM_FLG(%a6) //check if any of the ops were denorms
0405 bne ck_wrap //if so, check if it is a potential
0406 // ;wrap-around case
0407 fix_stk:
0408 moveb #0xfe,CU_SAVEPC(%a6)
0409 bclrb #E1,E_BYTE(%a6)
0410
0411 clrw NMNEXC(%a6)
0412
0413 st RES_FLG(%a6) //indicate that a restore is needed
0414 rts
0415
0416 //
0417 // cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
0418 // ftst) completely in software without an frestore to the 040.
0419 //
0420 cu_dnrm:
0421 st CU_ONLY(%a6)
0422 movew CMDREG1B(%a6),%d0
0423 andib #0x3b,%d0 //isolate bits to select inst
0424 tstb %d0
0425 beql cu_dmove //if zero, it is an fmove
0426 cmpib #0x18,%d0
0427 beql cu_dabs //if $18, it is fabs
0428 cmpib #0x1a,%d0
0429 beql cu_dneg //if $1a, it is fneg
0430 //
0431 // Inst is ftst. Check the source operand and set the cc's accordingly.
0432 // No write is done, so simply rts.
0433 //
0434 cu_dtst:
0435 movew LOCAL_EX(%a0),%d0
0436 bclrl #15,%d0
0437 sne LOCAL_SGN(%a0)
0438 beqs cu_dtpo
0439 orl #neg_mask,USER_FPSR(%a6) //set N
0440 cu_dtpo:
0441 cmpiw #0x7fff,%d0 //test for inf/nan
0442 bnes cu_dtcz
0443 tstl LOCAL_HI(%a0)
0444 bnes cu_dtn
0445 tstl LOCAL_LO(%a0)
0446 bnes cu_dtn
0447 orl #inf_mask,USER_FPSR(%a6)
0448 rts
0449 cu_dtn:
0450 orl #nan_mask,USER_FPSR(%a6)
0451 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) //set up fptemp sign for
0452 // ;snan handler
0453 rts
0454 cu_dtcz:
0455 tstl LOCAL_HI(%a0)
0456 bnel cu_dtsx
0457 tstl LOCAL_LO(%a0)
0458 bnel cu_dtsx
0459 orl #z_mask,USER_FPSR(%a6)
0460 cu_dtsx:
0461 rts
0462 //
0463 // Inst is fabs. Execute the absolute value function on the input.
0464 // Branch to the fmove code.
0465 //
0466 cu_dabs:
0467 bclrb #7,LOCAL_EX(%a0) //do abs
0468 bras cu_dmove //fmove code will finish
0469 //
0470 // Inst is fneg. Execute the negate value function on the input.
0471 // Fall though to the fmove code.
0472 //
0473 cu_dneg:
0474 bchgb #7,LOCAL_EX(%a0) //do neg
0475 //
0476 // Inst is fmove. This code also handles all result writes.
0477 // If bit 2 is set, round is forced to double. If it is clear,
0478 // and bit 6 is set, round is forced to single. If both are clear,
0479 // the round precision is found in the fpcr. If the rounding precision
0480 // is double or single, the result is zero, and the mode is checked
0481 // to determine if the lsb of the result should be set.
0482 //
0483 cu_dmove:
0484 btstb #2,CMDREG1B+1(%a6) //check for rd
0485 bne cu_dmrd
0486 btstb #6,CMDREG1B+1(%a6) //check for rs
0487 bne cu_dmrs
0488 //
0489 // The move or operation is not with forced precision. Use the
0490 // FPCR_MODE byte to get rounding.
0491 //
0492 cu_dmnr:
0493 bfextu FPCR_MODE(%a6){#0:#2},%d0
0494 tstb %d0 //check for extended
0495 beq cu_wrexd //if so, just write result
0496 cmpib #1,%d0 //check for single
0497 beq cu_dmrs //fall through to double
0498 //
0499 // The move is fdmove or round precision is double. Result is zero.
0500 // Check rmode for rp or rm and set lsb accordingly.
0501 //
0502 cu_dmrd:
0503 bfextu FPCR_MODE(%a6){#2:#2},%d1 //get rmode
0504 tstw LOCAL_EX(%a0) //check sign
0505 blts cu_dmdn
0506 cmpib #3,%d1 //check for rp
0507 bne cu_dpd //load double pos zero
0508 bra cu_dpdr //load double pos zero w/lsb
0509 cu_dmdn:
0510 cmpib #2,%d1 //check for rm
0511 bne cu_dnd //load double neg zero
0512 bra cu_dndr //load double neg zero w/lsb
0513 //
0514 // The move is fsmove or round precision is single. Result is zero.
0515 // Check for rp or rm and set lsb accordingly.
0516 //
0517 cu_dmrs:
0518 bfextu FPCR_MODE(%a6){#2:#2},%d1 //get rmode
0519 tstw LOCAL_EX(%a0) //check sign
0520 blts cu_dmsn
0521 cmpib #3,%d1 //check for rp
0522 bne cu_spd //load single pos zero
0523 bra cu_spdr //load single pos zero w/lsb
0524 cu_dmsn:
0525 cmpib #2,%d1 //check for rm
0526 bne cu_snd //load single neg zero
0527 bra cu_sndr //load single neg zero w/lsb
0528 //
0529 // The precision is extended, so the result in etemp is correct.
0530 // Simply set unfl (not inex2 or aunfl) and write the result to
0531 // the correct fp register.
0532 cu_wrexd:
0533 orl #unfl_mask,USER_FPSR(%a6)
0534 tstw LOCAL_EX(%a0)
0535 beq wr_etemp
0536 orl #neg_mask,USER_FPSR(%a6)
0537 bra wr_etemp
0538 //
0539 // These routines write +/- zero in double format. The routines
0540 // cu_dpdr and cu_dndr set the double lsb.
0541 //
0542 cu_dpd:
0543 movel #0x3c010000,LOCAL_EX(%a0) //force pos double zero
0544 clrl LOCAL_HI(%a0)
0545 clrl LOCAL_LO(%a0)
0546 orl #z_mask,USER_FPSR(%a6)
0547 orl #unfinx_mask,USER_FPSR(%a6)
0548 bra wr_etemp
0549 cu_dpdr:
0550 movel #0x3c010000,LOCAL_EX(%a0) //force pos double zero
0551 clrl LOCAL_HI(%a0)
0552 movel #0x800,LOCAL_LO(%a0) //with lsb set
0553 orl #unfinx_mask,USER_FPSR(%a6)
0554 bra wr_etemp
0555 cu_dnd:
0556 movel #0xbc010000,LOCAL_EX(%a0) //force pos double zero
0557 clrl LOCAL_HI(%a0)
0558 clrl LOCAL_LO(%a0)
0559 orl #z_mask,USER_FPSR(%a6)
0560 orl #neg_mask,USER_FPSR(%a6)
0561 orl #unfinx_mask,USER_FPSR(%a6)
0562 bra wr_etemp
0563 cu_dndr:
0564 movel #0xbc010000,LOCAL_EX(%a0) //force pos double zero
0565 clrl LOCAL_HI(%a0)
0566 movel #0x800,LOCAL_LO(%a0) //with lsb set
0567 orl #neg_mask,USER_FPSR(%a6)
0568 orl #unfinx_mask,USER_FPSR(%a6)
0569 bra wr_etemp
0570 //
0571 // These routines write +/- zero in single format. The routines
0572 // cu_dpdr and cu_dndr set the single lsb.
0573 //
0574 cu_spd:
0575 movel #0x3f810000,LOCAL_EX(%a0) //force pos single zero
0576 clrl LOCAL_HI(%a0)
0577 clrl LOCAL_LO(%a0)
0578 orl #z_mask,USER_FPSR(%a6)
0579 orl #unfinx_mask,USER_FPSR(%a6)
0580 bra wr_etemp
0581 cu_spdr:
0582 movel #0x3f810000,LOCAL_EX(%a0) //force pos single zero
0583 movel #0x100,LOCAL_HI(%a0) //with lsb set
0584 clrl LOCAL_LO(%a0)
0585 orl #unfinx_mask,USER_FPSR(%a6)
0586 bra wr_etemp
0587 cu_snd:
0588 movel #0xbf810000,LOCAL_EX(%a0) //force pos single zero
0589 clrl LOCAL_HI(%a0)
0590 clrl LOCAL_LO(%a0)
0591 orl #z_mask,USER_FPSR(%a6)
0592 orl #neg_mask,USER_FPSR(%a6)
0593 orl #unfinx_mask,USER_FPSR(%a6)
0594 bra wr_etemp
0595 cu_sndr:
0596 movel #0xbf810000,LOCAL_EX(%a0) //force pos single zero
0597 movel #0x100,LOCAL_HI(%a0) //with lsb set
0598 clrl LOCAL_LO(%a0)
0599 orl #neg_mask,USER_FPSR(%a6)
0600 orl #unfinx_mask,USER_FPSR(%a6)
0601 bra wr_etemp
0602
0603 //
0604 // This code checks for 16-bit overflow conditions on dyadic
0605 // operations which are not restorable into the floating-point
0606 // unit and must be completed in software. Basically, this
0607 // condition exists with a very large norm and a denorm. One
0608 // of the operands must be denormalized to enter this code.
0609 //
0610 // Flags used:
0611 // DY_MO_FLG contains 0 for monadic op, $ff for dyadic
0612 // DNRM_FLG contains $00 for neither op denormalized
0613 // $0f for the destination op denormalized
0614 // $f0 for the source op denormalized
0615 // $ff for both ops denormalized
0616 //
0617 // The wrap-around condition occurs for add, sub, div, and cmp
0618 // when
0619 //
0620 // abs(dest_exp - src_exp) >= $8000
0621 //
0622 // and for mul when
0623 //
0624 // (dest_exp + src_exp) < $0
0625 //
0626 // we must process the operation here if this case is true.
0627 //
0628 // The rts following the frcfpn routine is the exit from res_func
0629 // for this condition. The restore flag (RES_FLG) is left clear.
0630 // No frestore is done unless an exception is to be reported.
0631 //
0632 // For fadd:
0633 // if(sign_of(dest) != sign_of(src))
0634 // replace exponent of src with $3fff (keep sign)
0635 // use fpu to perform dest+new_src (user's rmode and X)
0636 // clr sticky
0637 // else
0638 // set sticky
0639 // call round with user's precision and mode
0640 // move result to fpn and wbtemp
0641 //
0642 // For fsub:
0643 // if(sign_of(dest) == sign_of(src))
0644 // replace exponent of src with $3fff (keep sign)
0645 // use fpu to perform dest+new_src (user's rmode and X)
0646 // clr sticky
0647 // else
0648 // set sticky
0649 // call round with user's precision and mode
0650 // move result to fpn and wbtemp
0651 //
0652 // For fdiv/fsgldiv:
0653 // if(both operands are denorm)
0654 // restore_to_fpu;
0655 // if(dest is norm)
0656 // force_ovf;
0657 // else(dest is denorm)
0658 // force_unf:
0659 //
0660 // For fcmp:
0661 // if(dest is norm)
0662 // N = sign_of(dest);
0663 // else(dest is denorm)
0664 // N = sign_of(src);
0665 //
0666 // For fmul:
0667 // if(both operands are denorm)
0668 // force_unf;
0669 // if((dest_exp + src_exp) < 0)
0670 // force_unf:
0671 // else
0672 // restore_to_fpu;
0673 //
0674 // local equates:
0675 .set addcode,0x22
0676 .set subcode,0x28
0677 .set mulcode,0x23
0678 .set divcode,0x20
0679 .set cmpcode,0x38
0680 ck_wrap:
0681 | tstb DY_MO_FLG(%a6) ;check for fsqrt
0682 beq fix_stk //if zero, it is fsqrt
0683 movew CMDREG1B(%a6),%d0
0684 andiw #0x3b,%d0 //strip to command bits
0685 cmpiw #addcode,%d0
0686 beq wrap_add
0687 cmpiw #subcode,%d0
0688 beq wrap_sub
0689 cmpiw #mulcode,%d0
0690 beq wrap_mul
0691 cmpiw #cmpcode,%d0
0692 beq wrap_cmp
0693 //
0694 // Inst is fdiv.
0695 //
0696 wrap_div:
0697 cmpb #0xff,DNRM_FLG(%a6) //if both ops denorm,
0698 beq fix_stk //restore to fpu
0699 //
0700 // One of the ops is denormalized. Test for wrap condition
0701 // and force the result.
0702 //
0703 cmpb #0x0f,DNRM_FLG(%a6) //check for dest denorm
0704 bnes div_srcd
0705 div_destd:
0706 bsrl ckinf_ns
0707 bne fix_stk
0708 bfextu ETEMP_EX(%a6){#1:#15},%d0 //get src exp (always pos)
0709 bfexts FPTEMP_EX(%a6){#1:#15},%d1 //get dest exp (always neg)
0710 subl %d1,%d0 //subtract dest from src
0711 cmpl #0x7fff,%d0
0712 blt fix_stk //if less, not wrap case
0713 clrb WBTEMP_SGN(%a6)
0714 movew ETEMP_EX(%a6),%d0 //find the sign of the result
0715 movew FPTEMP_EX(%a6),%d1
0716 eorw %d1,%d0
0717 andiw #0x8000,%d0
0718 beq force_unf
0719 st WBTEMP_SGN(%a6)
0720 bra force_unf
0721
0722 ckinf_ns:
0723 moveb STAG(%a6),%d0 //check source tag for inf or nan
0724 bra ck_in_com
0725 ckinf_nd:
0726 moveb DTAG(%a6),%d0 //check destination tag for inf or nan
0727 ck_in_com:
0728 andib #0x60,%d0 //isolate tag bits
0729 cmpb #0x40,%d0 //is it inf?
0730 beq nan_or_inf //not wrap case
0731 cmpb #0x60,%d0 //is it nan?
0732 beq nan_or_inf //yes, not wrap case?
0733 cmpb #0x20,%d0 //is it a zero?
0734 beq nan_or_inf //yes
0735 clrl %d0
0736 rts //then ; it is either a zero of norm,
0737 // ;check wrap case
0738 nan_or_inf:
0739 moveql #-1,%d0
0740 rts
0741
0742
0743
0744 div_srcd:
0745 bsrl ckinf_nd
0746 bne fix_stk
0747 bfextu FPTEMP_EX(%a6){#1:#15},%d0 //get dest exp (always pos)
0748 bfexts ETEMP_EX(%a6){#1:#15},%d1 //get src exp (always neg)
0749 subl %d1,%d0 //subtract src from dest
0750 cmpl #0x8000,%d0
0751 blt fix_stk //if less, not wrap case
0752 clrb WBTEMP_SGN(%a6)
0753 movew ETEMP_EX(%a6),%d0 //find the sign of the result
0754 movew FPTEMP_EX(%a6),%d1
0755 eorw %d1,%d0
0756 andiw #0x8000,%d0
0757 beqs force_ovf
0758 st WBTEMP_SGN(%a6)
0759 //
0760 // This code handles the case of the instruction resulting in
0761 // an overflow condition.
0762 //
0763 force_ovf:
0764 bclrb #E1,E_BYTE(%a6)
0765 orl #ovfl_inx_mask,USER_FPSR(%a6)
0766 clrw NMNEXC(%a6)
0767 leal WBTEMP(%a6),%a0 //point a0 to memory location
0768 movew CMDREG1B(%a6),%d0
0769 btstl #6,%d0 //test for forced precision
0770 beqs frcovf_fpcr
0771 btstl #2,%d0 //check for double
0772 bnes frcovf_dbl
0773 movel #0x1,%d0 //inst is forced single
0774 bras frcovf_rnd
0775 frcovf_dbl:
0776 movel #0x2,%d0 //inst is forced double
0777 bras frcovf_rnd
0778 frcovf_fpcr:
0779 bfextu FPCR_MODE(%a6){#0:#2},%d0 //inst not forced - use fpcr prec
0780 frcovf_rnd:
0781
0782 // The 881/882 does not set inex2 for the following case, so the
0783 // line is commented out to be compatible with 881/882
0784 // tst.b %d0
0785 // beq.b frcovf_x
0786 // or.l #inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2
0787
0788 //frcovf_x:
0789 bsrl ovf_res //get correct result based on
0790 // ;round precision/mode. This
0791 // ;sets FPSR_CC correctly
0792 // ;returns in external format
0793 bfclr WBTEMP_SGN(%a6){#0:#8}
0794 beq frcfpn
0795 bsetb #sign_bit,WBTEMP_EX(%a6)
0796 bra frcfpn
0797 //
0798 // Inst is fadd.
0799 //
0800 wrap_add:
0801 cmpb #0xff,DNRM_FLG(%a6) //if both ops denorm,
0802 beq fix_stk //restore to fpu
0803 //
0804 // One of the ops is denormalized. Test for wrap condition
0805 // and complete the instruction.
0806 //
0807 cmpb #0x0f,DNRM_FLG(%a6) //check for dest denorm
0808 bnes add_srcd
0809 add_destd:
0810 bsrl ckinf_ns
0811 bne fix_stk
0812 bfextu ETEMP_EX(%a6){#1:#15},%d0 //get src exp (always pos)
0813 bfexts FPTEMP_EX(%a6){#1:#15},%d1 //get dest exp (always neg)
0814 subl %d1,%d0 //subtract dest from src
0815 cmpl #0x8000,%d0
0816 blt fix_stk //if less, not wrap case
0817 bra add_wrap
0818 add_srcd:
0819 bsrl ckinf_nd
0820 bne fix_stk
0821 bfextu FPTEMP_EX(%a6){#1:#15},%d0 //get dest exp (always pos)
0822 bfexts ETEMP_EX(%a6){#1:#15},%d1 //get src exp (always neg)
0823 subl %d1,%d0 //subtract src from dest
0824 cmpl #0x8000,%d0
0825 blt fix_stk //if less, not wrap case
0826 //
0827 // Check the signs of the operands. If they are unlike, the fpu
0828 // can be used to add the norm and 1.0 with the sign of the
0829 // denorm and it will correctly generate the result in extended
0830 // precision. We can then call round with no sticky and the result
0831 // will be correct for the user's rounding mode and precision. If
0832 // the signs are the same, we call round with the sticky bit set
0833 // and the result will be correct for the user's rounding mode and
0834 // precision.
0835 //
0836 add_wrap:
0837 movew ETEMP_EX(%a6),%d0
0838 movew FPTEMP_EX(%a6),%d1
0839 eorw %d1,%d0
0840 andiw #0x8000,%d0
0841 beq add_same
0842 //
0843 // The signs are unlike.
0844 //
0845 cmpb #0x0f,DNRM_FLG(%a6) //is dest the denorm?
0846 bnes add_u_srcd
0847 movew FPTEMP_EX(%a6),%d0
0848 andiw #0x8000,%d0
0849 orw #0x3fff,%d0 //force the exponent to +/- 1
0850 movew %d0,FPTEMP_EX(%a6) //in the denorm
0851 movel USER_FPCR(%a6),%d0
0852 andil #0x30,%d0
0853 fmovel %d0,%fpcr //set up users rmode and X
0854 fmovex ETEMP(%a6),%fp0
0855 faddx FPTEMP(%a6),%fp0
0856 leal WBTEMP(%a6),%a0 //point a0 to wbtemp in frame
0857 fmovel %fpsr,%d1
0858 orl %d1,USER_FPSR(%a6) //capture cc's and inex from fadd
0859 fmovex %fp0,WBTEMP(%a6) //write result to memory
0860 lsrl #4,%d0 //put rmode in lower 2 bits
0861 movel USER_FPCR(%a6),%d1
0862 andil #0xc0,%d1
0863 lsrl #6,%d1 //put precision in upper word
0864 swap %d1
0865 orl %d0,%d1 //set up for round call
0866 clrl %d0 //force sticky to zero
0867 bclrb #sign_bit,WBTEMP_EX(%a6)
0868 sne WBTEMP_SGN(%a6)
0869 bsrl round //round result to users rmode & prec
0870 bfclr WBTEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
0871 beq frcfpnr
0872 bsetb #sign_bit,WBTEMP_EX(%a6)
0873 bra frcfpnr
0874 add_u_srcd:
0875 movew ETEMP_EX(%a6),%d0
0876 andiw #0x8000,%d0
0877 orw #0x3fff,%d0 //force the exponent to +/- 1
0878 movew %d0,ETEMP_EX(%a6) //in the denorm
0879 movel USER_FPCR(%a6),%d0
0880 andil #0x30,%d0
0881 fmovel %d0,%fpcr //set up users rmode and X
0882 fmovex ETEMP(%a6),%fp0
0883 faddx FPTEMP(%a6),%fp0
0884 fmovel %fpsr,%d1
0885 orl %d1,USER_FPSR(%a6) //capture cc's and inex from fadd
0886 leal WBTEMP(%a6),%a0 //point a0 to wbtemp in frame
0887 fmovex %fp0,WBTEMP(%a6) //write result to memory
0888 lsrl #4,%d0 //put rmode in lower 2 bits
0889 movel USER_FPCR(%a6),%d1
0890 andil #0xc0,%d1
0891 lsrl #6,%d1 //put precision in upper word
0892 swap %d1
0893 orl %d0,%d1 //set up for round call
0894 clrl %d0 //force sticky to zero
0895 bclrb #sign_bit,WBTEMP_EX(%a6)
0896 sne WBTEMP_SGN(%a6) //use internal format for round
0897 bsrl round //round result to users rmode & prec
0898 bfclr WBTEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
0899 beq frcfpnr
0900 bsetb #sign_bit,WBTEMP_EX(%a6)
0901 bra frcfpnr
0902 //
0903 // Signs are alike:
0904 //
0905 add_same:
0906 cmpb #0x0f,DNRM_FLG(%a6) //is dest the denorm?
0907 bnes add_s_srcd
0908 add_s_destd:
0909 leal ETEMP(%a6),%a0
0910 movel USER_FPCR(%a6),%d0
0911 andil #0x30,%d0
0912 lsrl #4,%d0 //put rmode in lower 2 bits
0913 movel USER_FPCR(%a6),%d1
0914 andil #0xc0,%d1
0915 lsrl #6,%d1 //put precision in upper word
0916 swap %d1
0917 orl %d0,%d1 //set up for round call
0918 movel #0x20000000,%d0 //set sticky for round
0919 bclrb #sign_bit,ETEMP_EX(%a6)
0920 sne ETEMP_SGN(%a6)
0921 bsrl round //round result to users rmode & prec
0922 bfclr ETEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
0923 beqs add_s_dclr
0924 bsetb #sign_bit,ETEMP_EX(%a6)
0925 add_s_dclr:
0926 leal WBTEMP(%a6),%a0
0927 movel ETEMP(%a6),(%a0) //write result to wbtemp
0928 movel ETEMP_HI(%a6),4(%a0)
0929 movel ETEMP_LO(%a6),8(%a0)
0930 tstw ETEMP_EX(%a6)
0931 bgt add_ckovf
0932 orl #neg_mask,USER_FPSR(%a6)
0933 bra add_ckovf
0934 add_s_srcd:
0935 leal FPTEMP(%a6),%a0
0936 movel USER_FPCR(%a6),%d0
0937 andil #0x30,%d0
0938 lsrl #4,%d0 //put rmode in lower 2 bits
0939 movel USER_FPCR(%a6),%d1
0940 andil #0xc0,%d1
0941 lsrl #6,%d1 //put precision in upper word
0942 swap %d1
0943 orl %d0,%d1 //set up for round call
0944 movel #0x20000000,%d0 //set sticky for round
0945 bclrb #sign_bit,FPTEMP_EX(%a6)
0946 sne FPTEMP_SGN(%a6)
0947 bsrl round //round result to users rmode & prec
0948 bfclr FPTEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
0949 beqs add_s_sclr
0950 bsetb #sign_bit,FPTEMP_EX(%a6)
0951 add_s_sclr:
0952 leal WBTEMP(%a6),%a0
0953 movel FPTEMP(%a6),(%a0) //write result to wbtemp
0954 movel FPTEMP_HI(%a6),4(%a0)
0955 movel FPTEMP_LO(%a6),8(%a0)
0956 tstw FPTEMP_EX(%a6)
0957 bgt add_ckovf
0958 orl #neg_mask,USER_FPSR(%a6)
0959 add_ckovf:
0960 movew WBTEMP_EX(%a6),%d0
0961 andiw #0x7fff,%d0
0962 cmpiw #0x7fff,%d0
0963 bne frcfpnr
0964 //
0965 // The result has overflowed to $7fff exponent. Set I, ovfl,
0966 // and aovfl, and clr the mantissa (incorrectly set by the
0967 // round routine.)
0968 //
0969 orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
0970 clrl 4(%a0)
0971 bra frcfpnr
0972 //
0973 // Inst is fsub.
0974 //
0975 wrap_sub:
0976 cmpb #0xff,DNRM_FLG(%a6) //if both ops denorm,
0977 beq fix_stk //restore to fpu
0978 //
0979 // One of the ops is denormalized. Test for wrap condition
0980 // and complete the instruction.
0981 //
0982 cmpb #0x0f,DNRM_FLG(%a6) //check for dest denorm
0983 bnes sub_srcd
0984 sub_destd:
0985 bsrl ckinf_ns
0986 bne fix_stk
0987 bfextu ETEMP_EX(%a6){#1:#15},%d0 //get src exp (always pos)
0988 bfexts FPTEMP_EX(%a6){#1:#15},%d1 //get dest exp (always neg)
0989 subl %d1,%d0 //subtract src from dest
0990 cmpl #0x8000,%d0
0991 blt fix_stk //if less, not wrap case
0992 bra sub_wrap
0993 sub_srcd:
0994 bsrl ckinf_nd
0995 bne fix_stk
0996 bfextu FPTEMP_EX(%a6){#1:#15},%d0 //get dest exp (always pos)
0997 bfexts ETEMP_EX(%a6){#1:#15},%d1 //get src exp (always neg)
0998 subl %d1,%d0 //subtract dest from src
0999 cmpl #0x8000,%d0
1000 blt fix_stk //if less, not wrap case
1001 //
1002 // Check the signs of the operands. If they are alike, the fpu
1003 // can be used to subtract from the norm 1.0 with the sign of the
1004 // denorm and it will correctly generate the result in extended
1005 // precision. We can then call round with no sticky and the result
1006 // will be correct for the user's rounding mode and precision. If
1007 // the signs are unlike, we call round with the sticky bit set
1008 // and the result will be correct for the user's rounding mode and
1009 // precision.
1010 //
1011 sub_wrap:
1012 movew ETEMP_EX(%a6),%d0
1013 movew FPTEMP_EX(%a6),%d1
1014 eorw %d1,%d0
1015 andiw #0x8000,%d0
1016 bne sub_diff
1017 //
1018 // The signs are alike.
1019 //
1020 cmpb #0x0f,DNRM_FLG(%a6) //is dest the denorm?
1021 bnes sub_u_srcd
1022 movew FPTEMP_EX(%a6),%d0
1023 andiw #0x8000,%d0
1024 orw #0x3fff,%d0 //force the exponent to +/- 1
1025 movew %d0,FPTEMP_EX(%a6) //in the denorm
1026 movel USER_FPCR(%a6),%d0
1027 andil #0x30,%d0
1028 fmovel %d0,%fpcr //set up users rmode and X
1029 fmovex FPTEMP(%a6),%fp0
1030 fsubx ETEMP(%a6),%fp0
1031 fmovel %fpsr,%d1
1032 orl %d1,USER_FPSR(%a6) //capture cc's and inex from fadd
1033 leal WBTEMP(%a6),%a0 //point a0 to wbtemp in frame
1034 fmovex %fp0,WBTEMP(%a6) //write result to memory
1035 lsrl #4,%d0 //put rmode in lower 2 bits
1036 movel USER_FPCR(%a6),%d1
1037 andil #0xc0,%d1
1038 lsrl #6,%d1 //put precision in upper word
1039 swap %d1
1040 orl %d0,%d1 //set up for round call
1041 clrl %d0 //force sticky to zero
1042 bclrb #sign_bit,WBTEMP_EX(%a6)
1043 sne WBTEMP_SGN(%a6)
1044 bsrl round //round result to users rmode & prec
1045 bfclr WBTEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
1046 beq frcfpnr
1047 bsetb #sign_bit,WBTEMP_EX(%a6)
1048 bra frcfpnr
1049 sub_u_srcd:
1050 movew ETEMP_EX(%a6),%d0
1051 andiw #0x8000,%d0
1052 orw #0x3fff,%d0 //force the exponent to +/- 1
1053 movew %d0,ETEMP_EX(%a6) //in the denorm
1054 movel USER_FPCR(%a6),%d0
1055 andil #0x30,%d0
1056 fmovel %d0,%fpcr //set up users rmode and X
1057 fmovex FPTEMP(%a6),%fp0
1058 fsubx ETEMP(%a6),%fp0
1059 fmovel %fpsr,%d1
1060 orl %d1,USER_FPSR(%a6) //capture cc's and inex from fadd
1061 leal WBTEMP(%a6),%a0 //point a0 to wbtemp in frame
1062 fmovex %fp0,WBTEMP(%a6) //write result to memory
1063 lsrl #4,%d0 //put rmode in lower 2 bits
1064 movel USER_FPCR(%a6),%d1
1065 andil #0xc0,%d1
1066 lsrl #6,%d1 //put precision in upper word
1067 swap %d1
1068 orl %d0,%d1 //set up for round call
1069 clrl %d0 //force sticky to zero
1070 bclrb #sign_bit,WBTEMP_EX(%a6)
1071 sne WBTEMP_SGN(%a6)
1072 bsrl round //round result to users rmode & prec
1073 bfclr WBTEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
1074 beq frcfpnr
1075 bsetb #sign_bit,WBTEMP_EX(%a6)
1076 bra frcfpnr
1077 //
1078 // Signs are unlike:
1079 //
1080 sub_diff:
1081 cmpb #0x0f,DNRM_FLG(%a6) //is dest the denorm?
1082 bnes sub_s_srcd
1083 sub_s_destd:
1084 leal ETEMP(%a6),%a0
1085 movel USER_FPCR(%a6),%d0
1086 andil #0x30,%d0
1087 lsrl #4,%d0 //put rmode in lower 2 bits
1088 movel USER_FPCR(%a6),%d1
1089 andil #0xc0,%d1
1090 lsrl #6,%d1 //put precision in upper word
1091 swap %d1
1092 orl %d0,%d1 //set up for round call
1093 movel #0x20000000,%d0 //set sticky for round
1094 //
1095 // Since the dest is the denorm, the sign is the opposite of the
1096 // norm sign.
1097 //
1098 eoriw #0x8000,ETEMP_EX(%a6) //flip sign on result
1099 tstw ETEMP_EX(%a6)
1100 bgts sub_s_dwr
1101 orl #neg_mask,USER_FPSR(%a6)
1102 sub_s_dwr:
1103 bclrb #sign_bit,ETEMP_EX(%a6)
1104 sne ETEMP_SGN(%a6)
1105 bsrl round //round result to users rmode & prec
1106 bfclr ETEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
1107 beqs sub_s_dclr
1108 bsetb #sign_bit,ETEMP_EX(%a6)
1109 sub_s_dclr:
1110 leal WBTEMP(%a6),%a0
1111 movel ETEMP(%a6),(%a0) //write result to wbtemp
1112 movel ETEMP_HI(%a6),4(%a0)
1113 movel ETEMP_LO(%a6),8(%a0)
1114 bra sub_ckovf
1115 sub_s_srcd:
1116 leal FPTEMP(%a6),%a0
1117 movel USER_FPCR(%a6),%d0
1118 andil #0x30,%d0
1119 lsrl #4,%d0 //put rmode in lower 2 bits
1120 movel USER_FPCR(%a6),%d1
1121 andil #0xc0,%d1
1122 lsrl #6,%d1 //put precision in upper word
1123 swap %d1
1124 orl %d0,%d1 //set up for round call
1125 movel #0x20000000,%d0 //set sticky for round
1126 bclrb #sign_bit,FPTEMP_EX(%a6)
1127 sne FPTEMP_SGN(%a6)
1128 bsrl round //round result to users rmode & prec
1129 bfclr FPTEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
1130 beqs sub_s_sclr
1131 bsetb #sign_bit,FPTEMP_EX(%a6)
1132 sub_s_sclr:
1133 leal WBTEMP(%a6),%a0
1134 movel FPTEMP(%a6),(%a0) //write result to wbtemp
1135 movel FPTEMP_HI(%a6),4(%a0)
1136 movel FPTEMP_LO(%a6),8(%a0)
1137 tstw FPTEMP_EX(%a6)
1138 bgt sub_ckovf
1139 orl #neg_mask,USER_FPSR(%a6)
1140 sub_ckovf:
1141 movew WBTEMP_EX(%a6),%d0
1142 andiw #0x7fff,%d0
1143 cmpiw #0x7fff,%d0
1144 bne frcfpnr
1145 //
1146 // The result has overflowed to $7fff exponent. Set I, ovfl,
1147 // and aovfl, and clr the mantissa (incorrectly set by the
1148 // round routine.)
1149 //
1150 orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
1151 clrl 4(%a0)
1152 bra frcfpnr
1153 //
1154 // Inst is fcmp.
1155 //
1156 wrap_cmp:
1157 cmpb #0xff,DNRM_FLG(%a6) //if both ops denorm,
1158 beq fix_stk //restore to fpu
1159 //
1160 // One of the ops is denormalized. Test for wrap condition
1161 // and complete the instruction.
1162 //
1163 cmpb #0x0f,DNRM_FLG(%a6) //check for dest denorm
1164 bnes cmp_srcd
1165 cmp_destd:
1166 bsrl ckinf_ns
1167 bne fix_stk
1168 bfextu ETEMP_EX(%a6){#1:#15},%d0 //get src exp (always pos)
1169 bfexts FPTEMP_EX(%a6){#1:#15},%d1 //get dest exp (always neg)
1170 subl %d1,%d0 //subtract dest from src
1171 cmpl #0x8000,%d0
1172 blt fix_stk //if less, not wrap case
1173 tstw ETEMP_EX(%a6) //set N to ~sign_of(src)
1174 bge cmp_setn
1175 rts
1176 cmp_srcd:
1177 bsrl ckinf_nd
1178 bne fix_stk
1179 bfextu FPTEMP_EX(%a6){#1:#15},%d0 //get dest exp (always pos)
1180 bfexts ETEMP_EX(%a6){#1:#15},%d1 //get src exp (always neg)
1181 subl %d1,%d0 //subtract src from dest
1182 cmpl #0x8000,%d0
1183 blt fix_stk //if less, not wrap case
1184 tstw FPTEMP_EX(%a6) //set N to sign_of(dest)
1185 blt cmp_setn
1186 rts
1187 cmp_setn:
1188 orl #neg_mask,USER_FPSR(%a6)
1189 rts
1190
1191 //
1192 // Inst is fmul.
1193 //
1194 wrap_mul:
1195 cmpb #0xff,DNRM_FLG(%a6) //if both ops denorm,
1196 beq force_unf //force an underflow (really!)
1197 //
1198 // One of the ops is denormalized. Test for wrap condition
1199 // and complete the instruction.
1200 //
1201 cmpb #0x0f,DNRM_FLG(%a6) //check for dest denorm
1202 bnes mul_srcd
1203 mul_destd:
1204 bsrl ckinf_ns
1205 bne fix_stk
1206 bfextu ETEMP_EX(%a6){#1:#15},%d0 //get src exp (always pos)
1207 bfexts FPTEMP_EX(%a6){#1:#15},%d1 //get dest exp (always neg)
1208 addl %d1,%d0 //subtract dest from src
1209 bgt fix_stk
1210 bra force_unf
1211 mul_srcd:
1212 bsrl ckinf_nd
1213 bne fix_stk
1214 bfextu FPTEMP_EX(%a6){#1:#15},%d0 //get dest exp (always pos)
1215 bfexts ETEMP_EX(%a6){#1:#15},%d1 //get src exp (always neg)
1216 addl %d1,%d0 //subtract src from dest
1217 bgt fix_stk
1218
1219 //
1220 // This code handles the case of the instruction resulting in
1221 // an underflow condition.
1222 //
1223 force_unf:
1224 bclrb #E1,E_BYTE(%a6)
1225 orl #unfinx_mask,USER_FPSR(%a6)
1226 clrw NMNEXC(%a6)
1227 clrb WBTEMP_SGN(%a6)
1228 movew ETEMP_EX(%a6),%d0 //find the sign of the result
1229 movew FPTEMP_EX(%a6),%d1
1230 eorw %d1,%d0
1231 andiw #0x8000,%d0
1232 beqs frcunfcont
1233 st WBTEMP_SGN(%a6)
1234 frcunfcont:
1235 lea WBTEMP(%a6),%a0 //point a0 to memory location
1236 movew CMDREG1B(%a6),%d0
1237 btstl #6,%d0 //test for forced precision
1238 beqs frcunf_fpcr
1239 btstl #2,%d0 //check for double
1240 bnes frcunf_dbl
1241 movel #0x1,%d0 //inst is forced single
1242 bras frcunf_rnd
1243 frcunf_dbl:
1244 movel #0x2,%d0 //inst is forced double
1245 bras frcunf_rnd
1246 frcunf_fpcr:
1247 bfextu FPCR_MODE(%a6){#0:#2},%d0 //inst not forced - use fpcr prec
1248 frcunf_rnd:
1249 bsrl unf_sub //get correct result based on
1250 // ;round precision/mode. This
1251 // ;sets FPSR_CC correctly
1252 bfclr WBTEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
1253 beqs frcfpn
1254 bsetb #sign_bit,WBTEMP_EX(%a6)
1255 bra frcfpn
1256
1257 //
1258 // Write the result to the user's fpn. All results must be HUGE to be
1259 // written; otherwise the results would have overflowed or underflowed.
1260 // If the rounding precision is single or double, the ovf_res routine
1261 // is needed to correctly supply the max value.
1262 //
1263 frcfpnr:
1264 movew CMDREG1B(%a6),%d0
1265 btstl #6,%d0 //test for forced precision
1266 beqs frcfpn_fpcr
1267 btstl #2,%d0 //check for double
1268 bnes frcfpn_dbl
1269 movel #0x1,%d0 //inst is forced single
1270 bras frcfpn_rnd
1271 frcfpn_dbl:
1272 movel #0x2,%d0 //inst is forced double
1273 bras frcfpn_rnd
1274 frcfpn_fpcr:
1275 bfextu FPCR_MODE(%a6){#0:#2},%d0 //inst not forced - use fpcr prec
1276 tstb %d0
1277 beqs frcfpn //if extended, write what you got
1278 frcfpn_rnd:
1279 bclrb #sign_bit,WBTEMP_EX(%a6)
1280 sne WBTEMP_SGN(%a6)
1281 bsrl ovf_res //get correct result based on
1282 // ;round precision/mode. This
1283 // ;sets FPSR_CC correctly
1284 bfclr WBTEMP_SGN(%a6){#0:#8} //convert back to IEEE ext format
1285 beqs frcfpn_clr
1286 bsetb #sign_bit,WBTEMP_EX(%a6)
1287 frcfpn_clr:
1288 orl #ovfinx_mask,USER_FPSR(%a6)
1289 //
1290 // Perform the write.
1291 //
1292 frcfpn:
1293 bfextu CMDREG1B(%a6){#6:#3},%d0 //extract fp destination register
1294 cmpib #3,%d0
1295 bles frc0123 //check if dest is fp0-fp3
1296 movel #7,%d1
1297 subl %d0,%d1
1298 clrl %d0
1299 bsetl %d1,%d0
1300 fmovemx WBTEMP(%a6),%d0
1301 rts
1302 frc0123:
1303 cmpib #0,%d0
1304 beqs frc0_dst
1305 cmpib #1,%d0
1306 beqs frc1_dst
1307 cmpib #2,%d0
1308 beqs frc2_dst
1309 frc3_dst:
1310 movel WBTEMP_EX(%a6),USER_FP3(%a6)
1311 movel WBTEMP_HI(%a6),USER_FP3+4(%a6)
1312 movel WBTEMP_LO(%a6),USER_FP3+8(%a6)
1313 rts
1314 frc2_dst:
1315 movel WBTEMP_EX(%a6),USER_FP2(%a6)
1316 movel WBTEMP_HI(%a6),USER_FP2+4(%a6)
1317 movel WBTEMP_LO(%a6),USER_FP2+8(%a6)
1318 rts
1319 frc1_dst:
1320 movel WBTEMP_EX(%a6),USER_FP1(%a6)
1321 movel WBTEMP_HI(%a6),USER_FP1+4(%a6)
1322 movel WBTEMP_LO(%a6),USER_FP1+8(%a6)
1323 rts
1324 frc0_dst:
1325 movel WBTEMP_EX(%a6),USER_FP0(%a6)
1326 movel WBTEMP_HI(%a6),USER_FP0+4(%a6)
1327 movel WBTEMP_LO(%a6),USER_FP0+8(%a6)
1328 rts
1329
1330 //
1331 // Write etemp to fpn.
1332 // A check is made on enabled and signalled snan exceptions,
1333 // and the destination is not overwritten if this condition exists.
1334 // This code is designed to make fmoveins of unsupported data types
1335 // faster.
1336 //
1337 wr_etemp:
1338 btstb #snan_bit,FPSR_EXCEPT(%a6) //if snan is set, and
1339 beqs fmoveinc //enabled, force restore
1340 btstb #snan_bit,FPCR_ENABLE(%a6) //and don't overwrite
1341 beqs fmoveinc //the dest
1342 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) //set up fptemp sign for
1343 // ;snan handler
1344 tstb ETEMP(%a6) //check for negative
1345 blts snan_neg
1346 rts
1347 snan_neg:
1348 orl #neg_bit,USER_FPSR(%a6) //snan is negative; set N
1349 rts
1350 fmoveinc:
1351 clrw NMNEXC(%a6)
1352 bclrb #E1,E_BYTE(%a6)
1353 moveb STAG(%a6),%d0 //check if stag is inf
1354 andib #0xe0,%d0
1355 cmpib #0x40,%d0
1356 bnes fminc_cnan
1357 orl #inf_mask,USER_FPSR(%a6) //if inf, nothing yet has set I
1358 tstw LOCAL_EX(%a0) //check sign
1359 bges fminc_con
1360 orl #neg_mask,USER_FPSR(%a6)
1361 bra fminc_con
1362 fminc_cnan:
1363 cmpib #0x60,%d0 //check if stag is NaN
1364 bnes fminc_czero
1365 orl #nan_mask,USER_FPSR(%a6) //if nan, nothing yet has set NaN
1366 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) //set up fptemp sign for
1367 // ;snan handler
1368 tstw LOCAL_EX(%a0) //check sign
1369 bges fminc_con
1370 orl #neg_mask,USER_FPSR(%a6)
1371 bra fminc_con
1372 fminc_czero:
1373 cmpib #0x20,%d0 //check if zero
1374 bnes fminc_con
1375 orl #z_mask,USER_FPSR(%a6) //if zero, set Z
1376 tstw LOCAL_EX(%a0) //check sign
1377 bges fminc_con
1378 orl #neg_mask,USER_FPSR(%a6)
1379 fminc_con:
1380 bfextu CMDREG1B(%a6){#6:#3},%d0 //extract fp destination register
1381 cmpib #3,%d0
1382 bles fp0123 //check if dest is fp0-fp3
1383 movel #7,%d1
1384 subl %d0,%d1
1385 clrl %d0
1386 bsetl %d1,%d0
1387 fmovemx ETEMP(%a6),%d0
1388 rts
1389
1390 fp0123:
1391 cmpib #0,%d0
1392 beqs fp0_dst
1393 cmpib #1,%d0
1394 beqs fp1_dst
1395 cmpib #2,%d0
1396 beqs fp2_dst
1397 fp3_dst:
1398 movel ETEMP_EX(%a6),USER_FP3(%a6)
1399 movel ETEMP_HI(%a6),USER_FP3+4(%a6)
1400 movel ETEMP_LO(%a6),USER_FP3+8(%a6)
1401 rts
1402 fp2_dst:
1403 movel ETEMP_EX(%a6),USER_FP2(%a6)
1404 movel ETEMP_HI(%a6),USER_FP2+4(%a6)
1405 movel ETEMP_LO(%a6),USER_FP2+8(%a6)
1406 rts
1407 fp1_dst:
1408 movel ETEMP_EX(%a6),USER_FP1(%a6)
1409 movel ETEMP_HI(%a6),USER_FP1+4(%a6)
1410 movel ETEMP_LO(%a6),USER_FP1+8(%a6)
1411 rts
1412 fp0_dst:
1413 movel ETEMP_EX(%a6),USER_FP0(%a6)
1414 movel ETEMP_HI(%a6),USER_FP0+4(%a6)
1415 movel ETEMP_LO(%a6),USER_FP0+8(%a6)
1416 rts
1417
1418 opclass3:
1419 st CU_ONLY(%a6)
1420 movew CMDREG1B(%a6),%d0 //check if packed moveout
1421 andiw #0x0c00,%d0 //isolate last 2 bits of size field
1422 cmpiw #0x0c00,%d0 //if size is 011 or 111, it is packed
1423 beq pack_out //else it is norm or denorm
1424 bra mv_out
1425
1426
1427 //
1428 // MOVE OUT
1429 //
1430
1431 mv_tbl:
1432 .long li
1433 .long sgp
1434 .long xp
1435 .long mvout_end //should never be taken
1436 .long wi
1437 .long dp
1438 .long bi
1439 .long mvout_end //should never be taken
1440 mv_out:
1441 bfextu CMDREG1B(%a6){#3:#3},%d1 //put source specifier in d1
1442 leal mv_tbl,%a0
1443 movel %a0@(%d1:l:4),%a0
1444 jmp (%a0)
1445
1446 //
1447 // This exit is for move-out to memory. The aunfl bit is
1448 // set if the result is inex and unfl is signalled.
1449 //
1450 mvout_end:
1451 btstb #inex2_bit,FPSR_EXCEPT(%a6)
1452 beqs no_aufl
1453 btstb #unfl_bit,FPSR_EXCEPT(%a6)
1454 beqs no_aufl
1455 bsetb #aunfl_bit,FPSR_AEXCEPT(%a6)
1456 no_aufl:
1457 clrw NMNEXC(%a6)
1458 bclrb #E1,E_BYTE(%a6)
1459 fmovel #0,%FPSR //clear any cc bits from res_func
1460 //
1461 // Return ETEMP to extended format from internal extended format so
1462 // that gen_except will have a correctly signed value for ovfl/unfl
1463 // handlers.
1464 //
1465 bfclr ETEMP_SGN(%a6){#0:#8}
1466 beqs mvout_con
1467 bsetb #sign_bit,ETEMP_EX(%a6)
1468 mvout_con:
1469 rts
1470 //
1471 // This exit is for move-out to int register. The aunfl bit is
1472 // not set in any case for this move.
1473 //
1474 mvouti_end:
1475 clrw NMNEXC(%a6)
1476 bclrb #E1,E_BYTE(%a6)
1477 fmovel #0,%FPSR //clear any cc bits from res_func
1478 //
1479 // Return ETEMP to extended format from internal extended format so
1480 // that gen_except will have a correctly signed value for ovfl/unfl
1481 // handlers.
1482 //
1483 bfclr ETEMP_SGN(%a6){#0:#8}
1484 beqs mvouti_con
1485 bsetb #sign_bit,ETEMP_EX(%a6)
1486 mvouti_con:
1487 rts
1488 //
1489 // li is used to handle a long integer source specifier
1490 //
1491
1492 li:
1493 moveql #4,%d0 //set byte count
1494
1495 btstb #7,STAG(%a6) //check for extended denorm
1496 bne int_dnrm //if so, branch
1497
1498 fmovemx ETEMP(%a6),%fp0-%fp0
1499 fcmpd #0x41dfffffffc00000,%fp0
1500 // 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
1501 fbge lo_plrg
1502 fcmpd #0xc1e0000000000000,%fp0
1503 // c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
1504 fble lo_nlrg
1505 //
1506 // at this point, the answer is between the largest pos and neg values
1507 //
1508 movel USER_FPCR(%a6),%d1 //use user's rounding mode
1509 andil #0x30,%d1
1510 fmovel %d1,%fpcr
1511 fmovel %fp0,L_SCR1(%a6) //let the 040 perform conversion
1512 fmovel %fpsr,%d1
1513 orl %d1,USER_FPSR(%a6) //capture inex2/ainex if set
1514 bra int_wrt
1515
1516
1517 lo_plrg:
1518 movel #0x7fffffff,L_SCR1(%a6) //answer is largest positive int
1519 fbeq int_wrt //exact answer
1520 fcmpd #0x41dfffffffe00000,%fp0
1521 // 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
1522 fbge int_operr //set operr
1523 bra int_inx //set inexact
1524
1525 lo_nlrg:
1526 movel #0x80000000,L_SCR1(%a6)
1527 fbeq int_wrt //exact answer
1528 fcmpd #0xc1e0000000100000,%fp0
1529 // c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
1530 fblt int_operr //set operr
1531 bra int_inx //set inexact
1532
1533 //
1534 // wi is used to handle a word integer source specifier
1535 //
1536
1537 wi:
1538 moveql #2,%d0 //set byte count
1539
1540 btstb #7,STAG(%a6) //check for extended denorm
1541 bne int_dnrm //branch if so
1542
1543 fmovemx ETEMP(%a6),%fp0-%fp0
1544 fcmps #0x46fffe00,%fp0
1545 // 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
1546 fbge wo_plrg
1547 fcmps #0xc7000000,%fp0
1548 // c7000000 in sgl prec = c00e00008000000000000000 in ext prec
1549 fble wo_nlrg
1550
1551 //
1552 // at this point, the answer is between the largest pos and neg values
1553 //
1554 movel USER_FPCR(%a6),%d1 //use user's rounding mode
1555 andil #0x30,%d1
1556 fmovel %d1,%fpcr
1557 fmovew %fp0,L_SCR1(%a6) //let the 040 perform conversion
1558 fmovel %fpsr,%d1
1559 orl %d1,USER_FPSR(%a6) //capture inex2/ainex if set
1560 bra int_wrt
1561
1562 wo_plrg:
1563 movew #0x7fff,L_SCR1(%a6) //answer is largest positive int
1564 fbeq int_wrt //exact answer
1565 fcmps #0x46ffff00,%fp0
1566 // 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
1567 fbge int_operr //set operr
1568 bra int_inx //set inexact
1569
1570 wo_nlrg:
1571 movew #0x8000,L_SCR1(%a6)
1572 fbeq int_wrt //exact answer
1573 fcmps #0xc7000080,%fp0
1574 // c7000080 in sgl prec = c00e00008000800000000000 in ext prec
1575 fblt int_operr //set operr
1576 bra int_inx //set inexact
1577
1578 //
1579 // bi is used to handle a byte integer source specifier
1580 //
1581
1582 bi:
1583 moveql #1,%d0 //set byte count
1584
1585 btstb #7,STAG(%a6) //check for extended denorm
1586 bne int_dnrm //branch if so
1587
1588 fmovemx ETEMP(%a6),%fp0-%fp0
1589 fcmps #0x42fe0000,%fp0
1590 // 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
1591 fbge by_plrg
1592 fcmps #0xc3000000,%fp0
1593 // c3000000 in sgl prec = c00600008000000000000000 in ext prec
1594 fble by_nlrg
1595
1596 //
1597 // at this point, the answer is between the largest pos and neg values
1598 //
1599 movel USER_FPCR(%a6),%d1 //use user's rounding mode
1600 andil #0x30,%d1
1601 fmovel %d1,%fpcr
1602 fmoveb %fp0,L_SCR1(%a6) //let the 040 perform conversion
1603 fmovel %fpsr,%d1
1604 orl %d1,USER_FPSR(%a6) //capture inex2/ainex if set
1605 bra int_wrt
1606
1607 by_plrg:
1608 moveb #0x7f,L_SCR1(%a6) //answer is largest positive int
1609 fbeq int_wrt //exact answer
1610 fcmps #0x42ff0000,%fp0
1611 // 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
1612 fbge int_operr //set operr
1613 bra int_inx //set inexact
1614
1615 by_nlrg:
1616 moveb #0x80,L_SCR1(%a6)
1617 fbeq int_wrt //exact answer
1618 fcmps #0xc3008000,%fp0
1619 // c3008000 in sgl prec = c00600008080000000000000 in ext prec
1620 fblt int_operr //set operr
1621 bra int_inx //set inexact
1622
1623 //
1624 // Common integer routines
1625 //
1626 // int_drnrm---account for possible nonzero result for round up with positive
1627 // operand and round down for negative answer. In the first case (result = 1)
1628 // byte-width (store in d0) of result must be honored. In the second case,
1629 // -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).
1630
1631 int_dnrm:
1632 movel #0,L_SCR1(%a6) // initialize result to 0
1633 bfextu FPCR_MODE(%a6){#2:#2},%d1 // d1 is the rounding mode
1634 cmpb #2,%d1
1635 bmis int_inx // if RN or RZ, done
1636 bnes int_rp // if RP, continue below
1637 tstw ETEMP(%a6) // RM: store -1 in L_SCR1 if src is negative
1638 bpls int_inx // otherwise result is 0
1639 movel #-1,L_SCR1(%a6)
1640 bras int_inx
1641 int_rp:
1642 tstw ETEMP(%a6) // RP: store +1 of proper width in L_SCR1 if
1643 // ; source is greater than 0
1644 bmis int_inx // otherwise, result is 0
1645 lea L_SCR1(%a6),%a1 // a1 is address of L_SCR1
1646 addal %d0,%a1 // offset by destination width -1
1647 subal #1,%a1
1648 bsetb #0,(%a1) // set low bit at a1 address
1649 int_inx:
1650 oril #inx2a_mask,USER_FPSR(%a6)
1651 bras int_wrt
1652 int_operr:
1653 fmovemx %fp0-%fp0,FPTEMP(%a6) //FPTEMP must contain the extended
1654 // ;precision source that needs to be
1655 // ;converted to integer this is required
1656 // ;if the operr exception is enabled.
1657 // ;set operr/aiop (no inex2 on int ovfl)
1658
1659 oril #opaop_mask,USER_FPSR(%a6)
1660 // ;fall through to perform int_wrt
1661 int_wrt:
1662 movel EXC_EA(%a6),%a1 //load destination address
1663 tstl %a1 //check to see if it is a dest register
1664 beqs wrt_dn //write data register
1665 lea L_SCR1(%a6),%a0 //point to supervisor source address
1666 bsrl mem_write
1667 bra mvouti_end
1668
1669 wrt_dn:
1670 movel %d0,-(%sp) //d0 currently contains the size to write
1671 bsrl get_fline //get_fline returns Dn in d0
1672 andiw #0x7,%d0 //isolate register
1673 movel (%sp)+,%d1 //get size
1674 cmpil #4,%d1 //most frequent case
1675 beqs sz_long
1676 cmpil #2,%d1
1677 bnes sz_con
1678 orl #8,%d0 //add 'word' size to register#
1679 bras sz_con
1680 sz_long:
1681 orl #0x10,%d0 //add 'long' size to register#
1682 sz_con:
1683 movel %d0,%d1 //reg_dest expects size:reg in d1
1684 bsrl reg_dest //load proper data register
1685 bra mvouti_end
1686 xp:
1687 lea ETEMP(%a6),%a0
1688 bclrb #sign_bit,LOCAL_EX(%a0)
1689 sne LOCAL_SGN(%a0)
1690 btstb #7,STAG(%a6) //check for extended denorm
1691 bne xdnrm
1692 clrl %d0
1693 bras do_fp //do normal case
1694 sgp:
1695 lea ETEMP(%a6),%a0
1696 bclrb #sign_bit,LOCAL_EX(%a0)
1697 sne LOCAL_SGN(%a0)
1698 btstb #7,STAG(%a6) //check for extended denorm
1699 bne sp_catas //branch if so
1700 movew LOCAL_EX(%a0),%d0
1701 lea sp_bnds,%a1
1702 cmpw (%a1),%d0
1703 blt sp_under
1704 cmpw 2(%a1),%d0
1705 bgt sp_over
1706 movel #1,%d0 //set destination format to single
1707 bras do_fp //do normal case
1708 dp:
1709 lea ETEMP(%a6),%a0
1710 bclrb #sign_bit,LOCAL_EX(%a0)
1711 sne LOCAL_SGN(%a0)
1712
1713 btstb #7,STAG(%a6) //check for extended denorm
1714 bne dp_catas //branch if so
1715
1716 movew LOCAL_EX(%a0),%d0
1717 lea dp_bnds,%a1
1718
1719 cmpw (%a1),%d0
1720 blt dp_under
1721 cmpw 2(%a1),%d0
1722 bgt dp_over
1723
1724 movel #2,%d0 //set destination format to double
1725 // ;fall through to do_fp
1726 //
1727 do_fp:
1728 bfextu FPCR_MODE(%a6){#2:#2},%d1 //rnd mode in d1
1729 swap %d0 //rnd prec in upper word
1730 addl %d0,%d1 //d1 has PREC/MODE info
1731
1732 clrl %d0 //clear g,r,s
1733
1734 bsrl round //round
1735
1736 movel %a0,%a1
1737 movel EXC_EA(%a6),%a0
1738
1739 bfextu CMDREG1B(%a6){#3:#3},%d1 //extract destination format
1740 // ;at this point only the dest
1741 // ;formats sgl, dbl, ext are
1742 // ;possible
1743 cmpb #2,%d1
1744 bgts ddbl //double=5, extended=2, single=1
1745 bnes dsgl
1746 // ;fall through to dext
1747 dext:
1748 bsrl dest_ext
1749 bra mvout_end
1750 dsgl:
1751 bsrl dest_sgl
1752 bra mvout_end
1753 ddbl:
1754 bsrl dest_dbl
1755 bra mvout_end
1756
1757 //
1758 // Handle possible denorm or catastrophic underflow cases here
1759 //
1760 xdnrm:
1761 bsr set_xop //initialize WBTEMP
1762 bsetb #wbtemp15_bit,WB_BYTE(%a6) //set wbtemp15
1763
1764 movel %a0,%a1
1765 movel EXC_EA(%a6),%a0 //a0 has the destination pointer
1766 bsrl dest_ext //store to memory
1767 bsetb #unfl_bit,FPSR_EXCEPT(%a6)
1768 bra mvout_end
1769
1770 sp_under:
1771 bsetb #etemp15_bit,STAG(%a6)
1772
1773 cmpw 4(%a1),%d0
1774 blts sp_catas //catastrophic underflow case
1775
1776 movel #1,%d0 //load in round precision
1777 movel #sgl_thresh,%d1 //load in single denorm threshold
1778 bsrl dpspdnrm //expects d1 to have the proper
1779 // ;denorm threshold
1780 bsrl dest_sgl //stores value to destination
1781 bsetb #unfl_bit,FPSR_EXCEPT(%a6)
1782 bra mvout_end //exit
1783
1784 dp_under:
1785 bsetb #etemp15_bit,STAG(%a6)
1786
1787 cmpw 4(%a1),%d0
1788 blts dp_catas //catastrophic underflow case
1789
1790 movel #dbl_thresh,%d1 //load in double precision threshold
1791 movel #2,%d0
1792 bsrl dpspdnrm //expects d1 to have proper
1793 // ;denorm threshold
1794 // ;expects d0 to have round precision
1795 bsrl dest_dbl //store value to destination
1796 bsetb #unfl_bit,FPSR_EXCEPT(%a6)
1797 bra mvout_end //exit
1798
1799 //
1800 // Handle catastrophic underflow cases here
1801 //
1802 sp_catas:
1803 // Temp fix for z bit set in unf_sub
1804 movel USER_FPSR(%a6),-(%a7)
1805
1806 movel #1,%d0 //set round precision to sgl
1807
1808 bsrl unf_sub //a0 points to result
1809
1810 movel (%a7)+,USER_FPSR(%a6)
1811
1812 movel #1,%d0
1813 subw %d0,LOCAL_EX(%a0) //account for difference between
1814 // ;denorm/norm bias
1815
1816 movel %a0,%a1 //a1 has the operand input
1817 movel EXC_EA(%a6),%a0 //a0 has the destination pointer
1818
1819 bsrl dest_sgl //store the result
1820 oril #unfinx_mask,USER_FPSR(%a6)
1821 bra mvout_end
1822
1823 dp_catas:
1824 // Temp fix for z bit set in unf_sub
1825 movel USER_FPSR(%a6),-(%a7)
1826
1827 movel #2,%d0 //set round precision to dbl
1828 bsrl unf_sub //a0 points to result
1829
1830 movel (%a7)+,USER_FPSR(%a6)
1831
1832 movel #1,%d0
1833 subw %d0,LOCAL_EX(%a0) //account for difference between
1834 // ;denorm/norm bias
1835
1836 movel %a0,%a1 //a1 has the operand input
1837 movel EXC_EA(%a6),%a0 //a0 has the destination pointer
1838
1839 bsrl dest_dbl //store the result
1840 oril #unfinx_mask,USER_FPSR(%a6)
1841 bra mvout_end
1842
1843 //
1844 // Handle catastrophic overflow cases here
1845 //
1846 sp_over:
1847 // Temp fix for z bit set in unf_sub
1848 movel USER_FPSR(%a6),-(%a7)
1849
1850 movel #1,%d0
1851 leal FP_SCR1(%a6),%a0 //use FP_SCR1 for creating result
1852 movel ETEMP_EX(%a6),(%a0)
1853 movel ETEMP_HI(%a6),4(%a0)
1854 movel ETEMP_LO(%a6),8(%a0)
1855 bsrl ovf_res
1856
1857 movel (%a7)+,USER_FPSR(%a6)
1858
1859 movel %a0,%a1
1860 movel EXC_EA(%a6),%a0
1861 bsrl dest_sgl
1862 orl #ovfinx_mask,USER_FPSR(%a6)
1863 bra mvout_end
1864
1865 dp_over:
1866 // Temp fix for z bit set in ovf_res
1867 movel USER_FPSR(%a6),-(%a7)
1868
1869 movel #2,%d0
1870 leal FP_SCR1(%a6),%a0 //use FP_SCR1 for creating result
1871 movel ETEMP_EX(%a6),(%a0)
1872 movel ETEMP_HI(%a6),4(%a0)
1873 movel ETEMP_LO(%a6),8(%a0)
1874 bsrl ovf_res
1875
1876 movel (%a7)+,USER_FPSR(%a6)
1877
1878 movel %a0,%a1
1879 movel EXC_EA(%a6),%a0
1880 bsrl dest_dbl
1881 orl #ovfinx_mask,USER_FPSR(%a6)
1882 bra mvout_end
1883
1884 //
1885 // DPSPDNRM
1886 //
1887 // This subroutine takes an extended normalized number and denormalizes
1888 // it to the given round precision. This subroutine also decrements
1889 // the input operand's exponent by 1 to account for the fact that
1890 // dest_sgl or dest_dbl expects a normalized number's bias.
1891 //
1892 // Input: a0 points to a normalized number in internal extended format
1893 // d0 is the round precision (=1 for sgl; =2 for dbl)
1894 // d1 is the the single precision or double precision
1895 // denorm threshold
1896 //
1897 // Output: (In the format for dest_sgl or dest_dbl)
1898 // a0 points to the destination
1899 // a1 points to the operand
1900 //
1901 // Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
1902 //
1903 dpspdnrm:
1904 movel %d0,-(%a7) //save round precision
1905 clrl %d0 //clear initial g,r,s
1906 bsrl dnrm_lp //careful with d0, it's needed by round
1907
1908 bfextu FPCR_MODE(%a6){#2:#2},%d1 //get rounding mode
1909 swap %d1
1910 movew 2(%a7),%d1 //set rounding precision
1911 swap %d1 //at this point d1 has PREC/MODE info
1912 bsrl round //round result, sets the inex bit in
1913 // ;USER_FPSR if needed
1914
1915 movew #1,%d0
1916 subw %d0,LOCAL_EX(%a0) //account for difference in denorm
1917 // ;vs norm bias
1918
1919 movel %a0,%a1 //a1 has the operand input
1920 movel EXC_EA(%a6),%a0 //a0 has the destination pointer
1921 addw #4,%a7 //pop stack
1922 rts
1923 //
1924 // SET_XOP initialized WBTEMP with the value pointed to by a0
1925 // input: a0 points to input operand in the internal extended format
1926 //
1927 set_xop:
1928 movel LOCAL_EX(%a0),WBTEMP_EX(%a6)
1929 movel LOCAL_HI(%a0),WBTEMP_HI(%a6)
1930 movel LOCAL_LO(%a0),WBTEMP_LO(%a6)
1931 bfclr WBTEMP_SGN(%a6){#0:#8}
1932 beqs sxop
1933 bsetb #sign_bit,WBTEMP_EX(%a6)
1934 sxop:
1935 bfclr STAG(%a6){#5:#4} //clear wbtm66,wbtm1,wbtm0,sbit
1936 rts
1937 //
1938 // P_MOVE
1939 //
1940 p_movet:
1941 .long p_move
1942 .long p_movez
1943 .long p_movei
1944 .long p_moven
1945 .long p_move
1946 p_regd:
1947 .long p_dyd0
1948 .long p_dyd1
1949 .long p_dyd2
1950 .long p_dyd3
1951 .long p_dyd4
1952 .long p_dyd5
1953 .long p_dyd6
1954 .long p_dyd7
1955
1956 pack_out:
1957 leal p_movet,%a0 //load jmp table address
1958 movew STAG(%a6),%d0 //get source tag
1959 bfextu %d0{#16:#3},%d0 //isolate source bits
1960 movel (%a0,%d0.w*4),%a0 //load a0 with routine label for tag
1961 jmp (%a0) //go to the routine
1962
1963 p_write:
1964 movel #0x0c,%d0 //get byte count
1965 movel EXC_EA(%a6),%a1 //get the destination address
1966 bsr mem_write //write the user's destination
1967 moveb #0,CU_SAVEPC(%a6) //set the cu save pc to all 0's
1968
1969 //
1970 // Also note that the dtag must be set to norm here - this is because
1971 // the 040 uses the dtag to execute the correct microcode.
1972 //
1973 bfclr DTAG(%a6){#0:#3} //set dtag to norm
1974
1975 rts
1976
1977 // Notes on handling of special case (zero, inf, and nan) inputs:
1978 // 1. Operr is not signalled if the k-factor is greater than 18.
1979 // 2. Per the manual, status bits are not set.
1980 //
1981
1982 p_move:
1983 movew CMDREG1B(%a6),%d0
1984 btstl #kfact_bit,%d0 //test for dynamic k-factor
1985 beqs statick //if clear, k-factor is static
1986 dynamick:
1987 bfextu %d0{#25:#3},%d0 //isolate register for dynamic k-factor
1988 lea p_regd,%a0
1989 movel %a0@(%d0:l:4),%a0
1990 jmp (%a0)
1991 statick:
1992 andiw #0x007f,%d0 //get k-factor
1993 bfexts %d0{#25:#7},%d0 //sign extend d0 for bindec
1994 leal ETEMP(%a6),%a0 //a0 will point to the packed decimal
1995 bsrl bindec //perform the convert; data at a6
1996 leal FP_SCR1(%a6),%a0 //load a0 with result address
1997 bral p_write
1998 p_movez:
1999 leal ETEMP(%a6),%a0 //a0 will point to the packed decimal
2000 clrw 2(%a0) //clear lower word of exp
2001 clrl 4(%a0) //load second lword of ZERO
2002 clrl 8(%a0) //load third lword of ZERO
2003 bra p_write //go write results
2004 p_movei:
2005 fmovel #0,%FPSR //clear aiop
2006 leal ETEMP(%a6),%a0 //a0 will point to the packed decimal
2007 clrw 2(%a0) //clear lower word of exp
2008 bra p_write //go write the result
2009 p_moven:
2010 leal ETEMP(%a6),%a0 //a0 will point to the packed decimal
2011 clrw 2(%a0) //clear lower word of exp
2012 bra p_write //go write the result
2013
2014 //
2015 // Routines to read the dynamic k-factor from Dn.
2016 //
2017 p_dyd0:
2018 movel USER_D0(%a6),%d0
2019 bras statick
2020 p_dyd1:
2021 movel USER_D1(%a6),%d0
2022 bras statick
2023 p_dyd2:
2024 movel %d2,%d0
2025 bras statick
2026 p_dyd3:
2027 movel %d3,%d0
2028 bras statick
2029 p_dyd4:
2030 movel %d4,%d0
2031 bras statick
2032 p_dyd5:
2033 movel %d5,%d0
2034 bras statick
2035 p_dyd6:
2036 movel %d6,%d0
2037 bra statick
2038 p_dyd7:
2039 movel %d7,%d0
2040 bra statick
2041
2042 |end