1 | 2 | res_func.sa 3.9 7/29/91 3 | 4 | Normalizes denormalized numbers if necessary and updates the 5 | stack frame. The function is then restored back into the 6 | machine and the 040 completes the operation. This routine 7 | is only used by the unsupported data type/format handler. 8 | (Exception vector 55). 9 | 10 | For packed move out (fmove.p fpm,<ea>) the operation is 11 | completed here; data is packed and moved to user memory. 12 | The stack is restored to the 040 only in the case of a 13 | reportable exception in the conversion. 14 | 15 | 16 | Copyright (C) Motorola, Inc. 1990 17 | All Rights Reserved 18 | 19 | THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 20 | The copyright notice above does not evidence any 21 | actual or intended publication of such source code. 22 23 RES_FUNC: |idnt 2,1 | Motorola 040 Floating Point Software Package 24 25 |section 8 26 27 .include "fpsp.h" 28 29 sp_bnds: .short 0x3f81,0x407e 30 .short 0x3f6a,0x0000 31 dp_bnds: .short 0x3c01,0x43fe 32 .short 0x3bcd,0x0000 33 34 |xref mem_write 35 |xref bindec 36 |xref get_fline 37 |xref round 38 |xref denorm 39 |xref dest_ext 40 |xref dest_dbl 41 |xref dest_sgl 42 |xref unf_sub 43 |xref nrm_set 44 |xref dnrm_lp 45 |xref ovf_res 46 |xref reg_dest 47 |xref t_ovfl 48 |xref t_unfl 49 50 .global res_func 51 .global p_move 52 53 res_func: 54 clrb DNRM_FLG(%a6) 55 clrb RES_FLG(%a6) 56 clrb CU_ONLY(%a6) 57 tstb DY_MO_FLG(%a6) 58 beqs monadic 59 dyadic: 60 btstb #7,DTAG(%a6) |if dop = norm=000, zero=001, 61 | ;inf=010 or nan=011 62 beqs monadic |then branch 63 | ;else denorm 64 | HANDLE DESTINATION DENORM HERE 65 | ;set dtag to norm 66 | ;write the tag & fpte15 to the fstack 67 leal FPTEMP(%a6),%a0 68 69 bclrb #sign_bit,LOCAL_EX(%a0) 70 sne LOCAL_SGN(%a0) 71 72 bsr nrm_set |normalize number (exp will go negative) 73 bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign 74 bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format 75 beqs dpos 76 bsetb #sign_bit,LOCAL_EX(%a0) 77 dpos: 78 bfclr DTAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0 79 bsetb #4,DTAG(%a6) |set FPTE15 80 orb #0x0f,DNRM_FLG(%a6) 81 monadic: 82 leal ETEMP(%a6),%a0 83 btstb #direction_bit,CMDREG1B(%a6) |check direction 84 bne opclass3 |it is a mv out 85 | 86 | At this point, only opclass 0 and 2 possible 87 | 88 btstb #7,STAG(%a6) |if sop = norm=000, zero=001, 89 | ;inf=010 or nan=011 90 bne mon_dnrm |else denorm 91 tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would 92 bne normal |require normalization of denorm 93 94 | At this point: 95 | monadic instructions: fabs = $18 fneg = $1a ftst = $3a 96 | fmove = $00 fsmove = $40 fdmove = $44 97 | fsqrt = $05* fssqrt = $41 fdsqrt = $45 98 | (*fsqrt reencoded to $05) 99 | 100 movew CMDREG1B(%a6),%d0 |get command register 101 andil #0x7f,%d0 |strip to only command word 102 | 103 | At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and 104 | fdsqrt are possible. 105 | For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize) 106 | For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize) 107 | 108 btstl #0,%d0 109 bne normal |weed out fsqrt instructions 110 | 111 | cu_norm handles fmove in instructions with normalized inputs. 112 | The routine round is used to correctly round the input for the 113 | destination precision and mode. 114 | 115 cu_norm: 116 st CU_ONLY(%a6) |set cu-only inst flag 117 movew CMDREG1B(%a6),%d0 118 andib #0x3b,%d0 |isolate bits to select inst 119 tstb %d0 120 beql cu_nmove |if zero, it is an fmove 121 cmpib #0x18,%d0 122 beql cu_nabs |if $18, it is fabs 123 cmpib #0x1a,%d0 124 beql cu_nneg |if $1a, it is fneg 125 | 126 | Inst is ftst. Check the source operand and set the cc's accordingly. 127 | No write is done, so simply rts. 128 | 129 cu_ntst: 130 movew LOCAL_EX(%a0),%d0 131 bclrl #15,%d0 132 sne LOCAL_SGN(%a0) 133 beqs cu_ntpo 134 orl #neg_mask,USER_FPSR(%a6) |set N 135 cu_ntpo: 136 cmpiw #0x7fff,%d0 |test for inf/nan 137 bnes cu_ntcz 138 tstl LOCAL_HI(%a0) 139 bnes cu_ntn 140 tstl LOCAL_LO(%a0) 141 bnes cu_ntn 142 orl #inf_mask,USER_FPSR(%a6) 143 rts 144 cu_ntn: 145 orl #nan_mask,USER_FPSR(%a6) 146 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for 147 | ;snan handler 148 149 rts 150 cu_ntcz: 151 tstl LOCAL_HI(%a0) 152 bnel cu_ntsx 153 tstl LOCAL_LO(%a0) 154 bnel cu_ntsx 155 orl #z_mask,USER_FPSR(%a6) 156 cu_ntsx: 157 rts 158 | 159 | Inst is fabs. Execute the absolute value function on the input. 160 | Branch to the fmove code. If the operand is NaN, do nothing. 161 | 162 cu_nabs: 163 moveb STAG(%a6),%d0 164 btstl #5,%d0 |test for NaN or zero 165 bne wr_etemp |if either, simply write it 166 bclrb #7,LOCAL_EX(%a0) |do abs 167 bras cu_nmove |fmove code will finish 168 | 169 | Inst is fneg. Execute the negate value function on the input. 170 | Fall though to the fmove code. If the operand is NaN, do nothing. 171 | 172 cu_nneg: 173 moveb STAG(%a6),%d0 174 btstl #5,%d0 |test for NaN or zero 175 bne wr_etemp |if either, simply write it 176 bchgb #7,LOCAL_EX(%a0) |do neg 177 | 178 | Inst is fmove. This code also handles all result writes. 179 | If bit 2 is set, round is forced to double. If it is clear, 180 | and bit 6 is set, round is forced to single. If both are clear, 181 | the round precision is found in the fpcr. If the rounding precision 182 | is double or single, round the result before the write. 183 | 184 cu_nmove: 185 moveb STAG(%a6),%d0 186 andib #0xe0,%d0 |isolate stag bits 187 bne wr_etemp |if not norm, simply write it 188 btstb #2,CMDREG1B+1(%a6) |check for rd 189 bne cu_nmrd 190 btstb #6,CMDREG1B+1(%a6) |check for rs 191 bne cu_nmrs 192 | 193 | The move or operation is not with forced precision. Test for 194 | nan or inf as the input; if so, simply write it to FPn. Use the 195 | FPCR_MODE byte to get rounding on norms and zeros. 196 | 197 cu_nmnr: 198 bfextu FPCR_MODE(%a6){#0:#2},%d0 199 tstb %d0 |check for extended 200 beq cu_wrexn |if so, just write result 201 cmpib #1,%d0 |check for single 202 beq cu_nmrs |fall through to double 203 | 204 | The move is fdmove or round precision is double. 205 | 206 cu_nmrd: 207 movel #2,%d0 |set up the size for denorm 208 movew LOCAL_EX(%a0),%d1 |compare exponent to double threshold 209 andw #0x7fff,%d1 210 cmpw #0x3c01,%d1 211 bls cu_nunfl 212 bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode 213 orl #0x00020000,%d1 |or in rprec (double) 214 clrl %d0 |clear g,r,s for round 215 bclrb #sign_bit,LOCAL_EX(%a0) |convert to internal format 216 sne LOCAL_SGN(%a0) 217 bsrl round 218 bfclr LOCAL_SGN(%a0){#0:#8} 219 beqs cu_nmrdc 220 bsetb #sign_bit,LOCAL_EX(%a0) 221 cu_nmrdc: 222 movew LOCAL_EX(%a0),%d1 |check for overflow 223 andw #0x7fff,%d1 224 cmpw #0x43ff,%d1 225 bge cu_novfl |take care of overflow case 226 bra cu_wrexn 227 | 228 | The move is fsmove or round precision is single. 229 | 230 cu_nmrs: 231 movel #1,%d0 232 movew LOCAL_EX(%a0),%d1 233 andw #0x7fff,%d1 234 cmpw #0x3f81,%d1 235 bls cu_nunfl 236 bfextu FPCR_MODE(%a6){#2:#2},%d1 237 orl #0x00010000,%d1 238 clrl %d0 239 bclrb #sign_bit,LOCAL_EX(%a0) 240 sne LOCAL_SGN(%a0) 241 bsrl round 242 bfclr LOCAL_SGN(%a0){#0:#8} 243 beqs cu_nmrsc 244 bsetb #sign_bit,LOCAL_EX(%a0) 245 cu_nmrsc: 246 movew LOCAL_EX(%a0),%d1 247 andw #0x7FFF,%d1 248 cmpw #0x407f,%d1 249 blt cu_wrexn 250 | 251 | The operand is above precision boundaries. Use t_ovfl to 252 | generate the correct value. 253 | 254 cu_novfl: 255 bsr t_ovfl 256 bra cu_wrexn 257 | 258 | The operand is below precision boundaries. Use denorm to 259 | generate the correct value. 260 | 261 cu_nunfl: 262 bclrb #sign_bit,LOCAL_EX(%a0) 263 sne LOCAL_SGN(%a0) 264 bsr denorm 265 bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format 266 beqs cu_nucont 267 bsetb #sign_bit,LOCAL_EX(%a0) 268 cu_nucont: 269 bfextu FPCR_MODE(%a6){#2:#2},%d1 270 btstb #2,CMDREG1B+1(%a6) |check for rd 271 bne inst_d 272 btstb #6,CMDREG1B+1(%a6) |check for rs 273 bne inst_s 274 swap %d1 275 moveb FPCR_MODE(%a6),%d1 276 lsrb #6,%d1 277 swap %d1 278 bra inst_sd 279 inst_d: 280 orl #0x00020000,%d1 281 bra inst_sd 282 inst_s: 283 orl #0x00010000,%d1 284 inst_sd: 285 bclrb #sign_bit,LOCAL_EX(%a0) 286 sne LOCAL_SGN(%a0) 287 bsrl round 288 bfclr LOCAL_SGN(%a0){#0:#8} 289 beqs cu_nuflp 290 bsetb #sign_bit,LOCAL_EX(%a0) 291 cu_nuflp: 292 btstb #inex2_bit,FPSR_EXCEPT(%a6) 293 beqs cu_nuninx 294 orl #aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL 295 cu_nuninx: 296 tstl LOCAL_HI(%a0) |test for zero 297 bnes cu_nunzro 298 tstl LOCAL_LO(%a0) 299 bnes cu_nunzro 300 | 301 | The mantissa is zero from the denorm loop. Check sign and rmode 302 | to see if rounding should have occurred which would leave the lsb. 303 | 304 movel USER_FPCR(%a6),%d0 305 andil #0x30,%d0 |isolate rmode 306 cmpil #0x20,%d0 307 blts cu_nzro 308 bnes cu_nrp 309 cu_nrm: 310 tstw LOCAL_EX(%a0) |if positive, set lsb 311 bges cu_nzro 312 btstb #7,FPCR_MODE(%a6) |check for double 313 beqs cu_nincs 314 bras cu_nincd 315 cu_nrp: 316 tstw LOCAL_EX(%a0) |if positive, set lsb 317 blts cu_nzro 318 btstb #7,FPCR_MODE(%a6) |check for double 319 beqs cu_nincs 320 cu_nincd: 321 orl #0x800,LOCAL_LO(%a0) |inc for double 322 bra cu_nunzro 323 cu_nincs: 324 orl #0x100,LOCAL_HI(%a0) |inc for single 325 bra cu_nunzro 326 cu_nzro: 327 orl #z_mask,USER_FPSR(%a6) 328 moveb STAG(%a6),%d0 329 andib #0xe0,%d0 330 cmpib #0x40,%d0 |check if input was tagged zero 331 beqs cu_numv 332 cu_nunzro: 333 orl #unfl_mask,USER_FPSR(%a6) |set unfl 334 cu_numv: 335 movel (%a0),ETEMP(%a6) 336 movel 4(%a0),ETEMP_HI(%a6) 337 movel 8(%a0),ETEMP_LO(%a6) 338 | 339 | Write the result to memory, setting the fpsr cc bits. NaN and Inf 340 | bypass cu_wrexn. 341 | 342 cu_wrexn: 343 tstw LOCAL_EX(%a0) |test for zero 344 beqs cu_wrzero 345 cmpw #0x8000,LOCAL_EX(%a0) |test for zero 346 bnes cu_wreon 347 cu_wrzero: 348 orl #z_mask,USER_FPSR(%a6) |set Z bit 349 cu_wreon: 350 tstw LOCAL_EX(%a0) 351 bpl wr_etemp 352 orl #neg_mask,USER_FPSR(%a6) 353 bra wr_etemp 354 355 | 356 | HANDLE SOURCE DENORM HERE 357 | 358 | ;clear denorm stag to norm 359 | ;write the new tag & ete15 to the fstack 360 mon_dnrm: 361 | 362 | At this point, check for the cases in which normalizing the 363 | denorm produces incorrect results. 364 | 365 tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would 366 bnes nrm_src |require normalization of denorm 367 368 | At this point: 369 | monadic instructions: fabs = $18 fneg = $1a ftst = $3a 370 | fmove = $00 fsmove = $40 fdmove = $44 371 | fsqrt = $05* fssqrt = $41 fdsqrt = $45 372 | (*fsqrt reencoded to $05) 373 | 374 movew CMDREG1B(%a6),%d0 |get command register 375 andil #0x7f,%d0 |strip to only command word 376 | 377 | At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and 378 | fdsqrt are possible. 379 | For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize) 380 | For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize) 381 | 382 btstl #0,%d0 383 bnes nrm_src |weed out fsqrt instructions 384 st CU_ONLY(%a6) |set cu-only inst flag 385 bra cu_dnrm |fmove, fabs, fneg, ftst 386 | ;cases go to cu_dnrm 387 nrm_src: 388 bclrb #sign_bit,LOCAL_EX(%a0) 389 sne LOCAL_SGN(%a0) 390 bsr nrm_set |normalize number (exponent will go 391 | ; negative) 392 bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign 393 394 bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format 395 beqs spos 396 bsetb #sign_bit,LOCAL_EX(%a0) 397 spos: 398 bfclr STAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0 399 bsetb #4,STAG(%a6) |set ETE15 400 orb #0xf0,DNRM_FLG(%a6) 401 normal: 402 tstb DNRM_FLG(%a6) |check if any of the ops were denorms 403 bne ck_wrap |if so, check if it is a potential 404 | ;wrap-around case 405 fix_stk: 406 moveb #0xfe,CU_SAVEPC(%a6) 407 bclrb #E1,E_BYTE(%a6) 408 409 clrw NMNEXC(%a6) 410 411 st RES_FLG(%a6) |indicate that a restore is needed 412 rts 413 414 | 415 | cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and 416 | ftst) completely in software without an frestore to the 040. 417 | 418 cu_dnrm: 419 st CU_ONLY(%a6) 420 movew CMDREG1B(%a6),%d0 421 andib #0x3b,%d0 |isolate bits to select inst 422 tstb %d0 423 beql cu_dmove |if zero, it is an fmove 424 cmpib #0x18,%d0 425 beql cu_dabs |if $18, it is fabs 426 cmpib #0x1a,%d0 427 beql cu_dneg |if $1a, it is fneg 428 | 429 | Inst is ftst. Check the source operand and set the cc's accordingly. 430 | No write is done, so simply rts. 431 | 432 cu_dtst: 433 movew LOCAL_EX(%a0),%d0 434 bclrl #15,%d0 435 sne LOCAL_SGN(%a0) 436 beqs cu_dtpo 437 orl #neg_mask,USER_FPSR(%a6) |set N 438 cu_dtpo: 439 cmpiw #0x7fff,%d0 |test for inf/nan 440 bnes cu_dtcz 441 tstl LOCAL_HI(%a0) 442 bnes cu_dtn 443 tstl LOCAL_LO(%a0) 444 bnes cu_dtn 445 orl #inf_mask,USER_FPSR(%a6) 446 rts 447 cu_dtn: 448 orl #nan_mask,USER_FPSR(%a6) 449 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for 450 | ;snan handler 451 rts 452 cu_dtcz: 453 tstl LOCAL_HI(%a0) 454 bnel cu_dtsx 455 tstl LOCAL_LO(%a0) 456 bnel cu_dtsx 457 orl #z_mask,USER_FPSR(%a6) 458 cu_dtsx: 459 rts 460 | 461 | Inst is fabs. Execute the absolute value function on the input. 462 | Branch to the fmove code. 463 | 464 cu_dabs: 465 bclrb #7,LOCAL_EX(%a0) |do abs 466 bras cu_dmove |fmove code will finish 467 | 468 | Inst is fneg. Execute the negate value function on the input. 469 | Fall though to the fmove code. 470 | 471 cu_dneg: 472 bchgb #7,LOCAL_EX(%a0) |do neg 473 | 474 | Inst is fmove. This code also handles all result writes. 475 | If bit 2 is set, round is forced to double. If it is clear, 476 | and bit 6 is set, round is forced to single. If both are clear, 477 | the round precision is found in the fpcr. If the rounding precision 478 | is double or single, the result is zero, and the mode is checked 479 | to determine if the lsb of the result should be set. 480 | 481 cu_dmove: 482 btstb #2,CMDREG1B+1(%a6) |check for rd 483 bne cu_dmrd 484 btstb #6,CMDREG1B+1(%a6) |check for rs 485 bne cu_dmrs 486 | 487 | The move or operation is not with forced precision. Use the 488 | FPCR_MODE byte to get rounding. 489 | 490 cu_dmnr: 491 bfextu FPCR_MODE(%a6){#0:#2},%d0 492 tstb %d0 |check for extended 493 beq cu_wrexd |if so, just write result 494 cmpib #1,%d0 |check for single 495 beq cu_dmrs |fall through to double 496 | 497 | The move is fdmove or round precision is double. Result is zero. 498 | Check rmode for rp or rm and set lsb accordingly. 499 | 500 cu_dmrd: 501 bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode 502 tstw LOCAL_EX(%a0) |check sign 503 blts cu_dmdn 504 cmpib #3,%d1 |check for rp 505 bne cu_dpd |load double pos zero 506 bra cu_dpdr |load double pos zero w/lsb 507 cu_dmdn: 508 cmpib #2,%d1 |check for rm 509 bne cu_dnd |load double neg zero 510 bra cu_dndr |load double neg zero w/lsb 511 | 512 | The move is fsmove or round precision is single. Result is zero. 513 | Check for rp or rm and set lsb accordingly. 514 | 515 cu_dmrs: 516 bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode 517 tstw LOCAL_EX(%a0) |check sign 518 blts cu_dmsn 519 cmpib #3,%d1 |check for rp 520 bne cu_spd |load single pos zero 521 bra cu_spdr |load single pos zero w/lsb 522 cu_dmsn: 523 cmpib #2,%d1 |check for rm 524 bne cu_snd |load single neg zero 525 bra cu_sndr |load single neg zero w/lsb 526 | 527 | The precision is extended, so the result in etemp is correct. 528 | Simply set unfl (not inex2 or aunfl) and write the result to 529 | the correct fp register. 530 cu_wrexd: 531 orl #unfl_mask,USER_FPSR(%a6) 532 tstw LOCAL_EX(%a0) 533 beq wr_etemp 534 orl #neg_mask,USER_FPSR(%a6) 535 bra wr_etemp 536 | 537 | These routines write +/- zero in double format. The routines 538 | cu_dpdr and cu_dndr set the double lsb. 539 | 540 cu_dpd: 541 movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero 542 clrl LOCAL_HI(%a0) 543 clrl LOCAL_LO(%a0) 544 orl #z_mask,USER_FPSR(%a6) 545 orl #unfinx_mask,USER_FPSR(%a6) 546 bra wr_etemp 547 cu_dpdr: 548 movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero 549 clrl LOCAL_HI(%a0) 550 movel #0x800,LOCAL_LO(%a0) |with lsb set 551 orl #unfinx_mask,USER_FPSR(%a6) 552 bra wr_etemp 553 cu_dnd: 554 movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero 555 clrl LOCAL_HI(%a0) 556 clrl LOCAL_LO(%a0) 557 orl #z_mask,USER_FPSR(%a6) 558 orl #neg_mask,USER_FPSR(%a6) 559 orl #unfinx_mask,USER_FPSR(%a6) 560 bra wr_etemp 561 cu_dndr: 562 movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero 563 clrl LOCAL_HI(%a0) 564 movel #0x800,LOCAL_LO(%a0) |with lsb set 565 orl #neg_mask,USER_FPSR(%a6) 566 orl #unfinx_mask,USER_FPSR(%a6) 567 bra wr_etemp 568 | 569 | These routines write +/- zero in single format. The routines 570 | cu_dpdr and cu_dndr set the single lsb. 571 | 572 cu_spd: 573 movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero 574 clrl LOCAL_HI(%a0) 575 clrl LOCAL_LO(%a0) 576 orl #z_mask,USER_FPSR(%a6) 577 orl #unfinx_mask,USER_FPSR(%a6) 578 bra wr_etemp 579 cu_spdr: 580 movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero 581 movel #0x100,LOCAL_HI(%a0) |with lsb set 582 clrl LOCAL_LO(%a0) 583 orl #unfinx_mask,USER_FPSR(%a6) 584 bra wr_etemp 585 cu_snd: 586 movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero 587 clrl LOCAL_HI(%a0) 588 clrl LOCAL_LO(%a0) 589 orl #z_mask,USER_FPSR(%a6) 590 orl #neg_mask,USER_FPSR(%a6) 591 orl #unfinx_mask,USER_FPSR(%a6) 592 bra wr_etemp 593 cu_sndr: 594 movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero 595 movel #0x100,LOCAL_HI(%a0) |with lsb set 596 clrl LOCAL_LO(%a0) 597 orl #neg_mask,USER_FPSR(%a6) 598 orl #unfinx_mask,USER_FPSR(%a6) 599 bra wr_etemp 600 601 | 602 | This code checks for 16-bit overflow conditions on dyadic 603 | operations which are not restorable into the floating-point 604 | unit and must be completed in software. Basically, this 605 | condition exists with a very large norm and a denorm. One 606 | of the operands must be denormalized to enter this code. 607 | 608 | Flags used: 609 | DY_MO_FLG contains 0 for monadic op, $ff for dyadic 610 | DNRM_FLG contains $00 for neither op denormalized 611 | $0f for the destination op denormalized 612 | $f0 for the source op denormalized 613 | $ff for both ops denormalized 614 | 615 | The wrap-around condition occurs for add, sub, div, and cmp 616 | when 617 | 618 | abs(dest_exp - src_exp) >= $8000 619 | 620 | and for mul when 621 | 622 | (dest_exp + src_exp) < $0 623 | 624 | we must process the operation here if this case is true. 625 | 626 | The rts following the frcfpn routine is the exit from res_func 627 | for this condition. The restore flag (RES_FLG) is left clear. 628 | No frestore is done unless an exception is to be reported. 629 | 630 | For fadd: 631 | if(sign_of(dest) != sign_of(src)) 632 | replace exponent of src with $3fff (keep sign) 633 | use fpu to perform dest+new_src (user's rmode and X) 634 | clr sticky 635 | else 636 | set sticky 637 | call round with user's precision and mode 638 | move result to fpn and wbtemp 639 | 640 | For fsub: 641 | if(sign_of(dest) == sign_of(src)) 642 | replace exponent of src with $3fff (keep sign) 643 | use fpu to perform dest+new_src (user's rmode and X) 644 | clr sticky 645 | else 646 | set sticky 647 | call round with user's precision and mode 648 | move result to fpn and wbtemp 649 | 650 | For fdiv/fsgldiv: 651 | if(both operands are denorm) 652 | restore_to_fpu; 653 | if(dest is norm) 654 | force_ovf; 655 | else(dest is denorm) 656 | force_unf: 657 | 658 | For fcmp: 659 | if(dest is norm) 660 | N = sign_of(dest); 661 | else(dest is denorm) 662 | N = sign_of(src); 663 | 664 | For fmul: 665 | if(both operands are denorm) 666 | force_unf; 667 | if((dest_exp + src_exp) < 0) 668 | force_unf: 669 | else 670 | restore_to_fpu; 671 | 672 | local equates: 673 .set addcode,0x22 674 .set subcode,0x28 675 .set mulcode,0x23 676 .set divcode,0x20 677 .set cmpcode,0x38 678 ck_wrap: 679 | tstb DY_MO_FLG(%a6) ;check for fsqrt 680 beq fix_stk |if zero, it is fsqrt 681 movew CMDREG1B(%a6),%d0 682 andiw #0x3b,%d0 |strip to command bits 683 cmpiw #addcode,%d0 684 beq wrap_add 685 cmpiw #subcode,%d0 686 beq wrap_sub 687 cmpiw #mulcode,%d0 688 beq wrap_mul 689 cmpiw #cmpcode,%d0 690 beq wrap_cmp 691 | 692 | Inst is fdiv. 693 | 694 wrap_div: 695 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, 696 beq fix_stk |restore to fpu 697 | 698 | One of the ops is denormalized. Test for wrap condition 699 | and force the result. 700 | 701 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm 702 bnes div_srcd 703 div_destd: 704 bsrl ckinf_ns 705 bne fix_stk 706 bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) 707 bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) 708 subl %d1,%d0 |subtract dest from src 709 cmpl #0x7fff,%d0 710 blt fix_stk |if less, not wrap case 711 clrb WBTEMP_SGN(%a6) 712 movew ETEMP_EX(%a6),%d0 |find the sign of the result 713 movew FPTEMP_EX(%a6),%d1 714 eorw %d1,%d0 715 andiw #0x8000,%d0 716 beq force_unf 717 st WBTEMP_SGN(%a6) 718 bra force_unf 719 720 ckinf_ns: 721 moveb STAG(%a6),%d0 |check source tag for inf or nan 722 bra ck_in_com 723 ckinf_nd: 724 moveb DTAG(%a6),%d0 |check destination tag for inf or nan 725 ck_in_com: 726 andib #0x60,%d0 |isolate tag bits 727 cmpb #0x40,%d0 |is it inf? 728 beq nan_or_inf |not wrap case 729 cmpb #0x60,%d0 |is it nan? 730 beq nan_or_inf |yes, not wrap case? 731 cmpb #0x20,%d0 |is it a zero? 732 beq nan_or_inf |yes 733 clrl %d0 734 rts |then ; it is either a zero of norm, 735 | ;check wrap case 736 nan_or_inf: 737 moveql #-1,%d0 738 rts 739 740 741 742 div_srcd: 743 bsrl ckinf_nd 744 bne fix_stk 745 bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) 746 bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) 747 subl %d1,%d0 |subtract src from dest 748 cmpl #0x8000,%d0 749 blt fix_stk |if less, not wrap case 750 clrb WBTEMP_SGN(%a6) 751 movew ETEMP_EX(%a6),%d0 |find the sign of the result 752 movew FPTEMP_EX(%a6),%d1 753 eorw %d1,%d0 754 andiw #0x8000,%d0 755 beqs force_ovf 756 st WBTEMP_SGN(%a6) 757 | 758 | This code handles the case of the instruction resulting in 759 | an overflow condition. 760 | 761 force_ovf: 762 bclrb #E1,E_BYTE(%a6) 763 orl #ovfl_inx_mask,USER_FPSR(%a6) 764 clrw NMNEXC(%a6) 765 leal WBTEMP(%a6),%a0 |point a0 to memory location 766 movew CMDREG1B(%a6),%d0 767 btstl #6,%d0 |test for forced precision 768 beqs frcovf_fpcr 769 btstl #2,%d0 |check for double 770 bnes frcovf_dbl 771 movel #0x1,%d0 |inst is forced single 772 bras frcovf_rnd 773 frcovf_dbl: 774 movel #0x2,%d0 |inst is forced double 775 bras frcovf_rnd 776 frcovf_fpcr: 777 bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec 778 frcovf_rnd: 779 780 | The 881/882 does not set inex2 for the following case, so the 781 | line is commented out to be compatible with 881/882 782 | tst.b %d0 783 | beq.b frcovf_x 784 | or.l #inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2 785 786 |frcovf_x: 787 bsrl ovf_res |get correct result based on 788 | ;round precision/mode. This 789 | ;sets FPSR_CC correctly 790 | ;returns in external format 791 bfclr WBTEMP_SGN(%a6){#0:#8} 792 beq frcfpn 793 bsetb #sign_bit,WBTEMP_EX(%a6) 794 bra frcfpn 795 | 796 | Inst is fadd. 797 | 798 wrap_add: 799 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, 800 beq fix_stk |restore to fpu 801 | 802 | One of the ops is denormalized. Test for wrap condition 803 | and complete the instruction. 804 | 805 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm 806 bnes add_srcd 807 add_destd: 808 bsrl ckinf_ns 809 bne fix_stk 810 bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) 811 bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) 812 subl %d1,%d0 |subtract dest from src 813 cmpl #0x8000,%d0 814 blt fix_stk |if less, not wrap case 815 bra add_wrap 816 add_srcd: 817 bsrl ckinf_nd 818 bne fix_stk 819 bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) 820 bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) 821 subl %d1,%d0 |subtract src from dest 822 cmpl #0x8000,%d0 823 blt fix_stk |if less, not wrap case 824 | 825 | Check the signs of the operands. If they are unlike, the fpu 826 | can be used to add the norm and 1.0 with the sign of the 827 | denorm and it will correctly generate the result in extended 828 | precision. We can then call round with no sticky and the result 829 | will be correct for the user's rounding mode and precision. If 830 | the signs are the same, we call round with the sticky bit set 831 | and the result will be correct for the user's rounding mode and 832 | precision. 833 | 834 add_wrap: 835 movew ETEMP_EX(%a6),%d0 836 movew FPTEMP_EX(%a6),%d1 837 eorw %d1,%d0 838 andiw #0x8000,%d0 839 beq add_same 840 | 841 | The signs are unlike. 842 | 843 cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? 844 bnes add_u_srcd 845 movew FPTEMP_EX(%a6),%d0 846 andiw #0x8000,%d0 847 orw #0x3fff,%d0 |force the exponent to +/- 1 848 movew %d0,FPTEMP_EX(%a6) |in the denorm 849 movel USER_FPCR(%a6),%d0 850 andil #0x30,%d0 851 fmovel %d0,%fpcr |set up users rmode and X 852 fmovex ETEMP(%a6),%fp0 853 faddx FPTEMP(%a6),%fp0 854 leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame 855 fmovel %fpsr,%d1 856 orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd 857 fmovex %fp0,WBTEMP(%a6) |write result to memory 858 lsrl #4,%d0 |put rmode in lower 2 bits 859 movel USER_FPCR(%a6),%d1 860 andil #0xc0,%d1 861 lsrl #6,%d1 |put precision in upper word 862 swap %d1 863 orl %d0,%d1 |set up for round call 864 clrl %d0 |force sticky to zero 865 bclrb #sign_bit,WBTEMP_EX(%a6) 866 sne WBTEMP_SGN(%a6) 867 bsrl round |round result to users rmode & prec 868 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 869 beq frcfpnr 870 bsetb #sign_bit,WBTEMP_EX(%a6) 871 bra frcfpnr 872 add_u_srcd: 873 movew ETEMP_EX(%a6),%d0 874 andiw #0x8000,%d0 875 orw #0x3fff,%d0 |force the exponent to +/- 1 876 movew %d0,ETEMP_EX(%a6) |in the denorm 877 movel USER_FPCR(%a6),%d0 878 andil #0x30,%d0 879 fmovel %d0,%fpcr |set up users rmode and X 880 fmovex ETEMP(%a6),%fp0 881 faddx FPTEMP(%a6),%fp0 882 fmovel %fpsr,%d1 883 orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd 884 leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame 885 fmovex %fp0,WBTEMP(%a6) |write result to memory 886 lsrl #4,%d0 |put rmode in lower 2 bits 887 movel USER_FPCR(%a6),%d1 888 andil #0xc0,%d1 889 lsrl #6,%d1 |put precision in upper word 890 swap %d1 891 orl %d0,%d1 |set up for round call 892 clrl %d0 |force sticky to zero 893 bclrb #sign_bit,WBTEMP_EX(%a6) 894 sne WBTEMP_SGN(%a6) |use internal format for round 895 bsrl round |round result to users rmode & prec 896 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 897 beq frcfpnr 898 bsetb #sign_bit,WBTEMP_EX(%a6) 899 bra frcfpnr 900 | 901 | Signs are alike: 902 | 903 add_same: 904 cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? 905 bnes add_s_srcd 906 add_s_destd: 907 leal ETEMP(%a6),%a0 908 movel USER_FPCR(%a6),%d0 909 andil #0x30,%d0 910 lsrl #4,%d0 |put rmode in lower 2 bits 911 movel USER_FPCR(%a6),%d1 912 andil #0xc0,%d1 913 lsrl #6,%d1 |put precision in upper word 914 swap %d1 915 orl %d0,%d1 |set up for round call 916 movel #0x20000000,%d0 |set sticky for round 917 bclrb #sign_bit,ETEMP_EX(%a6) 918 sne ETEMP_SGN(%a6) 919 bsrl round |round result to users rmode & prec 920 bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 921 beqs add_s_dclr 922 bsetb #sign_bit,ETEMP_EX(%a6) 923 add_s_dclr: 924 leal WBTEMP(%a6),%a0 925 movel ETEMP(%a6),(%a0) |write result to wbtemp 926 movel ETEMP_HI(%a6),4(%a0) 927 movel ETEMP_LO(%a6),8(%a0) 928 tstw ETEMP_EX(%a6) 929 bgt add_ckovf 930 orl #neg_mask,USER_FPSR(%a6) 931 bra add_ckovf 932 add_s_srcd: 933 leal FPTEMP(%a6),%a0 934 movel USER_FPCR(%a6),%d0 935 andil #0x30,%d0 936 lsrl #4,%d0 |put rmode in lower 2 bits 937 movel USER_FPCR(%a6),%d1 938 andil #0xc0,%d1 939 lsrl #6,%d1 |put precision in upper word 940 swap %d1 941 orl %d0,%d1 |set up for round call 942 movel #0x20000000,%d0 |set sticky for round 943 bclrb #sign_bit,FPTEMP_EX(%a6) 944 sne FPTEMP_SGN(%a6) 945 bsrl round |round result to users rmode & prec 946 bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 947 beqs add_s_sclr 948 bsetb #sign_bit,FPTEMP_EX(%a6) 949 add_s_sclr: 950 leal WBTEMP(%a6),%a0 951 movel FPTEMP(%a6),(%a0) |write result to wbtemp 952 movel FPTEMP_HI(%a6),4(%a0) 953 movel FPTEMP_LO(%a6),8(%a0) 954 tstw FPTEMP_EX(%a6) 955 bgt add_ckovf 956 orl #neg_mask,USER_FPSR(%a6) 957 add_ckovf: 958 movew WBTEMP_EX(%a6),%d0 959 andiw #0x7fff,%d0 960 cmpiw #0x7fff,%d0 961 bne frcfpnr 962 | 963 | The result has overflowed to $7fff exponent. Set I, ovfl, 964 | and aovfl, and clr the mantissa (incorrectly set by the 965 | round routine.) 966 | 967 orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6) 968 clrl 4(%a0) 969 bra frcfpnr 970 | 971 | Inst is fsub. 972 | 973 wrap_sub: 974 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, 975 beq fix_stk |restore to fpu 976 | 977 | One of the ops is denormalized. Test for wrap condition 978 | and complete the instruction. 979 | 980 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm 981 bnes sub_srcd 982 sub_destd: 983 bsrl ckinf_ns 984 bne fix_stk 985 bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) 986 bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) 987 subl %d1,%d0 |subtract src from dest 988 cmpl #0x8000,%d0 989 blt fix_stk |if less, not wrap case 990 bra sub_wrap 991 sub_srcd: 992 bsrl ckinf_nd 993 bne fix_stk 994 bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) 995 bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) 996 subl %d1,%d0 |subtract dest from src 997 cmpl #0x8000,%d0 998 blt fix_stk |if less, not wrap case 999 | 1000 | Check the signs of the operands. If they are alike, the fpu 1001 | can be used to subtract from the norm 1.0 with the sign of the 1002 | denorm and it will correctly generate the result in extended 1003 | precision. We can then call round with no sticky and the result 1004 | will be correct for the user's rounding mode and precision. If 1005 | the signs are unlike, we call round with the sticky bit set 1006 | and the result will be correct for the user's rounding mode and 1007 | precision. 1008 | 1009 sub_wrap: 1010 movew ETEMP_EX(%a6),%d0 1011 movew FPTEMP_EX(%a6),%d1 1012 eorw %d1,%d0 1013 andiw #0x8000,%d0 1014 bne sub_diff 1015 | 1016 | The signs are alike. 1017 | 1018 cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? 1019 bnes sub_u_srcd 1020 movew FPTEMP_EX(%a6),%d0 1021 andiw #0x8000,%d0 1022 orw #0x3fff,%d0 |force the exponent to +/- 1 1023 movew %d0,FPTEMP_EX(%a6) |in the denorm 1024 movel USER_FPCR(%a6),%d0 1025 andil #0x30,%d0 1026 fmovel %d0,%fpcr |set up users rmode and X 1027 fmovex FPTEMP(%a6),%fp0 1028 fsubx ETEMP(%a6),%fp0 1029 fmovel %fpsr,%d1 1030 orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd 1031 leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame 1032 fmovex %fp0,WBTEMP(%a6) |write result to memory 1033 lsrl #4,%d0 |put rmode in lower 2 bits 1034 movel USER_FPCR(%a6),%d1 1035 andil #0xc0,%d1 1036 lsrl #6,%d1 |put precision in upper word 1037 swap %d1 1038 orl %d0,%d1 |set up for round call 1039 clrl %d0 |force sticky to zero 1040 bclrb #sign_bit,WBTEMP_EX(%a6) 1041 sne WBTEMP_SGN(%a6) 1042 bsrl round |round result to users rmode & prec 1043 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 1044 beq frcfpnr 1045 bsetb #sign_bit,WBTEMP_EX(%a6) 1046 bra frcfpnr 1047 sub_u_srcd: 1048 movew ETEMP_EX(%a6),%d0 1049 andiw #0x8000,%d0 1050 orw #0x3fff,%d0 |force the exponent to +/- 1 1051 movew %d0,ETEMP_EX(%a6) |in the denorm 1052 movel USER_FPCR(%a6),%d0 1053 andil #0x30,%d0 1054 fmovel %d0,%fpcr |set up users rmode and X 1055 fmovex FPTEMP(%a6),%fp0 1056 fsubx ETEMP(%a6),%fp0 1057 fmovel %fpsr,%d1 1058 orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd 1059 leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame 1060 fmovex %fp0,WBTEMP(%a6) |write result to memory 1061 lsrl #4,%d0 |put rmode in lower 2 bits 1062 movel USER_FPCR(%a6),%d1 1063 andil #0xc0,%d1 1064 lsrl #6,%d1 |put precision in upper word 1065 swap %d1 1066 orl %d0,%d1 |set up for round call 1067 clrl %d0 |force sticky to zero 1068 bclrb #sign_bit,WBTEMP_EX(%a6) 1069 sne WBTEMP_SGN(%a6) 1070 bsrl round |round result to users rmode & prec 1071 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 1072 beq frcfpnr 1073 bsetb #sign_bit,WBTEMP_EX(%a6) 1074 bra frcfpnr 1075 | 1076 | Signs are unlike: 1077 | 1078 sub_diff: 1079 cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? 1080 bnes sub_s_srcd 1081 sub_s_destd: 1082 leal ETEMP(%a6),%a0 1083 movel USER_FPCR(%a6),%d0 1084 andil #0x30,%d0 1085 lsrl #4,%d0 |put rmode in lower 2 bits 1086 movel USER_FPCR(%a6),%d1 1087 andil #0xc0,%d1 1088 lsrl #6,%d1 |put precision in upper word 1089 swap %d1 1090 orl %d0,%d1 |set up for round call 1091 movel #0x20000000,%d0 |set sticky for round 1092 | 1093 | Since the dest is the denorm, the sign is the opposite of the 1094 | norm sign. 1095 | 1096 eoriw #0x8000,ETEMP_EX(%a6) |flip sign on result 1097 tstw ETEMP_EX(%a6) 1098 bgts sub_s_dwr 1099 orl #neg_mask,USER_FPSR(%a6) 1100 sub_s_dwr: 1101 bclrb #sign_bit,ETEMP_EX(%a6) 1102 sne ETEMP_SGN(%a6) 1103 bsrl round |round result to users rmode & prec 1104 bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 1105 beqs sub_s_dclr 1106 bsetb #sign_bit,ETEMP_EX(%a6) 1107 sub_s_dclr: 1108 leal WBTEMP(%a6),%a0 1109 movel ETEMP(%a6),(%a0) |write result to wbtemp 1110 movel ETEMP_HI(%a6),4(%a0) 1111 movel ETEMP_LO(%a6),8(%a0) 1112 bra sub_ckovf 1113 sub_s_srcd: 1114 leal FPTEMP(%a6),%a0 1115 movel USER_FPCR(%a6),%d0 1116 andil #0x30,%d0 1117 lsrl #4,%d0 |put rmode in lower 2 bits 1118 movel USER_FPCR(%a6),%d1 1119 andil #0xc0,%d1 1120 lsrl #6,%d1 |put precision in upper word 1121 swap %d1 1122 orl %d0,%d1 |set up for round call 1123 movel #0x20000000,%d0 |set sticky for round 1124 bclrb #sign_bit,FPTEMP_EX(%a6) 1125 sne FPTEMP_SGN(%a6) 1126 bsrl round |round result to users rmode & prec 1127 bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 1128 beqs sub_s_sclr 1129 bsetb #sign_bit,FPTEMP_EX(%a6) 1130 sub_s_sclr: 1131 leal WBTEMP(%a6),%a0 1132 movel FPTEMP(%a6),(%a0) |write result to wbtemp 1133 movel FPTEMP_HI(%a6),4(%a0) 1134 movel FPTEMP_LO(%a6),8(%a0) 1135 tstw FPTEMP_EX(%a6) 1136 bgt sub_ckovf 1137 orl #neg_mask,USER_FPSR(%a6) 1138 sub_ckovf: 1139 movew WBTEMP_EX(%a6),%d0 1140 andiw #0x7fff,%d0 1141 cmpiw #0x7fff,%d0 1142 bne frcfpnr 1143 | 1144 | The result has overflowed to $7fff exponent. Set I, ovfl, 1145 | and aovfl, and clr the mantissa (incorrectly set by the 1146 | round routine.) 1147 | 1148 orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6) 1149 clrl 4(%a0) 1150 bra frcfpnr 1151 | 1152 | Inst is fcmp. 1153 | 1154 wrap_cmp: 1155 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, 1156 beq fix_stk |restore to fpu 1157 | 1158 | One of the ops is denormalized. Test for wrap condition 1159 | and complete the instruction. 1160 | 1161 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm 1162 bnes cmp_srcd 1163 cmp_destd: 1164 bsrl ckinf_ns 1165 bne fix_stk 1166 bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) 1167 bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) 1168 subl %d1,%d0 |subtract dest from src 1169 cmpl #0x8000,%d0 1170 blt fix_stk |if less, not wrap case 1171 tstw ETEMP_EX(%a6) |set N to ~sign_of(src) 1172 bge cmp_setn 1173 rts 1174 cmp_srcd: 1175 bsrl ckinf_nd 1176 bne fix_stk 1177 bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) 1178 bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) 1179 subl %d1,%d0 |subtract src from dest 1180 cmpl #0x8000,%d0 1181 blt fix_stk |if less, not wrap case 1182 tstw FPTEMP_EX(%a6) |set N to sign_of(dest) 1183 blt cmp_setn 1184 rts 1185 cmp_setn: 1186 orl #neg_mask,USER_FPSR(%a6) 1187 rts 1188 1189 | 1190 | Inst is fmul. 1191 | 1192 wrap_mul: 1193 cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, 1194 beq force_unf |force an underflow (really!) 1195 | 1196 | One of the ops is denormalized. Test for wrap condition 1197 | and complete the instruction. 1198 | 1199 cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm 1200 bnes mul_srcd 1201 mul_destd: 1202 bsrl ckinf_ns 1203 bne fix_stk 1204 bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) 1205 bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) 1206 addl %d1,%d0 |subtract dest from src 1207 bgt fix_stk 1208 bra force_unf 1209 mul_srcd: 1210 bsrl ckinf_nd 1211 bne fix_stk 1212 bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) 1213 bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) 1214 addl %d1,%d0 |subtract src from dest 1215 bgt fix_stk 1216 1217 | 1218 | This code handles the case of the instruction resulting in 1219 | an underflow condition. 1220 | 1221 force_unf: 1222 bclrb #E1,E_BYTE(%a6) 1223 orl #unfinx_mask,USER_FPSR(%a6) 1224 clrw NMNEXC(%a6) 1225 clrb WBTEMP_SGN(%a6) 1226 movew ETEMP_EX(%a6),%d0 |find the sign of the result 1227 movew FPTEMP_EX(%a6),%d1 1228 eorw %d1,%d0 1229 andiw #0x8000,%d0 1230 beqs frcunfcont 1231 st WBTEMP_SGN(%a6) 1232 frcunfcont: 1233 lea WBTEMP(%a6),%a0 |point a0 to memory location 1234 movew CMDREG1B(%a6),%d0 1235 btstl #6,%d0 |test for forced precision 1236 beqs frcunf_fpcr 1237 btstl #2,%d0 |check for double 1238 bnes frcunf_dbl 1239 movel #0x1,%d0 |inst is forced single 1240 bras frcunf_rnd 1241 frcunf_dbl: 1242 movel #0x2,%d0 |inst is forced double 1243 bras frcunf_rnd 1244 frcunf_fpcr: 1245 bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec 1246 frcunf_rnd: 1247 bsrl unf_sub |get correct result based on 1248 | ;round precision/mode. This 1249 | ;sets FPSR_CC correctly 1250 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 1251 beqs frcfpn 1252 bsetb #sign_bit,WBTEMP_EX(%a6) 1253 bra frcfpn 1254 1255 | 1256 | Write the result to the user's fpn. All results must be HUGE to be 1257 | written; otherwise the results would have overflowed or underflowed. 1258 | If the rounding precision is single or double, the ovf_res routine 1259 | is needed to correctly supply the max value. 1260 | 1261 frcfpnr: 1262 movew CMDREG1B(%a6),%d0 1263 btstl #6,%d0 |test for forced precision 1264 beqs frcfpn_fpcr 1265 btstl #2,%d0 |check for double 1266 bnes frcfpn_dbl 1267 movel #0x1,%d0 |inst is forced single 1268 bras frcfpn_rnd 1269 frcfpn_dbl: 1270 movel #0x2,%d0 |inst is forced double 1271 bras frcfpn_rnd 1272 frcfpn_fpcr: 1273 bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec 1274 tstb %d0 1275 beqs frcfpn |if extended, write what you got 1276 frcfpn_rnd: 1277 bclrb #sign_bit,WBTEMP_EX(%a6) 1278 sne WBTEMP_SGN(%a6) 1279 bsrl ovf_res |get correct result based on 1280 | ;round precision/mode. This 1281 | ;sets FPSR_CC correctly 1282 bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format 1283 beqs frcfpn_clr 1284 bsetb #sign_bit,WBTEMP_EX(%a6) 1285 frcfpn_clr: 1286 orl #ovfinx_mask,USER_FPSR(%a6) 1287 | 1288 | Perform the write. 1289 | 1290 frcfpn: 1291 bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register 1292 cmpib #3,%d0 1293 bles frc0123 |check if dest is fp0-fp3 1294 movel #7,%d1 1295 subl %d0,%d1 1296 clrl %d0 1297 bsetl %d1,%d0 1298 fmovemx WBTEMP(%a6),%d0 1299 rts 1300 frc0123: 1301 cmpib #0,%d0 1302 beqs frc0_dst 1303 cmpib #1,%d0 1304 beqs frc1_dst 1305 cmpib #2,%d0 1306 beqs frc2_dst 1307 frc3_dst: 1308 movel WBTEMP_EX(%a6),USER_FP3(%a6) 1309 movel WBTEMP_HI(%a6),USER_FP3+4(%a6) 1310 movel WBTEMP_LO(%a6),USER_FP3+8(%a6) 1311 rts 1312 frc2_dst: 1313 movel WBTEMP_EX(%a6),USER_FP2(%a6) 1314 movel WBTEMP_HI(%a6),USER_FP2+4(%a6) 1315 movel WBTEMP_LO(%a6),USER_FP2+8(%a6) 1316 rts 1317 frc1_dst: 1318 movel WBTEMP_EX(%a6),USER_FP1(%a6) 1319 movel WBTEMP_HI(%a6),USER_FP1+4(%a6) 1320 movel WBTEMP_LO(%a6),USER_FP1+8(%a6) 1321 rts 1322 frc0_dst: 1323 movel WBTEMP_EX(%a6),USER_FP0(%a6) 1324 movel WBTEMP_HI(%a6),USER_FP0+4(%a6) 1325 movel WBTEMP_LO(%a6),USER_FP0+8(%a6) 1326 rts 1327 1328 | 1329 | Write etemp to fpn. 1330 | A check is made on enabled and signalled snan exceptions, 1331 | and the destination is not overwritten if this condition exists. 1332 | This code is designed to make fmoveins of unsupported data types 1333 | faster. 1334 | 1335 wr_etemp: 1336 btstb #snan_bit,FPSR_EXCEPT(%a6) |if snan is set, and 1337 beqs fmoveinc |enabled, force restore 1338 btstb #snan_bit,FPCR_ENABLE(%a6) |and don't overwrite 1339 beqs fmoveinc |the dest 1340 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for 1341 | ;snan handler 1342 tstb ETEMP(%a6) |check for negative 1343 blts snan_neg 1344 rts 1345 snan_neg: 1346 orl #neg_bit,USER_FPSR(%a6) |snan is negative; set N 1347 rts 1348 fmoveinc: 1349 clrw NMNEXC(%a6) 1350 bclrb #E1,E_BYTE(%a6) 1351 moveb STAG(%a6),%d0 |check if stag is inf 1352 andib #0xe0,%d0 1353 cmpib #0x40,%d0 1354 bnes fminc_cnan 1355 orl #inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set I 1356 tstw LOCAL_EX(%a0) |check sign 1357 bges fminc_con 1358 orl #neg_mask,USER_FPSR(%a6) 1359 bra fminc_con 1360 fminc_cnan: 1361 cmpib #0x60,%d0 |check if stag is NaN 1362 bnes fminc_czero 1363 orl #nan_mask,USER_FPSR(%a6) |if nan, nothing yet has set NaN 1364 movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for 1365 | ;snan handler 1366 tstw LOCAL_EX(%a0) |check sign 1367 bges fminc_con 1368 orl #neg_mask,USER_FPSR(%a6) 1369 bra fminc_con 1370 fminc_czero: 1371 cmpib #0x20,%d0 |check if zero 1372 bnes fminc_con 1373 orl #z_mask,USER_FPSR(%a6) |if zero, set Z 1374 tstw LOCAL_EX(%a0) |check sign 1375 bges fminc_con 1376 orl #neg_mask,USER_FPSR(%a6) 1377 fminc_con: 1378 bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register 1379 cmpib #3,%d0 1380 bles fp0123 |check if dest is fp0-fp3 1381 movel #7,%d1 1382 subl %d0,%d1 1383 clrl %d0 1384 bsetl %d1,%d0 1385 fmovemx ETEMP(%a6),%d0 1386 rts 1387 1388 fp0123: 1389 cmpib #0,%d0 1390 beqs fp0_dst 1391 cmpib #1,%d0 1392 beqs fp1_dst 1393 cmpib #2,%d0 1394 beqs fp2_dst 1395 fp3_dst: 1396 movel ETEMP_EX(%a6),USER_FP3(%a6) 1397 movel ETEMP_HI(%a6),USER_FP3+4(%a6) 1398 movel ETEMP_LO(%a6),USER_FP3+8(%a6) 1399 rts 1400 fp2_dst: 1401 movel ETEMP_EX(%a6),USER_FP2(%a6) 1402 movel ETEMP_HI(%a6),USER_FP2+4(%a6) 1403 movel ETEMP_LO(%a6),USER_FP2+8(%a6) 1404 rts 1405 fp1_dst: 1406 movel ETEMP_EX(%a6),USER_FP1(%a6) 1407 movel ETEMP_HI(%a6),USER_FP1+4(%a6) 1408 movel ETEMP_LO(%a6),USER_FP1+8(%a6) 1409 rts 1410 fp0_dst: 1411 movel ETEMP_EX(%a6),USER_FP0(%a6) 1412 movel ETEMP_HI(%a6),USER_FP0+4(%a6) 1413 movel ETEMP_LO(%a6),USER_FP0+8(%a6) 1414 rts 1415 1416 opclass3: 1417 st CU_ONLY(%a6) 1418 movew CMDREG1B(%a6),%d0 |check if packed moveout 1419 andiw #0x0c00,%d0 |isolate last 2 bits of size field 1420 cmpiw #0x0c00,%d0 |if size is 011 or 111, it is packed 1421 beq pack_out |else it is norm or denorm 1422 bra mv_out 1423 1424 1425 | 1426 | MOVE OUT 1427 | 1428 1429 mv_tbl: 1430 .long li 1431 .long sgp 1432 .long xp 1433 .long mvout_end |should never be taken 1434 .long wi 1435 .long dp 1436 .long bi 1437 .long mvout_end |should never be taken 1438 mv_out: 1439 bfextu CMDREG1B(%a6){#3:#3},%d1 |put source specifier in d1 1440 leal mv_tbl,%a0 1441 movel %a0@(%d1:l:4),%a0 1442 jmp (%a0) 1443 1444 | 1445 | This exit is for move-out to memory. The aunfl bit is 1446 | set if the result is inex and unfl is signalled. 1447 | 1448 mvout_end: 1449 btstb #inex2_bit,FPSR_EXCEPT(%a6) 1450 beqs no_aufl 1451 btstb #unfl_bit,FPSR_EXCEPT(%a6) 1452 beqs no_aufl 1453 bsetb #aunfl_bit,FPSR_AEXCEPT(%a6) 1454 no_aufl: 1455 clrw NMNEXC(%a6) 1456 bclrb #E1,E_BYTE(%a6) 1457 fmovel #0,%FPSR |clear any cc bits from res_func 1458 | 1459 | Return ETEMP to extended format from internal extended format so 1460 | that gen_except will have a correctly signed value for ovfl/unfl 1461 | handlers. 1462 | 1463 bfclr ETEMP_SGN(%a6){#0:#8} 1464 beqs mvout_con 1465 bsetb #sign_bit,ETEMP_EX(%a6) 1466 mvout_con: 1467 rts 1468 | 1469 | This exit is for move-out to int register. The aunfl bit is 1470 | not set in any case for this move. 1471 | 1472 mvouti_end: 1473 clrw NMNEXC(%a6) 1474 bclrb #E1,E_BYTE(%a6) 1475 fmovel #0,%FPSR |clear any cc bits from res_func 1476 | 1477 | Return ETEMP to extended format from internal extended format so 1478 | that gen_except will have a correctly signed value for ovfl/unfl 1479 | handlers. 1480 | 1481 bfclr ETEMP_SGN(%a6){#0:#8} 1482 beqs mvouti_con 1483 bsetb #sign_bit,ETEMP_EX(%a6) 1484 mvouti_con: 1485 rts 1486 | 1487 | li is used to handle a long integer source specifier 1488 | 1489 1490 li: 1491 moveql #4,%d0 |set byte count 1492 1493 btstb #7,STAG(%a6) |check for extended denorm 1494 bne int_dnrm |if so, branch 1495 1496 fmovemx ETEMP(%a6),%fp0-%fp0 1497 fcmpd #0x41dfffffffc00000,%fp0 1498 | 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec 1499 fbge lo_plrg 1500 fcmpd #0xc1e0000000000000,%fp0 1501 | c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec 1502 fble lo_nlrg 1503 | 1504 | at this point, the answer is between the largest pos and neg values 1505 | 1506 movel USER_FPCR(%a6),%d1 |use user's rounding mode 1507 andil #0x30,%d1 1508 fmovel %d1,%fpcr 1509 fmovel %fp0,L_SCR1(%a6) |let the 040 perform conversion 1510 fmovel %fpsr,%d1 1511 orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set 1512 bra int_wrt 1513 1514 1515 lo_plrg: 1516 movel #0x7fffffff,L_SCR1(%a6) |answer is largest positive int 1517 fbeq int_wrt |exact answer 1518 fcmpd #0x41dfffffffe00000,%fp0 1519 | 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec 1520 fbge int_operr |set operr 1521 bra int_inx |set inexact 1522 1523 lo_nlrg: 1524 movel #0x80000000,L_SCR1(%a6) 1525 fbeq int_wrt |exact answer 1526 fcmpd #0xc1e0000000100000,%fp0 1527 | c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec 1528 fblt int_operr |set operr 1529 bra int_inx |set inexact 1530 1531 | 1532 | wi is used to handle a word integer source specifier 1533 | 1534 1535 wi: 1536 moveql #2,%d0 |set byte count 1537 1538 btstb #7,STAG(%a6) |check for extended denorm 1539 bne int_dnrm |branch if so 1540 1541 fmovemx ETEMP(%a6),%fp0-%fp0 1542 fcmps #0x46fffe00,%fp0 1543 | 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec 1544 fbge wo_plrg 1545 fcmps #0xc7000000,%fp0 1546 | c7000000 in sgl prec = c00e00008000000000000000 in ext prec 1547 fble wo_nlrg 1548 1549 | 1550 | at this point, the answer is between the largest pos and neg values 1551 | 1552 movel USER_FPCR(%a6),%d1 |use user's rounding mode 1553 andil #0x30,%d1 1554 fmovel %d1,%fpcr 1555 fmovew %fp0,L_SCR1(%a6) |let the 040 perform conversion 1556 fmovel %fpsr,%d1 1557 orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set 1558 bra int_wrt 1559 1560 wo_plrg: 1561 movew #0x7fff,L_SCR1(%a6) |answer is largest positive int 1562 fbeq int_wrt |exact answer 1563 fcmps #0x46ffff00,%fp0 1564 | 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec 1565 fbge int_operr |set operr 1566 bra int_inx |set inexact 1567 1568 wo_nlrg: 1569 movew #0x8000,L_SCR1(%a6) 1570 fbeq int_wrt |exact answer 1571 fcmps #0xc7000080,%fp0 1572 | c7000080 in sgl prec = c00e00008000800000000000 in ext prec 1573 fblt int_operr |set operr 1574 bra int_inx |set inexact 1575 1576 | 1577 | bi is used to handle a byte integer source specifier 1578 | 1579 1580 bi: 1581 moveql #1,%d0 |set byte count 1582 1583 btstb #7,STAG(%a6) |check for extended denorm 1584 bne int_dnrm |branch if so 1585 1586 fmovemx ETEMP(%a6),%fp0-%fp0 1587 fcmps #0x42fe0000,%fp0 1588 | 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec 1589 fbge by_plrg 1590 fcmps #0xc3000000,%fp0 1591 | c3000000 in sgl prec = c00600008000000000000000 in ext prec 1592 fble by_nlrg 1593 1594 | 1595 | at this point, the answer is between the largest pos and neg values 1596 | 1597 movel USER_FPCR(%a6),%d1 |use user's rounding mode 1598 andil #0x30,%d1 1599 fmovel %d1,%fpcr 1600 fmoveb %fp0,L_SCR1(%a6) |let the 040 perform conversion 1601 fmovel %fpsr,%d1 1602 orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set 1603 bra int_wrt 1604 1605 by_plrg: 1606 moveb #0x7f,L_SCR1(%a6) |answer is largest positive int 1607 fbeq int_wrt |exact answer 1608 fcmps #0x42ff0000,%fp0 1609 | 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec 1610 fbge int_operr |set operr 1611 bra int_inx |set inexact 1612 1613 by_nlrg: 1614 moveb #0x80,L_SCR1(%a6) 1615 fbeq int_wrt |exact answer 1616 fcmps #0xc3008000,%fp0 1617 | c3008000 in sgl prec = c00600008080000000000000 in ext prec 1618 fblt int_operr |set operr 1619 bra int_inx |set inexact 1620 1621 | 1622 | Common integer routines 1623 | 1624 | int_drnrm---account for possible nonzero result for round up with positive 1625 | operand and round down for negative answer. In the first case (result = 1) 1626 | byte-width (store in d0) of result must be honored. In the second case, 1627 | -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out). 1628 1629 int_dnrm: 1630 movel #0,L_SCR1(%a6) | initialize result to 0 1631 bfextu FPCR_MODE(%a6){#2:#2},%d1 | d1 is the rounding mode 1632 cmpb #2,%d1 1633 bmis int_inx | if RN or RZ, done 1634 bnes int_rp | if RP, continue below 1635 tstw ETEMP(%a6) | RM: store -1 in L_SCR1 if src is negative 1636 bpls int_inx | otherwise result is 0 1637 movel #-1,L_SCR1(%a6) 1638 bras int_inx 1639 int_rp: 1640 tstw ETEMP(%a6) | RP: store +1 of proper width in L_SCR1 if 1641 | ; source is greater than 0 1642 bmis int_inx | otherwise, result is 0 1643 lea L_SCR1(%a6),%a1 | a1 is address of L_SCR1 1644 addal %d0,%a1 | offset by destination width -1 1645 subal #1,%a1 1646 bsetb #0,(%a1) | set low bit at a1 address 1647 int_inx: 1648 oril #inx2a_mask,USER_FPSR(%a6) 1649 bras int_wrt 1650 int_operr: 1651 fmovemx %fp0-%fp0,FPTEMP(%a6) |FPTEMP must contain the extended 1652 | ;precision source that needs to be 1653 | ;converted to integer this is required 1654 | ;if the operr exception is enabled. 1655 | ;set operr/aiop (no inex2 on int ovfl) 1656 1657 oril #opaop_mask,USER_FPSR(%a6) 1658 | ;fall through to perform int_wrt 1659 int_wrt: 1660 movel EXC_EA(%a6),%a1 |load destination address 1661 tstl %a1 |check to see if it is a dest register 1662 beqs wrt_dn |write data register 1663 lea L_SCR1(%a6),%a0 |point to supervisor source address 1664 bsrl mem_write 1665 bra mvouti_end 1666 1667 wrt_dn: 1668 movel %d0,-(%sp) |d0 currently contains the size to write 1669 bsrl get_fline |get_fline returns Dn in d0 1670 andiw #0x7,%d0 |isolate register 1671 movel (%sp)+,%d1 |get size 1672 cmpil #4,%d1 |most frequent case 1673 beqs sz_long 1674 cmpil #2,%d1 1675 bnes sz_con 1676 orl #8,%d0 |add 'word' size to register# 1677 bras sz_con 1678 sz_long: 1679 orl #0x10,%d0 |add 'long' size to register# 1680 sz_con: 1681 movel %d0,%d1 |reg_dest expects size:reg in d1 1682 bsrl reg_dest |load proper data register 1683 bra mvouti_end 1684 xp: 1685 lea ETEMP(%a6),%a0 1686 bclrb #sign_bit,LOCAL_EX(%a0) 1687 sne LOCAL_SGN(%a0) 1688 btstb #7,STAG(%a6) |check for extended denorm 1689 bne xdnrm 1690 clrl %d0 1691 bras do_fp |do normal case 1692 sgp: 1693 lea ETEMP(%a6),%a0 1694 bclrb #sign_bit,LOCAL_EX(%a0) 1695 sne LOCAL_SGN(%a0) 1696 btstb #7,STAG(%a6) |check for extended denorm 1697 bne sp_catas |branch if so 1698 movew LOCAL_EX(%a0),%d0 1699 lea sp_bnds,%a1 1700 cmpw (%a1),%d0 1701 blt sp_under 1702 cmpw 2(%a1),%d0 1703 bgt sp_over 1704 movel #1,%d0 |set destination format to single 1705 bras do_fp |do normal case 1706 dp: 1707 lea ETEMP(%a6),%a0 1708 bclrb #sign_bit,LOCAL_EX(%a0) 1709 sne LOCAL_SGN(%a0) 1710 1711 btstb #7,STAG(%a6) |check for extended denorm 1712 bne dp_catas |branch if so 1713 1714 movew LOCAL_EX(%a0),%d0 1715 lea dp_bnds,%a1 1716 1717 cmpw (%a1),%d0 1718 blt dp_under 1719 cmpw 2(%a1),%d0 1720 bgt dp_over 1721 1722 movel #2,%d0 |set destination format to double 1723 | ;fall through to do_fp 1724 | 1725 do_fp: 1726 bfextu FPCR_MODE(%a6){#2:#2},%d1 |rnd mode in d1 1727 swap %d0 |rnd prec in upper word 1728 addl %d0,%d1 |d1 has PREC/MODE info 1729 1730 clrl %d0 |clear g,r,s 1731 1732 bsrl round |round 1733 1734 movel %a0,%a1 1735 movel EXC_EA(%a6),%a0 1736 1737 bfextu CMDREG1B(%a6){#3:#3},%d1 |extract destination format 1738 | ;at this point only the dest 1739 | ;formats sgl, dbl, ext are 1740 | ;possible 1741 cmpb #2,%d1 1742 bgts ddbl |double=5, extended=2, single=1 1743 bnes dsgl 1744 | ;fall through to dext 1745 dext: 1746 bsrl dest_ext 1747 bra mvout_end 1748 dsgl: 1749 bsrl dest_sgl 1750 bra mvout_end 1751 ddbl: 1752 bsrl dest_dbl 1753 bra mvout_end 1754 1755 | 1756 | Handle possible denorm or catastrophic underflow cases here 1757 | 1758 xdnrm: 1759 bsr set_xop |initialize WBTEMP 1760 bsetb #wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15 1761 1762 movel %a0,%a1 1763 movel EXC_EA(%a6),%a0 |a0 has the destination pointer 1764 bsrl dest_ext |store to memory 1765 bsetb #unfl_bit,FPSR_EXCEPT(%a6) 1766 bra mvout_end 1767 1768 sp_under: 1769 bsetb #etemp15_bit,STAG(%a6) 1770 1771 cmpw 4(%a1),%d0 1772 blts sp_catas |catastrophic underflow case 1773 1774 movel #1,%d0 |load in round precision 1775 movel #sgl_thresh,%d1 |load in single denorm threshold 1776 bsrl dpspdnrm |expects d1 to have the proper 1777 | ;denorm threshold 1778 bsrl dest_sgl |stores value to destination 1779 bsetb #unfl_bit,FPSR_EXCEPT(%a6) 1780 bra mvout_end |exit 1781 1782 dp_under: 1783 bsetb #etemp15_bit,STAG(%a6) 1784 1785 cmpw 4(%a1),%d0 1786 blts dp_catas |catastrophic underflow case 1787 1788 movel #dbl_thresh,%d1 |load in double precision threshold 1789 movel #2,%d0 1790 bsrl dpspdnrm |expects d1 to have proper 1791 | ;denorm threshold 1792 | ;expects d0 to have round precision 1793 bsrl dest_dbl |store value to destination 1794 bsetb #unfl_bit,FPSR_EXCEPT(%a6) 1795 bra mvout_end |exit 1796 1797 | 1798 | Handle catastrophic underflow cases here 1799 | 1800 sp_catas: 1801 | Temp fix for z bit set in unf_sub 1802 movel USER_FPSR(%a6),-(%a7) 1803 1804 movel #1,%d0 |set round precision to sgl 1805 1806 bsrl unf_sub |a0 points to result 1807 1808 movel (%a7)+,USER_FPSR(%a6) 1809 1810 movel #1,%d0 1811 subw %d0,LOCAL_EX(%a0) |account for difference between 1812 | ;denorm/norm bias 1813 1814 movel %a0,%a1 |a1 has the operand input 1815 movel EXC_EA(%a6),%a0 |a0 has the destination pointer 1816 1817 bsrl dest_sgl |store the result 1818 oril #unfinx_mask,USER_FPSR(%a6) 1819 bra mvout_end 1820 1821 dp_catas: 1822 | Temp fix for z bit set in unf_sub 1823 movel USER_FPSR(%a6),-(%a7) 1824 1825 movel #2,%d0 |set round precision to dbl 1826 bsrl unf_sub |a0 points to result 1827 1828 movel (%a7)+,USER_FPSR(%a6) 1829 1830 movel #1,%d0 1831 subw %d0,LOCAL_EX(%a0) |account for difference between 1832 | ;denorm/norm bias 1833 1834 movel %a0,%a1 |a1 has the operand input 1835 movel EXC_EA(%a6),%a0 |a0 has the destination pointer 1836 1837 bsrl dest_dbl |store the result 1838 oril #unfinx_mask,USER_FPSR(%a6) 1839 bra mvout_end 1840 1841 | 1842 | Handle catastrophic overflow cases here 1843 | 1844 sp_over: 1845 | Temp fix for z bit set in unf_sub 1846 movel USER_FPSR(%a6),-(%a7) 1847 1848 movel #1,%d0 1849 leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating result 1850 movel ETEMP_EX(%a6),(%a0) 1851 movel ETEMP_HI(%a6),4(%a0) 1852 movel ETEMP_LO(%a6),8(%a0) 1853 bsrl ovf_res 1854 1855 movel (%a7)+,USER_FPSR(%a6) 1856 1857 movel %a0,%a1 1858 movel EXC_EA(%a6),%a0 1859 bsrl dest_sgl 1860 orl #ovfinx_mask,USER_FPSR(%a6) 1861 bra mvout_end 1862 1863 dp_over: 1864 | Temp fix for z bit set in ovf_res 1865 movel USER_FPSR(%a6),-(%a7) 1866 1867 movel #2,%d0 1868 leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating result 1869 movel ETEMP_EX(%a6),(%a0) 1870 movel ETEMP_HI(%a6),4(%a0) 1871 movel ETEMP_LO(%a6),8(%a0) 1872 bsrl ovf_res 1873 1874 movel (%a7)+,USER_FPSR(%a6) 1875 1876 movel %a0,%a1 1877 movel EXC_EA(%a6),%a0 1878 bsrl dest_dbl 1879 orl #ovfinx_mask,USER_FPSR(%a6) 1880 bra mvout_end 1881 1882 | 1883 | DPSPDNRM 1884 | 1885 | This subroutine takes an extended normalized number and denormalizes 1886 | it to the given round precision. This subroutine also decrements 1887 | the input operand's exponent by 1 to account for the fact that 1888 | dest_sgl or dest_dbl expects a normalized number's bias. 1889 | 1890 | Input: a0 points to a normalized number in internal extended format 1891 | d0 is the round precision (=1 for sgl; =2 for dbl) 1892 | d1 is the the single precision or double precision 1893 | denorm threshold 1894 | 1895 | Output: (In the format for dest_sgl or dest_dbl) 1896 | a0 points to the destination 1897 | a1 points to the operand 1898 | 1899 | Exceptions: Reports inexact 2 exception by setting USER_FPSR bits 1900 | 1901 dpspdnrm: 1902 movel %d0,-(%a7) |save round precision 1903 clrl %d0 |clear initial g,r,s 1904 bsrl dnrm_lp |careful with d0, it's needed by round 1905 1906 bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rounding mode 1907 swap %d1 1908 movew 2(%a7),%d1 |set rounding precision 1909 swap %d1 |at this point d1 has PREC/MODE info 1910 bsrl round |round result, sets the inex bit in 1911 | ;USER_FPSR if needed 1912 1913 movew #1,%d0 1914 subw %d0,LOCAL_EX(%a0) |account for difference in denorm 1915 | ;vs norm bias 1916 1917 movel %a0,%a1 |a1 has the operand input 1918 movel EXC_EA(%a6),%a0 |a0 has the destination pointer 1919 addw #4,%a7 |pop stack 1920 rts 1921 | 1922 | SET_XOP initialized WBTEMP with the value pointed to by a0 1923 | input: a0 points to input operand in the internal extended format 1924 | 1925 set_xop: 1926 movel LOCAL_EX(%a0),WBTEMP_EX(%a6) 1927 movel LOCAL_HI(%a0),WBTEMP_HI(%a6) 1928 movel LOCAL_LO(%a0),WBTEMP_LO(%a6) 1929 bfclr WBTEMP_SGN(%a6){#0:#8} 1930 beqs sxop 1931 bsetb #sign_bit,WBTEMP_EX(%a6) 1932 sxop: 1933 bfclr STAG(%a6){#5:#4} |clear wbtm66,wbtm1,wbtm0,sbit 1934 rts 1935 | 1936 | P_MOVE 1937 | 1938 p_movet: 1939 .long p_move 1940 .long p_movez 1941 .long p_movei 1942 .long p_moven 1943 .long p_move 1944 p_regd: 1945 .long p_dyd0 1946 .long p_dyd1 1947 .long p_dyd2 1948 .long p_dyd3 1949 .long p_dyd4 1950 .long p_dyd5 1951 .long p_dyd6 1952 .long p_dyd7 1953 1954 pack_out: 1955 leal p_movet,%a0 |load jmp table address 1956 movew STAG(%a6),%d0 |get source tag 1957 bfextu %d0{#16:#3},%d0 |isolate source bits 1958 movel (%a0,%d0.w*4),%a0 |load a0 with routine label for tag 1959 jmp (%a0) |go to the routine 1960 1961 p_write: 1962 movel #0x0c,%d0 |get byte count 1963 movel EXC_EA(%a6),%a1 |get the destination address 1964 bsr mem_write |write the user's destination 1965 moveb #0,CU_SAVEPC(%a6) |set the cu save pc to all 0's 1966 1967 | 1968 | Also note that the dtag must be set to norm here - this is because 1969 | the 040 uses the dtag to execute the correct microcode. 1970 | 1971 bfclr DTAG(%a6){#0:#3} |set dtag to norm 1972 1973 rts 1974 1975 | Notes on handling of special case (zero, inf, and nan) inputs: 1976 | 1. Operr is not signalled if the k-factor is greater than 18. 1977 | 2. Per the manual, status bits are not set. 1978 | 1979 1980 p_move: 1981 movew CMDREG1B(%a6),%d0 1982 btstl #kfact_bit,%d0 |test for dynamic k-factor 1983 beqs statick |if clear, k-factor is static 1984 dynamick: 1985 bfextu %d0{#25:#3},%d0 |isolate register for dynamic k-factor 1986 lea p_regd,%a0 1987 movel %a0@(%d0:l:4),%a0 1988 jmp (%a0) 1989 statick: 1990 andiw #0x007f,%d0 |get k-factor 1991 bfexts %d0{#25:#7},%d0 |sign extend d0 for bindec 1992 leal ETEMP(%a6),%a0 |a0 will point to the packed decimal 1993 bsrl bindec |perform the convert; data at a6 1994 leal FP_SCR1(%a6),%a0 |load a0 with result address 1995 bral p_write 1996 p_movez: 1997 leal ETEMP(%a6),%a0 |a0 will point to the packed decimal 1998 clrw 2(%a0) |clear lower word of exp 1999 clrl 4(%a0) |load second lword of ZERO 2000 clrl 8(%a0) |load third lword of ZERO 2001 bra p_write |go write results 2002 p_movei: 2003 fmovel #0,%FPSR |clear aiop 2004 leal ETEMP(%a6),%a0 |a0 will point to the packed decimal 2005 clrw 2(%a0) |clear lower word of exp 2006 bra p_write |go write the result 2007 p_moven: 2008 leal ETEMP(%a6),%a0 |a0 will point to the packed decimal 2009 clrw 2(%a0) |clear lower word of exp 2010 bra p_write |go write the result 2011 2012 | 2013 | Routines to read the dynamic k-factor from Dn. 2014 | 2015 p_dyd0: 2016 movel USER_D0(%a6),%d0 2017 bras statick 2018 p_dyd1: 2019 movel USER_D1(%a6),%d0 2020 bras statick 2021 p_dyd2: 2022 movel %d2,%d0 2023 bras statick 2024 p_dyd3: 2025 movel %d3,%d0 2026 bras statick 2027 p_dyd4: 2028 movel %d4,%d0 2029 bras statick 2030 p_dyd5: 2031 movel %d5,%d0 2032 bras statick 2033 p_dyd6: 2034 movel %d6,%d0 2035 bra statick 2036 p_dyd7: 2037 movel %d7,%d0 2038 bra statick 2039 2040 |end