root/arch/m68k/fpsp040/res_func.S

/* [<][>][^][v][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 |       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

/* [<][>][^][v][top][bottom][index][help] */