root/arch/m68k/fpsp040/res_func.S

/* [previous][next][first][last][top][bottom][index][help] */
   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

/* [previous][next][first][last][top][bottom][index][help] */