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