linux/arch/m68k/ifpsp060/src/fpsp.S
<<
>>
Prefs
   1~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   2MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
   3M68000 Hi-Performance Microprocessor Division
   4M68060 Software Package
   5Production Release P1.00 -- October 10, 1994
   6
   7M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.
   8
   9THE SOFTWARE is provided on an "AS IS" basis and without warranty.
  10To the maximum extent permitted by applicable law,
  11MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
  12INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
  13and any warranty against infringement with regard to the SOFTWARE
  14(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
  15
  16To the maximum extent permitted by applicable law,
  17IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
  18(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
  19BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
  20ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
  21Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
  22
  23You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
  24so long as this entire notice is retained without alteration in any modified and/or
  25redistributed versions, and that such modified versions are clearly identified as such.
  26No licenses are granted by implication, estoppel or otherwise under any patents
  27or trademarks of Motorola, Inc.
  28~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  29#
  30# freal.s:
  31#       This file is appended to the top of the 060FPSP package
  32# and contains the entry points into the package. The user, in
  33# effect, branches to one of the branch table entries located
  34# after _060FPSP_TABLE.
  35#       Also, subroutine stubs exist in this file (_fpsp_done for
  36# example) that are referenced by the FPSP package itself in order
  37# to call a given routine. The stub routine actually performs the
  38# callout. The FPSP code does a "bsr" to the stub routine. This
  39# extra layer of hierarchy adds a slight performance penalty but
  40# it makes the FPSP code easier to read and more mainatinable.
  41#
  42
  43set     _off_bsun,      0x00
  44set     _off_snan,      0x04
  45set     _off_operr,     0x08
  46set     _off_ovfl,      0x0c
  47set     _off_unfl,      0x10
  48set     _off_dz,        0x14
  49set     _off_inex,      0x18
  50set     _off_fline,     0x1c
  51set     _off_fpu_dis,   0x20
  52set     _off_trap,      0x24
  53set     _off_trace,     0x28
  54set     _off_access,    0x2c
  55set     _off_done,      0x30
  56
  57set     _off_imr,       0x40
  58set     _off_dmr,       0x44
  59set     _off_dmw,       0x48
  60set     _off_irw,       0x4c
  61set     _off_irl,       0x50
  62set     _off_drb,       0x54
  63set     _off_drw,       0x58
  64set     _off_drl,       0x5c
  65set     _off_dwb,       0x60
  66set     _off_dww,       0x64
  67set     _off_dwl,       0x68
  68
  69_060FPSP_TABLE:
  70
  71###############################################################
  72
  73# Here's the table of ENTRY POINTS for those linking the package.
  74        bra.l           _fpsp_snan
  75        short           0x0000
  76        bra.l           _fpsp_operr
  77        short           0x0000
  78        bra.l           _fpsp_ovfl
  79        short           0x0000
  80        bra.l           _fpsp_unfl
  81        short           0x0000
  82        bra.l           _fpsp_dz
  83        short           0x0000
  84        bra.l           _fpsp_inex
  85        short           0x0000
  86        bra.l           _fpsp_fline
  87        short           0x0000
  88        bra.l           _fpsp_unsupp
  89        short           0x0000
  90        bra.l           _fpsp_effadd
  91        short           0x0000
  92
  93        space           56
  94
  95###############################################################
  96        global          _fpsp_done
  97_fpsp_done:
  98        mov.l           %d0,-(%sp)
  99        mov.l           (_060FPSP_TABLE-0x80+_off_done,%pc),%d0
 100        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 101        mov.l           0x4(%sp),%d0
 102        rtd             &0x4
 103
 104        global          _real_ovfl
 105_real_ovfl:
 106        mov.l           %d0,-(%sp)
 107        mov.l           (_060FPSP_TABLE-0x80+_off_ovfl,%pc),%d0
 108        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 109        mov.l           0x4(%sp),%d0
 110        rtd             &0x4
 111
 112        global          _real_unfl
 113_real_unfl:
 114        mov.l           %d0,-(%sp)
 115        mov.l           (_060FPSP_TABLE-0x80+_off_unfl,%pc),%d0
 116        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 117        mov.l           0x4(%sp),%d0
 118        rtd             &0x4
 119
 120        global          _real_inex
 121_real_inex:
 122        mov.l           %d0,-(%sp)
 123        mov.l           (_060FPSP_TABLE-0x80+_off_inex,%pc),%d0
 124        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 125        mov.l           0x4(%sp),%d0
 126        rtd             &0x4
 127
 128        global          _real_bsun
 129_real_bsun:
 130        mov.l           %d0,-(%sp)
 131        mov.l           (_060FPSP_TABLE-0x80+_off_bsun,%pc),%d0
 132        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 133        mov.l           0x4(%sp),%d0
 134        rtd             &0x4
 135
 136        global          _real_operr
 137_real_operr:
 138        mov.l           %d0,-(%sp)
 139        mov.l           (_060FPSP_TABLE-0x80+_off_operr,%pc),%d0
 140        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 141        mov.l           0x4(%sp),%d0
 142        rtd             &0x4
 143
 144        global          _real_snan
 145_real_snan:
 146        mov.l           %d0,-(%sp)
 147        mov.l           (_060FPSP_TABLE-0x80+_off_snan,%pc),%d0
 148        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 149        mov.l           0x4(%sp),%d0
 150        rtd             &0x4
 151
 152        global          _real_dz
 153_real_dz:
 154        mov.l           %d0,-(%sp)
 155        mov.l           (_060FPSP_TABLE-0x80+_off_dz,%pc),%d0
 156        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 157        mov.l           0x4(%sp),%d0
 158        rtd             &0x4
 159
 160        global          _real_fline
 161_real_fline:
 162        mov.l           %d0,-(%sp)
 163        mov.l           (_060FPSP_TABLE-0x80+_off_fline,%pc),%d0
 164        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 165        mov.l           0x4(%sp),%d0
 166        rtd             &0x4
 167
 168        global          _real_fpu_disabled
 169_real_fpu_disabled:
 170        mov.l           %d0,-(%sp)
 171        mov.l           (_060FPSP_TABLE-0x80+_off_fpu_dis,%pc),%d0
 172        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 173        mov.l           0x4(%sp),%d0
 174        rtd             &0x4
 175
 176        global          _real_trap
 177_real_trap:
 178        mov.l           %d0,-(%sp)
 179        mov.l           (_060FPSP_TABLE-0x80+_off_trap,%pc),%d0
 180        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 181        mov.l           0x4(%sp),%d0
 182        rtd             &0x4
 183
 184        global          _real_trace
 185_real_trace:
 186        mov.l           %d0,-(%sp)
 187        mov.l           (_060FPSP_TABLE-0x80+_off_trace,%pc),%d0
 188        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 189        mov.l           0x4(%sp),%d0
 190        rtd             &0x4
 191
 192        global          _real_access
 193_real_access:
 194        mov.l           %d0,-(%sp)
 195        mov.l           (_060FPSP_TABLE-0x80+_off_access,%pc),%d0
 196        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 197        mov.l           0x4(%sp),%d0
 198        rtd             &0x4
 199
 200#######################################
 201
 202        global          _imem_read
 203_imem_read:
 204        mov.l           %d0,-(%sp)
 205        mov.l           (_060FPSP_TABLE-0x80+_off_imr,%pc),%d0
 206        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 207        mov.l           0x4(%sp),%d0
 208        rtd             &0x4
 209
 210        global          _dmem_read
 211_dmem_read:
 212        mov.l           %d0,-(%sp)
 213        mov.l           (_060FPSP_TABLE-0x80+_off_dmr,%pc),%d0
 214        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 215        mov.l           0x4(%sp),%d0
 216        rtd             &0x4
 217
 218        global          _dmem_write
 219_dmem_write:
 220        mov.l           %d0,-(%sp)
 221        mov.l           (_060FPSP_TABLE-0x80+_off_dmw,%pc),%d0
 222        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 223        mov.l           0x4(%sp),%d0
 224        rtd             &0x4
 225
 226        global          _imem_read_word
 227_imem_read_word:
 228        mov.l           %d0,-(%sp)
 229        mov.l           (_060FPSP_TABLE-0x80+_off_irw,%pc),%d0
 230        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 231        mov.l           0x4(%sp),%d0
 232        rtd             &0x4
 233
 234        global          _imem_read_long
 235_imem_read_long:
 236        mov.l           %d0,-(%sp)
 237        mov.l           (_060FPSP_TABLE-0x80+_off_irl,%pc),%d0
 238        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 239        mov.l           0x4(%sp),%d0
 240        rtd             &0x4
 241
 242        global          _dmem_read_byte
 243_dmem_read_byte:
 244        mov.l           %d0,-(%sp)
 245        mov.l           (_060FPSP_TABLE-0x80+_off_drb,%pc),%d0
 246        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 247        mov.l           0x4(%sp),%d0
 248        rtd             &0x4
 249
 250        global          _dmem_read_word
 251_dmem_read_word:
 252        mov.l           %d0,-(%sp)
 253        mov.l           (_060FPSP_TABLE-0x80+_off_drw,%pc),%d0
 254        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 255        mov.l           0x4(%sp),%d0
 256        rtd             &0x4
 257
 258        global          _dmem_read_long
 259_dmem_read_long:
 260        mov.l           %d0,-(%sp)
 261        mov.l           (_060FPSP_TABLE-0x80+_off_drl,%pc),%d0
 262        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 263        mov.l           0x4(%sp),%d0
 264        rtd             &0x4
 265
 266        global          _dmem_write_byte
 267_dmem_write_byte:
 268        mov.l           %d0,-(%sp)
 269        mov.l           (_060FPSP_TABLE-0x80+_off_dwb,%pc),%d0
 270        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 271        mov.l           0x4(%sp),%d0
 272        rtd             &0x4
 273
 274        global          _dmem_write_word
 275_dmem_write_word:
 276        mov.l           %d0,-(%sp)
 277        mov.l           (_060FPSP_TABLE-0x80+_off_dww,%pc),%d0
 278        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 279        mov.l           0x4(%sp),%d0
 280        rtd             &0x4
 281
 282        global          _dmem_write_long
 283_dmem_write_long:
 284        mov.l           %d0,-(%sp)
 285        mov.l           (_060FPSP_TABLE-0x80+_off_dwl,%pc),%d0
 286        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 287        mov.l           0x4(%sp),%d0
 288        rtd             &0x4
 289
 290#
 291# This file contains a set of define statements for constants
 292# in order to promote readability within the corecode itself.
 293#
 294
 295set LOCAL_SIZE,         192                     # stack frame size(bytes)
 296set LV,                 -LOCAL_SIZE             # stack offset
 297
 298set EXC_SR,             0x4                     # stack status register
 299set EXC_PC,             0x6                     # stack pc
 300set EXC_VOFF,           0xa                     # stacked vector offset
 301set EXC_EA,             0xc                     # stacked <ea>
 302
 303set EXC_FP,             0x0                     # frame pointer
 304
 305set EXC_AREGS,          -68                     # offset of all address regs
 306set EXC_DREGS,          -100                    # offset of all data regs
 307set EXC_FPREGS,         -36                     # offset of all fp regs
 308
 309set EXC_A7,             EXC_AREGS+(7*4)         # offset of saved a7
 310set OLD_A7,             EXC_AREGS+(6*4)         # extra copy of saved a7
 311set EXC_A6,             EXC_AREGS+(6*4)         # offset of saved a6
 312set EXC_A5,             EXC_AREGS+(5*4)
 313set EXC_A4,             EXC_AREGS+(4*4)
 314set EXC_A3,             EXC_AREGS+(3*4)
 315set EXC_A2,             EXC_AREGS+(2*4)
 316set EXC_A1,             EXC_AREGS+(1*4)
 317set EXC_A0,             EXC_AREGS+(0*4)
 318set EXC_D7,             EXC_DREGS+(7*4)
 319set EXC_D6,             EXC_DREGS+(6*4)
 320set EXC_D5,             EXC_DREGS+(5*4)
 321set EXC_D4,             EXC_DREGS+(4*4)
 322set EXC_D3,             EXC_DREGS+(3*4)
 323set EXC_D2,             EXC_DREGS+(2*4)
 324set EXC_D1,             EXC_DREGS+(1*4)
 325set EXC_D0,             EXC_DREGS+(0*4)
 326
 327set EXC_FP0,            EXC_FPREGS+(0*12)       # offset of saved fp0
 328set EXC_FP1,            EXC_FPREGS+(1*12)       # offset of saved fp1
 329set EXC_FP2,            EXC_FPREGS+(2*12)       # offset of saved fp2 (not used)
 330
 331set FP_SCR1,            LV+80                   # fp scratch 1
 332set FP_SCR1_EX,         FP_SCR1+0
 333set FP_SCR1_SGN,        FP_SCR1+2
 334set FP_SCR1_HI,         FP_SCR1+4
 335set FP_SCR1_LO,         FP_SCR1+8
 336
 337set FP_SCR0,            LV+68                   # fp scratch 0
 338set FP_SCR0_EX,         FP_SCR0+0
 339set FP_SCR0_SGN,        FP_SCR0+2
 340set FP_SCR0_HI,         FP_SCR0+4
 341set FP_SCR0_LO,         FP_SCR0+8
 342
 343set FP_DST,             LV+56                   # fp destination operand
 344set FP_DST_EX,          FP_DST+0
 345set FP_DST_SGN,         FP_DST+2
 346set FP_DST_HI,          FP_DST+4
 347set FP_DST_LO,          FP_DST+8
 348
 349set FP_SRC,             LV+44                   # fp source operand
 350set FP_SRC_EX,          FP_SRC+0
 351set FP_SRC_SGN,         FP_SRC+2
 352set FP_SRC_HI,          FP_SRC+4
 353set FP_SRC_LO,          FP_SRC+8
 354
 355set USER_FPIAR,         LV+40                   # FP instr address register
 356
 357set USER_FPSR,          LV+36                   # FP status register
 358set FPSR_CC,            USER_FPSR+0             # FPSR condition codes
 359set FPSR_QBYTE,         USER_FPSR+1             # FPSR qoutient byte
 360set FPSR_EXCEPT,        USER_FPSR+2             # FPSR exception status byte
 361set FPSR_AEXCEPT,       USER_FPSR+3             # FPSR accrued exception byte
 362
 363set USER_FPCR,          LV+32                   # FP control register
 364set FPCR_ENABLE,        USER_FPCR+2             # FPCR exception enable
 365set FPCR_MODE,          USER_FPCR+3             # FPCR rounding mode control
 366
 367set L_SCR3,             LV+28                   # integer scratch 3
 368set L_SCR2,             LV+24                   # integer scratch 2
 369set L_SCR1,             LV+20                   # integer scratch 1
 370
 371set STORE_FLG,          LV+19                   # flag: operand store (ie. not fcmp/ftst)
 372
 373set EXC_TEMP2,          LV+24                   # temporary space
 374set EXC_TEMP,           LV+16                   # temporary space
 375
 376set DTAG,               LV+15                   # destination operand type
 377set STAG,               LV+14                   # source operand type
 378
 379set SPCOND_FLG,         LV+10                   # flag: special case (see below)
 380
 381set EXC_CC,             LV+8                    # saved condition codes
 382set EXC_EXTWPTR,        LV+4                    # saved current PC (active)
 383set EXC_EXTWORD,        LV+2                    # saved extension word
 384set EXC_CMDREG,         LV+2                    # saved extension word
 385set EXC_OPWORD,         LV+0                    # saved operation word
 386
 387################################
 388
 389# Helpful macros
 390
 391set FTEMP,              0                       # offsets within an
 392set FTEMP_EX,           0                       # extended precision
 393set FTEMP_SGN,          2                       # value saved in memory.
 394set FTEMP_HI,           4
 395set FTEMP_LO,           8
 396set FTEMP_GRS,          12
 397
 398set LOCAL,              0                       # offsets within an
 399set LOCAL_EX,           0                       # extended precision
 400set LOCAL_SGN,          2                       # value saved in memory.
 401set LOCAL_HI,           4
 402set LOCAL_LO,           8
 403set LOCAL_GRS,          12
 404
 405set DST,                0                       # offsets within an
 406set DST_EX,             0                       # extended precision
 407set DST_HI,             4                       # value saved in memory.
 408set DST_LO,             8
 409
 410set SRC,                0                       # offsets within an
 411set SRC_EX,             0                       # extended precision
 412set SRC_HI,             4                       # value saved in memory.
 413set SRC_LO,             8
 414
 415set SGL_LO,             0x3f81                  # min sgl prec exponent
 416set SGL_HI,             0x407e                  # max sgl prec exponent
 417set DBL_LO,             0x3c01                  # min dbl prec exponent
 418set DBL_HI,             0x43fe                  # max dbl prec exponent
 419set EXT_LO,             0x0                     # min ext prec exponent
 420set EXT_HI,             0x7ffe                  # max ext prec exponent
 421
 422set EXT_BIAS,           0x3fff                  # extended precision bias
 423set SGL_BIAS,           0x007f                  # single precision bias
 424set DBL_BIAS,           0x03ff                  # double precision bias
 425
 426set NORM,               0x00                    # operand type for STAG/DTAG
 427set ZERO,               0x01                    # operand type for STAG/DTAG
 428set INF,                0x02                    # operand type for STAG/DTAG
 429set QNAN,               0x03                    # operand type for STAG/DTAG
 430set DENORM,             0x04                    # operand type for STAG/DTAG
 431set SNAN,               0x05                    # operand type for STAG/DTAG
 432set UNNORM,             0x06                    # operand type for STAG/DTAG
 433
 434##################
 435# FPSR/FPCR bits #
 436##################
 437set neg_bit,            0x3                     # negative result
 438set z_bit,              0x2                     # zero result
 439set inf_bit,            0x1                     # infinite result
 440set nan_bit,            0x0                     # NAN result
 441
 442set q_sn_bit,           0x7                     # sign bit of quotient byte
 443
 444set bsun_bit,           7                       # branch on unordered
 445set snan_bit,           6                       # signalling NAN
 446set operr_bit,          5                       # operand error
 447set ovfl_bit,           4                       # overflow
 448set unfl_bit,           3                       # underflow
 449set dz_bit,             2                       # divide by zero
 450set inex2_bit,          1                       # inexact result 2
 451set inex1_bit,          0                       # inexact result 1
 452
 453set aiop_bit,           7                       # accrued inexact operation bit
 454set aovfl_bit,          6                       # accrued overflow bit
 455set aunfl_bit,          5                       # accrued underflow bit
 456set adz_bit,            4                       # accrued dz bit
 457set ainex_bit,          3                       # accrued inexact bit
 458
 459#############################
 460# FPSR individual bit masks #
 461#############################
 462set neg_mask,           0x08000000              # negative bit mask (lw)
 463set inf_mask,           0x02000000              # infinity bit mask (lw)
 464set z_mask,             0x04000000              # zero bit mask (lw)
 465set nan_mask,           0x01000000              # nan bit mask (lw)
 466
 467set neg_bmask,          0x08                    # negative bit mask (byte)
 468set inf_bmask,          0x02                    # infinity bit mask (byte)
 469set z_bmask,            0x04                    # zero bit mask (byte)
 470set nan_bmask,          0x01                    # nan bit mask (byte)
 471
 472set bsun_mask,          0x00008000              # bsun exception mask
 473set snan_mask,          0x00004000              # snan exception mask
 474set operr_mask,         0x00002000              # operr exception mask
 475set ovfl_mask,          0x00001000              # overflow exception mask
 476set unfl_mask,          0x00000800              # underflow exception mask
 477set dz_mask,            0x00000400              # dz exception mask
 478set inex2_mask,         0x00000200              # inex2 exception mask
 479set inex1_mask,         0x00000100              # inex1 exception mask
 480
 481set aiop_mask,          0x00000080              # accrued illegal operation
 482set aovfl_mask,         0x00000040              # accrued overflow
 483set aunfl_mask,         0x00000020              # accrued underflow
 484set adz_mask,           0x00000010              # accrued divide by zero
 485set ainex_mask,         0x00000008              # accrued inexact
 486
 487######################################
 488# FPSR combinations used in the FPSP #
 489######################################
 490set dzinf_mask,         inf_mask+dz_mask+adz_mask
 491set opnan_mask,         nan_mask+operr_mask+aiop_mask
 492set nzi_mask,           0x01ffffff              #clears N, Z, and I
 493set unfinx_mask,        unfl_mask+inex2_mask+aunfl_mask+ainex_mask
 494set unf2inx_mask,       unfl_mask+inex2_mask+ainex_mask
 495set ovfinx_mask,        ovfl_mask+inex2_mask+aovfl_mask+ainex_mask
 496set inx1a_mask,         inex1_mask+ainex_mask
 497set inx2a_mask,         inex2_mask+ainex_mask
 498set snaniop_mask,       nan_mask+snan_mask+aiop_mask
 499set snaniop2_mask,      snan_mask+aiop_mask
 500set naniop_mask,        nan_mask+aiop_mask
 501set neginf_mask,        neg_mask+inf_mask
 502set infaiop_mask,       inf_mask+aiop_mask
 503set negz_mask,          neg_mask+z_mask
 504set opaop_mask,         operr_mask+aiop_mask
 505set unfl_inx_mask,      unfl_mask+aunfl_mask+ainex_mask
 506set ovfl_inx_mask,      ovfl_mask+aovfl_mask+ainex_mask
 507
 508#########
 509# misc. #
 510#########
 511set rnd_stky_bit,       29                      # stky bit pos in longword
 512
 513set sign_bit,           0x7                     # sign bit
 514set signan_bit,         0x6                     # signalling nan bit
 515
 516set sgl_thresh,         0x3f81                  # minimum sgl exponent
 517set dbl_thresh,         0x3c01                  # minimum dbl exponent
 518
 519set x_mode,             0x0                     # extended precision
 520set s_mode,             0x4                     # single precision
 521set d_mode,             0x8                     # double precision
 522
 523set rn_mode,            0x0                     # round-to-nearest
 524set rz_mode,            0x1                     # round-to-zero
 525set rm_mode,            0x2                     # round-tp-minus-infinity
 526set rp_mode,            0x3                     # round-to-plus-infinity
 527
 528set mantissalen,        64                      # length of mantissa in bits
 529
 530set BYTE,               1                       # len(byte) == 1 byte
 531set WORD,               2                       # len(word) == 2 bytes
 532set LONG,               4                       # len(longword) == 2 bytes
 533
 534set BSUN_VEC,           0xc0                    # bsun    vector offset
 535set INEX_VEC,           0xc4                    # inexact vector offset
 536set DZ_VEC,             0xc8                    # dz      vector offset
 537set UNFL_VEC,           0xcc                    # unfl    vector offset
 538set OPERR_VEC,          0xd0                    # operr   vector offset
 539set OVFL_VEC,           0xd4                    # ovfl    vector offset
 540set SNAN_VEC,           0xd8                    # snan    vector offset
 541
 542###########################
 543# SPecial CONDition FLaGs #
 544###########################
 545set ftrapcc_flg,        0x01                    # flag bit: ftrapcc exception
 546set fbsun_flg,          0x02                    # flag bit: bsun exception
 547set mia7_flg,           0x04                    # flag bit: (a7)+ <ea>
 548set mda7_flg,           0x08                    # flag bit: -(a7) <ea>
 549set fmovm_flg,          0x40                    # flag bit: fmovm instruction
 550set immed_flg,          0x80                    # flag bit: &<data> <ea>
 551
 552set ftrapcc_bit,        0x0
 553set fbsun_bit,          0x1
 554set mia7_bit,           0x2
 555set mda7_bit,           0x3
 556set immed_bit,          0x7
 557
 558##################################
 559# TRANSCENDENTAL "LAST-OP" FLAGS #
 560##################################
 561set FMUL_OP,            0x0                     # fmul instr performed last
 562set FDIV_OP,            0x1                     # fdiv performed last
 563set FADD_OP,            0x2                     # fadd performed last
 564set FMOV_OP,            0x3                     # fmov performed last
 565
 566#############
 567# CONSTANTS #
 568#############
 569T1:     long            0x40C62D38,0xD3D64634   # 16381 LOG2 LEAD
 570T2:     long            0x3D6F90AE,0xB1E75CC7   # 16381 LOG2 TRAIL
 571
 572PI:     long            0x40000000,0xC90FDAA2,0x2168C235,0x00000000
 573PIBY2:  long            0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000
 574
 575TWOBYPI:
 576        long            0x3FE45F30,0x6DC9C883
 577
 578#########################################################################
 579# XDEF **************************************************************** #
 580#       _fpsp_ovfl(): 060FPSP entry point for FP Overflow exception.    #
 581#                                                                       #
 582#       This handler should be the first code executed upon taking the  #
 583#       FP Overflow exception in an operating system.                   #
 584#                                                                       #
 585# XREF **************************************************************** #
 586#       _imem_read_long() - read instruction longword                   #
 587#       fix_skewed_ops() - adjust src operand in fsave frame            #
 588#       set_tag_x() - determine optype of src/dst operands              #
 589#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
 590#       unnorm_fix() - change UNNORM operands to NORM or ZERO           #
 591#       load_fpn2() - load dst operand from FP regfile                  #
 592#       fout() - emulate an opclass 3 instruction                       #
 593#       tbl_unsupp - add of table of emulation routines for opclass 0,2 #
 594#       _fpsp_done() - "callout" for 060FPSP exit (all work done!)      #
 595#       _real_ovfl() - "callout" for Overflow exception enabled code    #
 596#       _real_inex() - "callout" for Inexact exception enabled code     #
 597#       _real_trace() - "callout" for Trace exception code              #
 598#                                                                       #
 599# INPUT *************************************************************** #
 600#       - The system stack contains the FP Ovfl exception stack frame   #
 601#       - The fsave frame contains the source operand                   #
 602#                                                                       #
 603# OUTPUT ************************************************************** #
 604#       Overflow Exception enabled:                                     #
 605#       - The system stack is unchanged                                 #
 606#       - The fsave frame contains the adjusted src op for opclass 0,2  #
 607#       Overflow Exception disabled:                                    #
 608#       - The system stack is unchanged                                 #
 609#       - The "exception present" flag in the fsave frame is cleared    #
 610#                                                                       #
 611# ALGORITHM *********************************************************** #
 612#       On the 060, if an FP overflow is present as the result of any   #
 613# instruction, the 060 will take an overflow exception whether the      #
 614# exception is enabled or disabled in the FPCR. For the disabled case,  #
 615# This handler emulates the instruction to determine what the correct   #
 616# default result should be for the operation. This default result is    #
 617# then stored in either the FP regfile, data regfile, or memory.        #
 618# Finally, the handler exits through the "callout" _fpsp_done()         #
 619# denoting that no exceptional conditions exist within the machine.     #
 620#       If the exception is enabled, then this handler must create the  #
 621# exceptional operand and plave it in the fsave state frame, and store  #
 622# the default result (only if the instruction is opclass 3). For        #
 623# exceptions enabled, this handler must exit through the "callout"      #
 624# _real_ovfl() so that the operating system enabled overflow handler    #
 625# can handle this case.                                                 #
 626#       Two other conditions exist. First, if overflow was disabled     #
 627# but the inexact exception was enabled, this handler must exit         #
 628# through the "callout" _real_inex() regardless of whether the result   #
 629# was inexact.                                                          #
 630#       Also, in the case of an opclass three instruction where         #
 631# overflow was disabled and the trace exception was enabled, this       #
 632# handler must exit through the "callout" _real_trace().                #
 633#                                                                       #
 634#########################################################################
 635
 636        global          _fpsp_ovfl
 637_fpsp_ovfl:
 638
 639#$#     sub.l           &24,%sp                 # make room for src/dst
 640
 641        link.w          %a6,&-LOCAL_SIZE        # init stack frame
 642
 643        fsave           FP_SRC(%a6)             # grab the "busy" frame
 644
 645        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
 646        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
 647        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
 648
 649# the FPIAR holds the "current PC" of the faulting instruction
 650        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
 651        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
 652        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
 653        bsr.l           _imem_read_long         # fetch the instruction words
 654        mov.l           %d0,EXC_OPWORD(%a6)
 655
 656##############################################################################
 657
 658        btst            &0x5,EXC_CMDREG(%a6)    # is instr an fmove out?
 659        bne.w           fovfl_out
 660
 661
 662        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
 663        bsr.l           fix_skewed_ops          # fix src op
 664
 665# since, I believe, only NORMs and DENORMs can come through here,
 666# maybe we can avoid the subroutine call.
 667        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
 668        bsr.l           set_tag_x               # tag the operand type
 669        mov.b           %d0,STAG(%a6)           # maybe NORM,DENORM
 670
 671# bit five of the fp extension word separates the monadic and dyadic operations
 672# that can pass through fpsp_ovfl(). remember that fcmp, ftst, and fsincos
 673# will never take this exception.
 674        btst            &0x5,1+EXC_CMDREG(%a6)  # is operation monadic or dyadic?
 675        beq.b           fovfl_extract           # monadic
 676
 677        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
 678        bsr.l           load_fpn2               # load dst into FP_DST
 679
 680        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
 681        bsr.l           set_tag_x               # tag the operand type
 682        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
 683        bne.b           fovfl_op2_done          # no
 684        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
 685fovfl_op2_done:
 686        mov.b           %d0,DTAG(%a6)           # save dst optype tag
 687
 688fovfl_extract:
 689
 690#$#     mov.l           FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
 691#$#     mov.l           FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
 692#$#     mov.l           FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
 693#$#     mov.l           FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6)
 694#$#     mov.l           FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6)
 695#$#     mov.l           FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6)
 696
 697        clr.l           %d0
 698        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec/mode
 699
 700        mov.b           1+EXC_CMDREG(%a6),%d1
 701        andi.w          &0x007f,%d1             # extract extension
 702
 703        andi.l          &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field
 704
 705        fmov.l          &0x0,%fpcr              # zero current control regs
 706        fmov.l          &0x0,%fpsr
 707
 708        lea             FP_SRC(%a6),%a0
 709        lea             FP_DST(%a6),%a1
 710
 711# maybe we can make these entry points ONLY the OVFL entry points of each routine.
 712        mov.l           (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
 713        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
 714
 715# the operation has been emulated. the result is in fp0.
 716# the EXOP, if an exception occurred, is in fp1.
 717# we must save the default result regardless of whether
 718# traps are enabled or disabled.
 719        bfextu          EXC_CMDREG(%a6){&6:&3},%d0
 720        bsr.l           store_fpreg
 721
 722# the exceptional possibilities we have left ourselves with are ONLY overflow
 723# and inexact. and, the inexact is such that overflow occurred and was disabled
 724# but inexact was enabled.
 725        btst            &ovfl_bit,FPCR_ENABLE(%a6)
 726        bne.b           fovfl_ovfl_on
 727
 728        btst            &inex2_bit,FPCR_ENABLE(%a6)
 729        bne.b           fovfl_inex_on
 730
 731        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
 732        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 733        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
 734
 735        unlk            %a6
 736#$#     add.l           &24,%sp
 737        bra.l           _fpsp_done
 738
 739# overflow is enabled AND overflow, of course, occurred. so, we have the EXOP
 740# in fp1. now, simply jump to _real_ovfl()!
 741fovfl_ovfl_on:
 742        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP (fp1) to stack
 743
 744        mov.w           &0xe005,2+FP_SRC(%a6)   # save exc status
 745
 746        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
 747        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 748        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
 749
 750        frestore        FP_SRC(%a6)             # do this after fmovm,other f<op>s!
 751
 752        unlk            %a6
 753
 754        bra.l           _real_ovfl
 755
 756# overflow occurred but is disabled. meanwhile, inexact is enabled. Therefore,
 757# we must jump to real_inex().
 758fovfl_inex_on:
 759
 760        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP (fp1) to stack
 761
 762        mov.b           &0xc4,1+EXC_VOFF(%a6)   # vector offset = 0xc4
 763        mov.w           &0xe001,2+FP_SRC(%a6)   # save exc status
 764
 765        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
 766        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 767        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
 768
 769        frestore        FP_SRC(%a6)             # do this after fmovm,other f<op>s!
 770
 771        unlk            %a6
 772
 773        bra.l           _real_inex
 774
 775########################################################################
 776fovfl_out:
 777
 778
 779#$#     mov.l           FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
 780#$#     mov.l           FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
 781#$#     mov.l           FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
 782
 783# the src operand is definitely a NORM(!), so tag it as such
 784        mov.b           &NORM,STAG(%a6)         # set src optype tag
 785
 786        clr.l           %d0
 787        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec/mode
 788
 789        and.l           &0xffff00ff,USER_FPSR(%a6) # zero all but accured field
 790
 791        fmov.l          &0x0,%fpcr              # zero current control regs
 792        fmov.l          &0x0,%fpsr
 793
 794        lea             FP_SRC(%a6),%a0         # pass ptr to src operand
 795
 796        bsr.l           fout
 797
 798        btst            &ovfl_bit,FPCR_ENABLE(%a6)
 799        bne.w           fovfl_ovfl_on
 800
 801        btst            &inex2_bit,FPCR_ENABLE(%a6)
 802        bne.w           fovfl_inex_on
 803
 804        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
 805        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 806        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
 807
 808        unlk            %a6
 809#$#     add.l           &24,%sp
 810
 811        btst            &0x7,(%sp)              # is trace on?
 812        beq.l           _fpsp_done              # no
 813
 814        fmov.l          %fpiar,0x8(%sp)         # "Current PC" is in FPIAR
 815        mov.w           &0x2024,0x6(%sp)        # stk fmt = 0x2; voff = 0x024
 816        bra.l           _real_trace
 817
 818#########################################################################
 819# XDEF **************************************************************** #
 820#       _fpsp_unfl(): 060FPSP entry point for FP Underflow exception.   #
 821#                                                                       #
 822#       This handler should be the first code executed upon taking the  #
 823#       FP Underflow exception in an operating system.                  #
 824#                                                                       #
 825# XREF **************************************************************** #
 826#       _imem_read_long() - read instruction longword                   #
 827#       fix_skewed_ops() - adjust src operand in fsave frame            #
 828#       set_tag_x() - determine optype of src/dst operands              #
 829#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
 830#       unnorm_fix() - change UNNORM operands to NORM or ZERO           #
 831#       load_fpn2() - load dst operand from FP regfile                  #
 832#       fout() - emulate an opclass 3 instruction                       #
 833#       tbl_unsupp - add of table of emulation routines for opclass 0,2 #
 834#       _fpsp_done() - "callout" for 060FPSP exit (all work done!)      #
 835#       _real_ovfl() - "callout" for Overflow exception enabled code    #
 836#       _real_inex() - "callout" for Inexact exception enabled code     #
 837#       _real_trace() - "callout" for Trace exception code              #
 838#                                                                       #
 839# INPUT *************************************************************** #
 840#       - The system stack contains the FP Unfl exception stack frame   #
 841#       - The fsave frame contains the source operand                   #
 842#                                                                       #
 843# OUTPUT ************************************************************** #
 844#       Underflow Exception enabled:                                    #
 845#       - The system stack is unchanged                                 #
 846#       - The fsave frame contains the adjusted src op for opclass 0,2  #
 847#       Underflow Exception disabled:                                   #
 848#       - The system stack is unchanged                                 #
 849#       - The "exception present" flag in the fsave frame is cleared    #
 850#                                                                       #
 851# ALGORITHM *********************************************************** #
 852#       On the 060, if an FP underflow is present as the result of any  #
 853# instruction, the 060 will take an underflow exception whether the     #
 854# exception is enabled or disabled in the FPCR. For the disabled case,  #
 855# This handler emulates the instruction to determine what the correct   #
 856# default result should be for the operation. This default result is    #
 857# then stored in either the FP regfile, data regfile, or memory.        #
 858# Finally, the handler exits through the "callout" _fpsp_done()         #
 859# denoting that no exceptional conditions exist within the machine.     #
 860#       If the exception is enabled, then this handler must create the  #
 861# exceptional operand and plave it in the fsave state frame, and store  #
 862# the default result (only if the instruction is opclass 3). For        #
 863# exceptions enabled, this handler must exit through the "callout"      #
 864# _real_unfl() so that the operating system enabled overflow handler    #
 865# can handle this case.                                                 #
 866#       Two other conditions exist. First, if underflow was disabled    #
 867# but the inexact exception was enabled and the result was inexact,     #
 868# this handler must exit through the "callout" _real_inex().            #
 869# was inexact.                                                          #
 870#       Also, in the case of an opclass three instruction where         #
 871# underflow was disabled and the trace exception was enabled, this      #
 872# handler must exit through the "callout" _real_trace().                #
 873#                                                                       #
 874#########################################################################
 875
 876        global          _fpsp_unfl
 877_fpsp_unfl:
 878
 879#$#     sub.l           &24,%sp                 # make room for src/dst
 880
 881        link.w          %a6,&-LOCAL_SIZE        # init stack frame
 882
 883        fsave           FP_SRC(%a6)             # grab the "busy" frame
 884
 885        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
 886        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
 887        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
 888
 889# the FPIAR holds the "current PC" of the faulting instruction
 890        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
 891        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
 892        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
 893        bsr.l           _imem_read_long         # fetch the instruction words
 894        mov.l           %d0,EXC_OPWORD(%a6)
 895
 896##############################################################################
 897
 898        btst            &0x5,EXC_CMDREG(%a6)    # is instr an fmove out?
 899        bne.w           funfl_out
 900
 901
 902        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
 903        bsr.l           fix_skewed_ops          # fix src op
 904
 905        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
 906        bsr.l           set_tag_x               # tag the operand type
 907        mov.b           %d0,STAG(%a6)           # maybe NORM,DENORM
 908
 909# bit five of the fp ext word separates the monadic and dyadic operations
 910# that can pass through fpsp_unfl(). remember that fcmp, and ftst
 911# will never take this exception.
 912        btst            &0x5,1+EXC_CMDREG(%a6)  # is op monadic or dyadic?
 913        beq.b           funfl_extract           # monadic
 914
 915# now, what's left that's not dyadic is fsincos. we can distinguish it
 916# from all dyadics by the '0110xxx pattern
 917        btst            &0x4,1+EXC_CMDREG(%a6)  # is op an fsincos?
 918        bne.b           funfl_extract           # yes
 919
 920        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
 921        bsr.l           load_fpn2               # load dst into FP_DST
 922
 923        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
 924        bsr.l           set_tag_x               # tag the operand type
 925        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
 926        bne.b           funfl_op2_done          # no
 927        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
 928funfl_op2_done:
 929        mov.b           %d0,DTAG(%a6)           # save dst optype tag
 930
 931funfl_extract:
 932
 933#$#     mov.l           FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
 934#$#     mov.l           FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
 935#$#     mov.l           FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
 936#$#     mov.l           FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6)
 937#$#     mov.l           FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6)
 938#$#     mov.l           FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6)
 939
 940        clr.l           %d0
 941        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec/mode
 942
 943        mov.b           1+EXC_CMDREG(%a6),%d1
 944        andi.w          &0x007f,%d1             # extract extension
 945
 946        andi.l          &0x00ff01ff,USER_FPSR(%a6)
 947
 948        fmov.l          &0x0,%fpcr              # zero current control regs
 949        fmov.l          &0x0,%fpsr
 950
 951        lea             FP_SRC(%a6),%a0
 952        lea             FP_DST(%a6),%a1
 953
 954# maybe we can make these entry points ONLY the OVFL entry points of each routine.
 955        mov.l           (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
 956        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
 957
 958        bfextu          EXC_CMDREG(%a6){&6:&3},%d0
 959        bsr.l           store_fpreg
 960
 961# The `060 FPU multiplier hardware is such that if the result of a
 962# multiply operation is the smallest possible normalized number
 963# (0x00000000_80000000_00000000), then the machine will take an
 964# underflow exception. Since this is incorrect, we need to check
 965# if our emulation, after re-doing the operation, decided that
 966# no underflow was called for. We do these checks only in
 967# funfl_{unfl,inex}_on() because w/ both exceptions disabled, this
 968# special case will simply exit gracefully with the correct result.
 969
 970# the exceptional possibilities we have left ourselves with are ONLY overflow
 971# and inexact. and, the inexact is such that overflow occurred and was disabled
 972# but inexact was enabled.
 973        btst            &unfl_bit,FPCR_ENABLE(%a6)
 974        bne.b           funfl_unfl_on
 975
 976funfl_chkinex:
 977        btst            &inex2_bit,FPCR_ENABLE(%a6)
 978        bne.b           funfl_inex_on
 979
 980funfl_exit:
 981        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
 982        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 983        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
 984
 985        unlk            %a6
 986#$#     add.l           &24,%sp
 987        bra.l           _fpsp_done
 988
 989# overflow is enabled AND overflow, of course, occurred. so, we have the EXOP
 990# in fp1 (don't forget to save fp0). what to do now?
 991# well, we simply have to get to go to _real_unfl()!
 992funfl_unfl_on:
 993
 994# The `060 FPU multiplier hardware is such that if the result of a
 995# multiply operation is the smallest possible normalized number
 996# (0x00000000_80000000_00000000), then the machine will take an
 997# underflow exception. Since this is incorrect, we check here to see
 998# if our emulation, after re-doing the operation, decided that
 999# no underflow was called for.
1000        btst            &unfl_bit,FPSR_EXCEPT(%a6)
1001        beq.w           funfl_chkinex
1002
1003funfl_unfl_on2:
1004        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP (fp1) to stack
1005
1006        mov.w           &0xe003,2+FP_SRC(%a6)   # save exc status
1007
1008        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
1009        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1010        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1011
1012        frestore        FP_SRC(%a6)             # do this after fmovm,other f<op>s!
1013
1014        unlk            %a6
1015
1016        bra.l           _real_unfl
1017
1018# underflow occurred but is disabled. meanwhile, inexact is enabled. Therefore,
1019# we must jump to real_inex().
1020funfl_inex_on:
1021
1022# The `060 FPU multiplier hardware is such that if the result of a
1023# multiply operation is the smallest possible normalized number
1024# (0x00000000_80000000_00000000), then the machine will take an
1025# underflow exception.
1026# But, whether bogus or not, if inexact is enabled AND it occurred,
1027# then we have to branch to real_inex.
1028
1029        btst            &inex2_bit,FPSR_EXCEPT(%a6)
1030        beq.w           funfl_exit
1031
1032funfl_inex_on2:
1033
1034        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP to stack
1035
1036        mov.b           &0xc4,1+EXC_VOFF(%a6)   # vector offset = 0xc4
1037        mov.w           &0xe001,2+FP_SRC(%a6)   # save exc status
1038
1039        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
1040        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1041        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1042
1043        frestore        FP_SRC(%a6)             # do this after fmovm,other f<op>s!
1044
1045        unlk            %a6
1046
1047        bra.l           _real_inex
1048
1049#######################################################################
1050funfl_out:
1051
1052
1053#$#     mov.l           FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
1054#$#     mov.l           FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
1055#$#     mov.l           FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
1056
1057# the src operand is definitely a NORM(!), so tag it as such
1058        mov.b           &NORM,STAG(%a6)         # set src optype tag
1059
1060        clr.l           %d0
1061        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec/mode
1062
1063        and.l           &0xffff00ff,USER_FPSR(%a6) # zero all but accured field
1064
1065        fmov.l          &0x0,%fpcr              # zero current control regs
1066        fmov.l          &0x0,%fpsr
1067
1068        lea             FP_SRC(%a6),%a0         # pass ptr to src operand
1069
1070        bsr.l           fout
1071
1072        btst            &unfl_bit,FPCR_ENABLE(%a6)
1073        bne.w           funfl_unfl_on2
1074
1075        btst            &inex2_bit,FPCR_ENABLE(%a6)
1076        bne.w           funfl_inex_on2
1077
1078        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
1079        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1080        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1081
1082        unlk            %a6
1083#$#     add.l           &24,%sp
1084
1085        btst            &0x7,(%sp)              # is trace on?
1086        beq.l           _fpsp_done              # no
1087
1088        fmov.l          %fpiar,0x8(%sp)         # "Current PC" is in FPIAR
1089        mov.w           &0x2024,0x6(%sp)        # stk fmt = 0x2; voff = 0x024
1090        bra.l           _real_trace
1091
1092#########################################################################
1093# XDEF **************************************************************** #
1094#       _fpsp_unsupp(): 060FPSP entry point for FP "Unimplemented       #
1095#                       Data Type" exception.                           #
1096#                                                                       #
1097#       This handler should be the first code executed upon taking the  #
1098#       FP Unimplemented Data Type exception in an operating system.    #
1099#                                                                       #
1100# XREF **************************************************************** #
1101#       _imem_read_{word,long}() - read instruction word/longword       #
1102#       fix_skewed_ops() - adjust src operand in fsave frame            #
1103#       set_tag_x() - determine optype of src/dst operands              #
1104#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
1105#       unnorm_fix() - change UNNORM operands to NORM or ZERO           #
1106#       load_fpn2() - load dst operand from FP regfile                  #
1107#       load_fpn1() - load src operand from FP regfile                  #
1108#       fout() - emulate an opclass 3 instruction                       #
1109#       tbl_unsupp - add of table of emulation routines for opclass 0,2 #
1110#       _real_inex() - "callout" to operating system inexact handler    #
1111#       _fpsp_done() - "callout" for exit; work all done                #
1112#       _real_trace() - "callout" for Trace enabled exception           #
1113#       funimp_skew() - adjust fsave src ops to "incorrect" value       #
1114#       _real_snan() - "callout" for SNAN exception                     #
1115#       _real_operr() - "callout" for OPERR exception                   #
1116#       _real_ovfl() - "callout" for OVFL exception                     #
1117#       _real_unfl() - "callout" for UNFL exception                     #
1118#       get_packed() - fetch packed operand from memory                 #
1119#                                                                       #
1120# INPUT *************************************************************** #
1121#       - The system stack contains the "Unimp Data Type" stk frame     #
1122#       - The fsave frame contains the ssrc op (for UNNORM/DENORM)      #
1123#                                                                       #
1124# OUTPUT ************************************************************** #
1125#       If Inexact exception (opclass 3):                               #
1126#       - The system stack is changed to an Inexact exception stk frame #
1127#       If SNAN exception (opclass 3):                                  #
1128#       - The system stack is changed to an SNAN exception stk frame    #
1129#       If OPERR exception (opclass 3):                                 #
1130#       - The system stack is changed to an OPERR exception stk frame   #
1131#       If OVFL exception (opclass 3):                                  #
1132#       - The system stack is changed to an OVFL exception stk frame    #
1133#       If UNFL exception (opclass 3):                                  #
1134#       - The system stack is changed to an UNFL exception stack frame  #
1135#       If Trace exception enabled:                                     #
1136#       - The system stack is changed to a Trace exception stack frame  #
1137#       Else: (normal case)                                             #
1138#       - Correct result has been stored as appropriate                 #
1139#                                                                       #
1140# ALGORITHM *********************************************************** #
1141#       Two main instruction types can enter here: (1) DENORM or UNNORM #
1142# unimplemented data types. These can be either opclass 0,2 or 3        #
1143# instructions, and (2) PACKED unimplemented data format instructions   #
1144# also of opclasses 0,2, or 3.                                          #
1145#       For UNNORM/DENORM opclass 0 and 2, the handler fetches the src  #
1146# operand from the fsave state frame and the dst operand (if dyadic)    #
1147# from the FP register file. The instruction is then emulated by        #
1148# choosing an emulation routine from a table of routines indexed by     #
1149# instruction type. Once the instruction has been emulated and result   #
1150# saved, then we check to see if any enabled exceptions resulted from   #
1151# instruction emulation. If none, then we exit through the "callout"    #
1152# _fpsp_done(). If there is an enabled FP exception, then we insert     #
1153# this exception into the FPU in the fsave state frame and then exit    #
1154# through _fpsp_done().                                                 #
1155#       PACKED opclass 0 and 2 is similar in how the instruction is     #
1156# emulated and exceptions handled. The differences occur in how the     #
1157# handler loads the packed op (by calling get_packed() routine) and     #
1158# by the fact that a Trace exception could be pending for PACKED ops.   #
1159# If a Trace exception is pending, then the current exception stack     #
1160# frame is changed to a Trace exception stack frame and an exit is      #
1161# made through _real_trace().                                           #
1162#       For UNNORM/DENORM opclass 3, the actual move out to memory is   #
1163# performed by calling the routine fout(). If no exception should occur #
1164# as the result of emulation, then an exit either occurs through        #
1165# _fpsp_done() or through _real_trace() if a Trace exception is pending #
1166# (a Trace stack frame must be created here, too). If an FP exception   #
1167# should occur, then we must create an exception stack frame of that    #
1168# type and jump to either _real_snan(), _real_operr(), _real_inex(),    #
1169# _real_unfl(), or _real_ovfl() as appropriate. PACKED opclass 3        #
1170# emulation is performed in a similar manner.                           #
1171#                                                                       #
1172#########################################################################
1173
1174#
1175# (1) DENORM and UNNORM (unimplemented) data types:
1176#
1177#                               post-instruction
1178#                               *****************
1179#                               *      EA       *
1180#        pre-instruction        *               *
1181#       *****************       *****************
1182#       * 0x0 *  0x0dc  *       * 0x3 *  0x0dc  *
1183#       *****************       *****************
1184#       *     Next      *       *     Next      *
1185#       *      PC       *       *      PC       *
1186#       *****************       *****************
1187#       *      SR       *       *      SR       *
1188#       *****************       *****************
1189#
1190# (2) PACKED format (unsupported) opclasses two and three:
1191#       *****************
1192#       *      EA       *
1193#       *               *
1194#       *****************
1195#       * 0x2 *  0x0dc  *
1196#       *****************
1197#       *     Next      *
1198#       *      PC       *
1199#       *****************
1200#       *      SR       *
1201#       *****************
1202#
1203        global          _fpsp_unsupp
1204_fpsp_unsupp:
1205
1206        link.w          %a6,&-LOCAL_SIZE        # init stack frame
1207
1208        fsave           FP_SRC(%a6)             # save fp state
1209
1210        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
1211        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
1212        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
1213
1214        btst            &0x5,EXC_SR(%a6)        # user or supervisor mode?
1215        bne.b           fu_s
1216fu_u:
1217        mov.l           %usp,%a0                # fetch user stack pointer
1218        mov.l           %a0,EXC_A7(%a6)         # save on stack
1219        bra.b           fu_cont
1220# if the exception is an opclass zero or two unimplemented data type
1221# exception, then the a7' calculated here is wrong since it doesn't
1222# stack an ea. however, we don't need an a7' for this case anyways.
1223fu_s:
1224        lea             0x4+EXC_EA(%a6),%a0     # load old a7'
1225        mov.l           %a0,EXC_A7(%a6)         # save on stack
1226
1227fu_cont:
1228
1229# the FPIAR holds the "current PC" of the faulting instruction
1230# the FPIAR should be set correctly for ALL exceptions passing through
1231# this point.
1232        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
1233        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
1234        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
1235        bsr.l           _imem_read_long         # fetch the instruction words
1236        mov.l           %d0,EXC_OPWORD(%a6)     # store OPWORD and EXTWORD
1237
1238############################
1239
1240        clr.b           SPCOND_FLG(%a6)         # clear special condition flag
1241
1242# Separate opclass three (fpn-to-mem) ops since they have a different
1243# stack frame and protocol.
1244        btst            &0x5,EXC_CMDREG(%a6)    # is it an fmove out?
1245        bne.w           fu_out                  # yes
1246
1247# Separate packed opclass two instructions.
1248        bfextu          EXC_CMDREG(%a6){&0:&6},%d0
1249        cmpi.b          %d0,&0x13
1250        beq.w           fu_in_pack
1251
1252
1253# I'm not sure at this point what FPSR bits are valid for this instruction.
1254# so, since the emulation routines re-create them anyways, zero exception field
1255        andi.l          &0x00ff00ff,USER_FPSR(%a6) # zero exception field
1256
1257        fmov.l          &0x0,%fpcr              # zero current control regs
1258        fmov.l          &0x0,%fpsr
1259
1260# Opclass two w/ memory-to-fpn operation will have an incorrect extended
1261# precision format if the src format was single or double and the
1262# source data type was an INF, NAN, DENORM, or UNNORM
1263        lea             FP_SRC(%a6),%a0         # pass ptr to input
1264        bsr.l           fix_skewed_ops
1265
1266# we don't know whether the src operand or the dst operand (or both) is the
1267# UNNORM or DENORM. call the function that tags the operand type. if the
1268# input is an UNNORM, then convert it to a NORM, DENORM, or ZERO.
1269        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
1270        bsr.l           set_tag_x               # tag the operand type
1271        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
1272        bne.b           fu_op2                  # no
1273        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
1274
1275fu_op2:
1276        mov.b           %d0,STAG(%a6)           # save src optype tag
1277
1278        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1279
1280# bit five of the fp extension word separates the monadic and dyadic operations
1281# at this point
1282        btst            &0x5,1+EXC_CMDREG(%a6)  # is operation monadic or dyadic?
1283        beq.b           fu_extract              # monadic
1284        cmpi.b          1+EXC_CMDREG(%a6),&0x3a # is operation an ftst?
1285        beq.b           fu_extract              # yes, so it's monadic, too
1286
1287        bsr.l           load_fpn2               # load dst into FP_DST
1288
1289        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
1290        bsr.l           set_tag_x               # tag the operand type
1291        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
1292        bne.b           fu_op2_done             # no
1293        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
1294fu_op2_done:
1295        mov.b           %d0,DTAG(%a6)           # save dst optype tag
1296
1297fu_extract:
1298        clr.l           %d0
1299        mov.b           FPCR_MODE(%a6),%d0      # fetch rnd mode/prec
1300
1301        bfextu          1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension
1302
1303        lea             FP_SRC(%a6),%a0
1304        lea             FP_DST(%a6),%a1
1305
1306        mov.l           (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr
1307        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
1308
1309#
1310# Exceptions in order of precedence:
1311#       BSUN    : none
1312#       SNAN    : all dyadic ops
1313#       OPERR   : fsqrt(-NORM)
1314#       OVFL    : all except ftst,fcmp
1315#       UNFL    : all except ftst,fcmp
1316#       DZ      : fdiv
1317#       INEX2   : all except ftst,fcmp
1318#       INEX1   : none (packed doesn't go through here)
1319#
1320
1321# we determine the highest priority exception(if any) set by the
1322# emulation routine that has also been enabled by the user.
1323        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions set
1324        bne.b           fu_in_ena               # some are enabled
1325
1326fu_in_cont:
1327# fcmp and ftst do not store any result.
1328        mov.b           1+EXC_CMDREG(%a6),%d0   # fetch extension
1329        andi.b          &0x38,%d0               # extract bits 3-5
1330        cmpi.b          %d0,&0x38               # is instr fcmp or ftst?
1331        beq.b           fu_in_exit              # yes
1332
1333        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1334        bsr.l           store_fpreg             # store the result
1335
1336fu_in_exit:
1337
1338        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1339        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1340        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1341
1342        unlk            %a6
1343
1344        bra.l           _fpsp_done
1345
1346fu_in_ena:
1347        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enabled
1348        bfffo           %d0{&24:&8},%d0         # find highest priority exception
1349        bne.b           fu_in_exc               # there is at least one set
1350
1351#
1352# No exceptions occurred that were also enabled. Now:
1353#
1354#       if (OVFL && ovfl_disabled && inexact_enabled) {
1355#           branch to _real_inex() (even if the result was exact!);
1356#       } else {
1357#           save the result in the proper fp reg (unless the op is fcmp or ftst);
1358#           return;
1359#       }
1360#
1361        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
1362        beq.b           fu_in_cont              # no
1363
1364fu_in_ovflchk:
1365        btst            &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
1366        beq.b           fu_in_cont              # no
1367        bra.w           fu_in_exc_ovfl          # go insert overflow frame
1368
1369#
1370# An exception occurred and that exception was enabled:
1371#
1372#       shift enabled exception field into lo byte of d0;
1373#       if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) ||
1374#           ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) {
1375#               /*
1376#                * this is the case where we must call _real_inex() now or else
1377#                * there will be no other way to pass it the exceptional operand
1378#                */
1379#               call _real_inex();
1380#       } else {
1381#               restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU;
1382#       }
1383#
1384fu_in_exc:
1385        subi.l          &24,%d0                 # fix offset to be 0-8
1386        cmpi.b          %d0,&0x6                # is exception INEX? (6)
1387        bne.b           fu_in_exc_exit          # no
1388
1389# the enabled exception was inexact
1390        btst            &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur?
1391        bne.w           fu_in_exc_unfl          # yes
1392        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur?
1393        bne.w           fu_in_exc_ovfl          # yes
1394
1395# here, we insert the correct fsave status value into the fsave frame for the
1396# corresponding exception. the operand in the fsave frame should be the original
1397# src operand.
1398fu_in_exc_exit:
1399        mov.l           %d0,-(%sp)              # save d0
1400        bsr.l           funimp_skew             # skew sgl or dbl inputs
1401        mov.l           (%sp)+,%d0              # restore d0
1402
1403        mov.w           (tbl_except.b,%pc,%d0.w*2),2+FP_SRC(%a6) # create exc status
1404
1405        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1406        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1407        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1408
1409        frestore        FP_SRC(%a6)             # restore src op
1410
1411        unlk            %a6
1412
1413        bra.l           _fpsp_done
1414
1415tbl_except:
1416        short           0xe000,0xe006,0xe004,0xe005
1417        short           0xe003,0xe002,0xe001,0xe001
1418
1419fu_in_exc_unfl:
1420        mov.w           &0x4,%d0
1421        bra.b           fu_in_exc_exit
1422fu_in_exc_ovfl:
1423        mov.w           &0x03,%d0
1424        bra.b           fu_in_exc_exit
1425
1426# If the input operand to this operation was opclass two and a single
1427# or double precision denorm, inf, or nan, the operand needs to be
1428# "corrected" in order to have the proper equivalent extended precision
1429# number.
1430        global          fix_skewed_ops
1431fix_skewed_ops:
1432        bfextu          EXC_CMDREG(%a6){&0:&6},%d0 # extract opclass,src fmt
1433        cmpi.b          %d0,&0x11               # is class = 2 & fmt = sgl?
1434        beq.b           fso_sgl                 # yes
1435        cmpi.b          %d0,&0x15               # is class = 2 & fmt = dbl?
1436        beq.b           fso_dbl                 # yes
1437        rts                                     # no
1438
1439fso_sgl:
1440        mov.w           LOCAL_EX(%a0),%d0       # fetch src exponent
1441        andi.w          &0x7fff,%d0             # strip sign
1442        cmpi.w          %d0,&0x3f80             # is |exp| == $3f80?
1443        beq.b           fso_sgl_dnrm_zero       # yes
1444        cmpi.w          %d0,&0x407f             # no; is |exp| == $407f?
1445        beq.b           fso_infnan              # yes
1446        rts                                     # no
1447
1448fso_sgl_dnrm_zero:
1449        andi.l          &0x7fffffff,LOCAL_HI(%a0) # clear j-bit
1450        beq.b           fso_zero                # it's a skewed zero
1451fso_sgl_dnrm:
1452# here, we count on norm not to alter a0...
1453        bsr.l           norm                    # normalize mantissa
1454        neg.w           %d0                     # -shft amt
1455        addi.w          &0x3f81,%d0             # adjust new exponent
1456        andi.w          &0x8000,LOCAL_EX(%a0)   # clear old exponent
1457        or.w            %d0,LOCAL_EX(%a0)       # insert new exponent
1458        rts
1459
1460fso_zero:
1461        andi.w          &0x8000,LOCAL_EX(%a0)   # clear bogus exponent
1462        rts
1463
1464fso_infnan:
1465        andi.b          &0x7f,LOCAL_HI(%a0)     # clear j-bit
1466        ori.w           &0x7fff,LOCAL_EX(%a0)   # make exponent = $7fff
1467        rts
1468
1469fso_dbl:
1470        mov.w           LOCAL_EX(%a0),%d0       # fetch src exponent
1471        andi.w          &0x7fff,%d0             # strip sign
1472        cmpi.w          %d0,&0x3c00             # is |exp| == $3c00?
1473        beq.b           fso_dbl_dnrm_zero       # yes
1474        cmpi.w          %d0,&0x43ff             # no; is |exp| == $43ff?
1475        beq.b           fso_infnan              # yes
1476        rts                                     # no
1477
1478fso_dbl_dnrm_zero:
1479        andi.l          &0x7fffffff,LOCAL_HI(%a0) # clear j-bit
1480        bne.b           fso_dbl_dnrm            # it's a skewed denorm
1481        tst.l           LOCAL_LO(%a0)           # is it a zero?
1482        beq.b           fso_zero                # yes
1483fso_dbl_dnrm:
1484# here, we count on norm not to alter a0...
1485        bsr.l           norm                    # normalize mantissa
1486        neg.w           %d0                     # -shft amt
1487        addi.w          &0x3c01,%d0             # adjust new exponent
1488        andi.w          &0x8000,LOCAL_EX(%a0)   # clear old exponent
1489        or.w            %d0,LOCAL_EX(%a0)       # insert new exponent
1490        rts
1491
1492#################################################################
1493
1494# fmove out took an unimplemented data type exception.
1495# the src operand is in FP_SRC. Call _fout() to write out the result and
1496# to determine which exceptions, if any, to take.
1497fu_out:
1498
1499# Separate packed move outs from the UNNORM and DENORM move outs.
1500        bfextu          EXC_CMDREG(%a6){&3:&3},%d0
1501        cmpi.b          %d0,&0x3
1502        beq.w           fu_out_pack
1503        cmpi.b          %d0,&0x7
1504        beq.w           fu_out_pack
1505
1506
1507# I'm not sure at this point what FPSR bits are valid for this instruction.
1508# so, since the emulation routines re-create them anyways, zero exception field.
1509# fmove out doesn't affect ccodes.
1510        and.l           &0xffff00ff,USER_FPSR(%a6) # zero exception field
1511
1512        fmov.l          &0x0,%fpcr              # zero current control regs
1513        fmov.l          &0x0,%fpsr
1514
1515# the src can ONLY be a DENORM or an UNNORM! so, don't make any big subroutine
1516# call here. just figure out what it is...
1517        mov.w           FP_SRC_EX(%a6),%d0      # get exponent
1518        andi.w          &0x7fff,%d0             # strip sign
1519        beq.b           fu_out_denorm           # it's a DENORM
1520
1521        lea             FP_SRC(%a6),%a0
1522        bsr.l           unnorm_fix              # yes; fix it
1523
1524        mov.b           %d0,STAG(%a6)
1525
1526        bra.b           fu_out_cont
1527fu_out_denorm:
1528        mov.b           &DENORM,STAG(%a6)
1529fu_out_cont:
1530
1531        clr.l           %d0
1532        mov.b           FPCR_MODE(%a6),%d0      # fetch rnd mode/prec
1533
1534        lea             FP_SRC(%a6),%a0         # pass ptr to src operand
1535
1536        mov.l           (%a6),EXC_A6(%a6)       # in case a6 changes
1537        bsr.l           fout                    # call fmove out routine
1538
1539# Exceptions in order of precedence:
1540#       BSUN    : none
1541#       SNAN    : none
1542#       OPERR   : fmove.{b,w,l} out of large UNNORM
1543#       OVFL    : fmove.{s,d}
1544#       UNFL    : fmove.{s,d,x}
1545#       DZ      : none
1546#       INEX2   : all
1547#       INEX1   : none (packed doesn't travel through here)
1548
1549# determine the highest priority exception(if any) set by the
1550# emulation routine that has also been enabled by the user.
1551        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions enabled
1552        bne.w           fu_out_ena              # some are enabled
1553
1554fu_out_done:
1555
1556        mov.l           EXC_A6(%a6),(%a6)       # in case a6 changed
1557
1558# on extended precision opclass three instructions using pre-decrement or
1559# post-increment addressing mode, the address register is not updated. is the
1560# address register was the stack pointer used from user mode, then let's update
1561# it here. if it was used from supervisor mode, then we have to handle this
1562# as a special case.
1563        btst            &0x5,EXC_SR(%a6)
1564        bne.b           fu_out_done_s
1565
1566        mov.l           EXC_A7(%a6),%a0         # restore a7
1567        mov.l           %a0,%usp
1568
1569fu_out_done_cont:
1570        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1571        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1572        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1573
1574        unlk            %a6
1575
1576        btst            &0x7,(%sp)              # is trace on?
1577        bne.b           fu_out_trace            # yes
1578
1579        bra.l           _fpsp_done
1580
1581# is the ea mode pre-decrement of the stack pointer from supervisor mode?
1582# ("fmov.x fpm,-(a7)") if so,
1583fu_out_done_s:
1584        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
1585        bne.b           fu_out_done_cont
1586
1587# the extended precision result is still in fp0. but, we need to save it
1588# somewhere on the stack until we can copy it to its final resting place.
1589# here, we're counting on the top of the stack to be the old place-holders
1590# for fp0/fp1 which have already been restored. that way, we can write
1591# over those destinations with the shifted stack frame.
1592        fmovm.x         &0x80,FP_SRC(%a6)       # put answer on stack
1593
1594        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1595        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1596        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1597
1598        mov.l           (%a6),%a6               # restore frame pointer
1599
1600        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
1601        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
1602
1603# now, copy the result to the proper place on the stack
1604        mov.l           LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
1605        mov.l           LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
1606        mov.l           LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
1607
1608        add.l           &LOCAL_SIZE-0x8,%sp
1609
1610        btst            &0x7,(%sp)
1611        bne.b           fu_out_trace
1612
1613        bra.l           _fpsp_done
1614
1615fu_out_ena:
1616        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enabled
1617        bfffo           %d0{&24:&8},%d0         # find highest priority exception
1618        bne.b           fu_out_exc              # there is at least one set
1619
1620# no exceptions were set.
1621# if a disabled overflow occurred and inexact was enabled but the result
1622# was exact, then a branch to _real_inex() is made.
1623        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
1624        beq.w           fu_out_done             # no
1625
1626fu_out_ovflchk:
1627        btst            &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
1628        beq.w           fu_out_done             # no
1629        bra.w           fu_inex                 # yes
1630
1631#
1632# The fp move out that took the "Unimplemented Data Type" exception was
1633# being traced. Since the stack frames are similar, get the "current" PC
1634# from FPIAR and put it in the trace stack frame then jump to _real_trace().
1635#
1636#                 UNSUPP FRAME             TRACE FRAME
1637#               *****************       *****************
1638#               *      EA       *       *    Current    *
1639#               *               *       *      PC       *
1640#               *****************       *****************
1641#               * 0x3 *  0x0dc  *       * 0x2 *  0x024  *
1642#               *****************       *****************
1643#               *     Next      *       *     Next      *
1644#               *      PC       *       *      PC       *
1645#               *****************       *****************
1646#               *      SR       *       *      SR       *
1647#               *****************       *****************
1648#
1649fu_out_trace:
1650        mov.w           &0x2024,0x6(%sp)
1651        fmov.l          %fpiar,0x8(%sp)
1652        bra.l           _real_trace
1653
1654# an exception occurred and that exception was enabled.
1655fu_out_exc:
1656        subi.l          &24,%d0                 # fix offset to be 0-8
1657
1658# we don't mess with the existing fsave frame. just re-insert it and
1659# jump to the "_real_{}()" handler...
1660        mov.w           (tbl_fu_out.b,%pc,%d0.w*2),%d0
1661        jmp             (tbl_fu_out.b,%pc,%d0.w*1)
1662
1663        swbeg           &0x8
1664tbl_fu_out:
1665        short           tbl_fu_out      - tbl_fu_out    # BSUN can't happen
1666        short           tbl_fu_out      - tbl_fu_out    # SNAN can't happen
1667        short           fu_operr        - tbl_fu_out    # OPERR
1668        short           fu_ovfl         - tbl_fu_out    # OVFL
1669        short           fu_unfl         - tbl_fu_out    # UNFL
1670        short           tbl_fu_out      - tbl_fu_out    # DZ can't happen
1671        short           fu_inex         - tbl_fu_out    # INEX2
1672        short           tbl_fu_out      - tbl_fu_out    # INEX1 won't make it here
1673
1674# for snan,operr,ovfl,unfl, src op is still in FP_SRC so just
1675# frestore it.
1676fu_snan:
1677        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1678        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1679        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1680
1681        mov.w           &0x30d8,EXC_VOFF(%a6)   # vector offset = 0xd8
1682        mov.w           &0xe006,2+FP_SRC(%a6)
1683
1684        frestore        FP_SRC(%a6)
1685
1686        unlk            %a6
1687
1688
1689        bra.l           _real_snan
1690
1691fu_operr:
1692        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1693        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1694        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1695
1696        mov.w           &0x30d0,EXC_VOFF(%a6)   # vector offset = 0xd0
1697        mov.w           &0xe004,2+FP_SRC(%a6)
1698
1699        frestore        FP_SRC(%a6)
1700
1701        unlk            %a6
1702
1703
1704        bra.l           _real_operr
1705
1706fu_ovfl:
1707        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP to the stack
1708
1709        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1710        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1711        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1712
1713        mov.w           &0x30d4,EXC_VOFF(%a6)   # vector offset = 0xd4
1714        mov.w           &0xe005,2+FP_SRC(%a6)
1715
1716        frestore        FP_SRC(%a6)             # restore EXOP
1717
1718        unlk            %a6
1719
1720        bra.l           _real_ovfl
1721
1722# underflow can happen for extended precision. extended precision opclass
1723# three instruction exceptions don't update the stack pointer. so, if the
1724# exception occurred from user mode, then simply update a7 and exit normally.
1725# if the exception occurred from supervisor mode, check if
1726fu_unfl:
1727        mov.l           EXC_A6(%a6),(%a6)       # restore a6
1728
1729        btst            &0x5,EXC_SR(%a6)
1730        bne.w           fu_unfl_s
1731
1732        mov.l           EXC_A7(%a6),%a0         # restore a7 whether we need
1733        mov.l           %a0,%usp                # to or not...
1734
1735fu_unfl_cont:
1736        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP to the stack
1737
1738        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1739        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1740        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1741
1742        mov.w           &0x30cc,EXC_VOFF(%a6)   # vector offset = 0xcc
1743        mov.w           &0xe003,2+FP_SRC(%a6)
1744
1745        frestore        FP_SRC(%a6)             # restore EXOP
1746
1747        unlk            %a6
1748
1749        bra.l           _real_unfl
1750
1751fu_unfl_s:
1752        cmpi.b          SPCOND_FLG(%a6),&mda7_flg # was the <ea> mode -(sp)?
1753        bne.b           fu_unfl_cont
1754
1755# the extended precision result is still in fp0. but, we need to save it
1756# somewhere on the stack until we can copy it to its final resting place
1757# (where the exc frame is currently). make sure it's not at the top of the
1758# frame or it will get overwritten when the exc stack frame is shifted "down".
1759        fmovm.x         &0x80,FP_SRC(%a6)       # put answer on stack
1760        fmovm.x         &0x40,FP_DST(%a6)       # put EXOP on stack
1761
1762        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1763        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1764        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1765
1766        mov.w           &0x30cc,EXC_VOFF(%a6)   # vector offset = 0xcc
1767        mov.w           &0xe003,2+FP_DST(%a6)
1768
1769        frestore        FP_DST(%a6)             # restore EXOP
1770
1771        mov.l           (%a6),%a6               # restore frame pointer
1772
1773        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
1774        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
1775        mov.l           LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
1776
1777# now, copy the result to the proper place on the stack
1778        mov.l           LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
1779        mov.l           LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
1780        mov.l           LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
1781
1782        add.l           &LOCAL_SIZE-0x8,%sp
1783
1784        bra.l           _real_unfl
1785
1786# fmove in and out enter here.
1787fu_inex:
1788        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP to the stack
1789
1790        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1791        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1792        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1793
1794        mov.w           &0x30c4,EXC_VOFF(%a6)   # vector offset = 0xc4
1795        mov.w           &0xe001,2+FP_SRC(%a6)
1796
1797        frestore        FP_SRC(%a6)             # restore EXOP
1798
1799        unlk            %a6
1800
1801
1802        bra.l           _real_inex
1803
1804#########################################################################
1805#########################################################################
1806fu_in_pack:
1807
1808
1809# I'm not sure at this point what FPSR bits are valid for this instruction.
1810# so, since the emulation routines re-create them anyways, zero exception field
1811        andi.l          &0x0ff00ff,USER_FPSR(%a6) # zero exception field
1812
1813        fmov.l          &0x0,%fpcr              # zero current control regs
1814        fmov.l          &0x0,%fpsr
1815
1816        bsr.l           get_packed              # fetch packed src operand
1817
1818        lea             FP_SRC(%a6),%a0         # pass ptr to src
1819        bsr.l           set_tag_x               # set src optype tag
1820
1821        mov.b           %d0,STAG(%a6)           # save src optype tag
1822
1823        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1824
1825# bit five of the fp extension word separates the monadic and dyadic operations
1826# at this point
1827        btst            &0x5,1+EXC_CMDREG(%a6)  # is operation monadic or dyadic?
1828        beq.b           fu_extract_p            # monadic
1829        cmpi.b          1+EXC_CMDREG(%a6),&0x3a # is operation an ftst?
1830        beq.b           fu_extract_p            # yes, so it's monadic, too
1831
1832        bsr.l           load_fpn2               # load dst into FP_DST
1833
1834        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
1835        bsr.l           set_tag_x               # tag the operand type
1836        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
1837        bne.b           fu_op2_done_p           # no
1838        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
1839fu_op2_done_p:
1840        mov.b           %d0,DTAG(%a6)           # save dst optype tag
1841
1842fu_extract_p:
1843        clr.l           %d0
1844        mov.b           FPCR_MODE(%a6),%d0      # fetch rnd mode/prec
1845
1846        bfextu          1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension
1847
1848        lea             FP_SRC(%a6),%a0
1849        lea             FP_DST(%a6),%a1
1850
1851        mov.l           (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr
1852        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
1853
1854#
1855# Exceptions in order of precedence:
1856#       BSUN    : none
1857#       SNAN    : all dyadic ops
1858#       OPERR   : fsqrt(-NORM)
1859#       OVFL    : all except ftst,fcmp
1860#       UNFL    : all except ftst,fcmp
1861#       DZ      : fdiv
1862#       INEX2   : all except ftst,fcmp
1863#       INEX1   : all
1864#
1865
1866# we determine the highest priority exception(if any) set by the
1867# emulation routine that has also been enabled by the user.
1868        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions enabled
1869        bne.w           fu_in_ena_p             # some are enabled
1870
1871fu_in_cont_p:
1872# fcmp and ftst do not store any result.
1873        mov.b           1+EXC_CMDREG(%a6),%d0   # fetch extension
1874        andi.b          &0x38,%d0               # extract bits 3-5
1875        cmpi.b          %d0,&0x38               # is instr fcmp or ftst?
1876        beq.b           fu_in_exit_p            # yes
1877
1878        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1879        bsr.l           store_fpreg             # store the result
1880
1881fu_in_exit_p:
1882
1883        btst            &0x5,EXC_SR(%a6)        # user or supervisor?
1884        bne.w           fu_in_exit_s_p          # supervisor
1885
1886        mov.l           EXC_A7(%a6),%a0         # update user a7
1887        mov.l           %a0,%usp
1888
1889fu_in_exit_cont_p:
1890        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1891        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1892        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1893
1894        unlk            %a6                     # unravel stack frame
1895
1896        btst            &0x7,(%sp)              # is trace on?
1897        bne.w           fu_trace_p              # yes
1898
1899        bra.l           _fpsp_done              # exit to os
1900
1901# the exception occurred in supervisor mode. check to see if the
1902# addressing mode was (a7)+. if so, we'll need to shift the
1903# stack frame "up".
1904fu_in_exit_s_p:
1905        btst            &mia7_bit,SPCOND_FLG(%a6) # was ea mode (a7)+
1906        beq.b           fu_in_exit_cont_p       # no
1907
1908        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1909        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1910        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1911
1912        unlk            %a6                     # unravel stack frame
1913
1914# shift the stack frame "up". we don't really care about the <ea> field.
1915        mov.l           0x4(%sp),0x10(%sp)
1916        mov.l           0x0(%sp),0xc(%sp)
1917        add.l           &0xc,%sp
1918
1919        btst            &0x7,(%sp)              # is trace on?
1920        bne.w           fu_trace_p              # yes
1921
1922        bra.l           _fpsp_done              # exit to os
1923
1924fu_in_ena_p:
1925        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enabled & set
1926        bfffo           %d0{&24:&8},%d0         # find highest priority exception
1927        bne.b           fu_in_exc_p             # at least one was set
1928
1929#
1930# No exceptions occurred that were also enabled. Now:
1931#
1932#       if (OVFL && ovfl_disabled && inexact_enabled) {
1933#           branch to _real_inex() (even if the result was exact!);
1934#       } else {
1935#           save the result in the proper fp reg (unless the op is fcmp or ftst);
1936#           return;
1937#       }
1938#
1939        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
1940        beq.w           fu_in_cont_p            # no
1941
1942fu_in_ovflchk_p:
1943        btst            &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
1944        beq.w           fu_in_cont_p            # no
1945        bra.w           fu_in_exc_ovfl_p        # do _real_inex() now
1946
1947#
1948# An exception occurred and that exception was enabled:
1949#
1950#       shift enabled exception field into lo byte of d0;
1951#       if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) ||
1952#           ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) {
1953#               /*
1954#                * this is the case where we must call _real_inex() now or else
1955#                * there will be no other way to pass it the exceptional operand
1956#                */
1957#               call _real_inex();
1958#       } else {
1959#               restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU;
1960#       }
1961#
1962fu_in_exc_p:
1963        subi.l          &24,%d0                 # fix offset to be 0-8
1964        cmpi.b          %d0,&0x6                # is exception INEX? (6 or 7)
1965        blt.b           fu_in_exc_exit_p        # no
1966
1967# the enabled exception was inexact
1968        btst            &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur?
1969        bne.w           fu_in_exc_unfl_p        # yes
1970        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur?
1971        bne.w           fu_in_exc_ovfl_p        # yes
1972
1973# here, we insert the correct fsave status value into the fsave frame for the
1974# corresponding exception. the operand in the fsave frame should be the original
1975# src operand.
1976# as a reminder for future predicted pain and agony, we are passing in fsave the
1977# "non-skewed" operand for cases of sgl and dbl src INFs,NANs, and DENORMs.
1978# this is INCORRECT for enabled SNAN which would give to the user the skewed SNAN!!!
1979fu_in_exc_exit_p:
1980        btst            &0x5,EXC_SR(%a6)        # user or supervisor?
1981        bne.w           fu_in_exc_exit_s_p      # supervisor
1982
1983        mov.l           EXC_A7(%a6),%a0         # update user a7
1984        mov.l           %a0,%usp
1985
1986fu_in_exc_exit_cont_p:
1987        mov.w           (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6)
1988
1989        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1990        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1991        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1992
1993        frestore        FP_SRC(%a6)             # restore src op
1994
1995        unlk            %a6
1996
1997        btst            &0x7,(%sp)              # is trace enabled?
1998        bne.w           fu_trace_p              # yes
1999
2000        bra.l           _fpsp_done
2001
2002tbl_except_p:
2003        short           0xe000,0xe006,0xe004,0xe005
2004        short           0xe003,0xe002,0xe001,0xe001
2005
2006fu_in_exc_ovfl_p:
2007        mov.w           &0x3,%d0
2008        bra.w           fu_in_exc_exit_p
2009
2010fu_in_exc_unfl_p:
2011        mov.w           &0x4,%d0
2012        bra.w           fu_in_exc_exit_p
2013
2014fu_in_exc_exit_s_p:
2015        btst            &mia7_bit,SPCOND_FLG(%a6)
2016        beq.b           fu_in_exc_exit_cont_p
2017
2018        mov.w           (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6)
2019
2020        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2021        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2022        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2023
2024        frestore        FP_SRC(%a6)             # restore src op
2025
2026        unlk            %a6                     # unravel stack frame
2027
2028# shift stack frame "up". who cares about <ea> field.
2029        mov.l           0x4(%sp),0x10(%sp)
2030        mov.l           0x0(%sp),0xc(%sp)
2031        add.l           &0xc,%sp
2032
2033        btst            &0x7,(%sp)              # is trace on?
2034        bne.b           fu_trace_p              # yes
2035
2036        bra.l           _fpsp_done              # exit to os
2037
2038#
2039# The opclass two PACKED instruction that took an "Unimplemented Data Type"
2040# exception was being traced. Make the "current" PC the FPIAR and put it in the
2041# trace stack frame then jump to _real_trace().
2042#
2043#                 UNSUPP FRAME             TRACE FRAME
2044#               *****************       *****************
2045#               *      EA       *       *    Current    *
2046#               *               *       *      PC       *
2047#               *****************       *****************
2048#               * 0x2 * 0x0dc   *       * 0x2 *  0x024  *
2049#               *****************       *****************
2050#               *     Next      *       *     Next      *
2051#               *      PC       *       *      PC       *
2052#               *****************       *****************
2053#               *      SR       *       *      SR       *
2054#               *****************       *****************
2055fu_trace_p:
2056        mov.w           &0x2024,0x6(%sp)
2057        fmov.l          %fpiar,0x8(%sp)
2058
2059        bra.l           _real_trace
2060
2061#########################################################
2062#########################################################
2063fu_out_pack:
2064
2065
2066# I'm not sure at this point what FPSR bits are valid for this instruction.
2067# so, since the emulation routines re-create them anyways, zero exception field.
2068# fmove out doesn't affect ccodes.
2069        and.l           &0xffff00ff,USER_FPSR(%a6) # zero exception field
2070
2071        fmov.l          &0x0,%fpcr              # zero current control regs
2072        fmov.l          &0x0,%fpsr
2073
2074        bfextu          EXC_CMDREG(%a6){&6:&3},%d0
2075        bsr.l           load_fpn1
2076
2077# unlike other opclass 3, unimplemented data type exceptions, packed must be
2078# able to detect all operand types.
2079        lea             FP_SRC(%a6),%a0
2080        bsr.l           set_tag_x               # tag the operand type
2081        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
2082        bne.b           fu_op2_p                # no
2083        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
2084
2085fu_op2_p:
2086        mov.b           %d0,STAG(%a6)           # save src optype tag
2087
2088        clr.l           %d0
2089        mov.b           FPCR_MODE(%a6),%d0      # fetch rnd mode/prec
2090
2091        lea             FP_SRC(%a6),%a0         # pass ptr to src operand
2092
2093        mov.l           (%a6),EXC_A6(%a6)       # in case a6 changes
2094        bsr.l           fout                    # call fmove out routine
2095
2096# Exceptions in order of precedence:
2097#       BSUN    : no
2098#       SNAN    : yes
2099#       OPERR   : if ((k_factor > +17) || (dec. exp exceeds 3 digits))
2100#       OVFL    : no
2101#       UNFL    : no
2102#       DZ      : no
2103#       INEX2   : yes
2104#       INEX1   : no
2105
2106# determine the highest priority exception(if any) set by the
2107# emulation routine that has also been enabled by the user.
2108        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions enabled
2109        bne.w           fu_out_ena_p            # some are enabled
2110
2111fu_out_exit_p:
2112        mov.l           EXC_A6(%a6),(%a6)       # restore a6
2113
2114        btst            &0x5,EXC_SR(%a6)        # user or supervisor?
2115        bne.b           fu_out_exit_s_p         # supervisor
2116
2117        mov.l           EXC_A7(%a6),%a0         # update user a7
2118        mov.l           %a0,%usp
2119
2120fu_out_exit_cont_p:
2121        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2122        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2123        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2124
2125        unlk            %a6                     # unravel stack frame
2126
2127        btst            &0x7,(%sp)              # is trace on?
2128        bne.w           fu_trace_p              # yes
2129
2130        bra.l           _fpsp_done              # exit to os
2131
2132# the exception occurred in supervisor mode. check to see if the
2133# addressing mode was -(a7). if so, we'll need to shift the
2134# stack frame "down".
2135fu_out_exit_s_p:
2136        btst            &mda7_bit,SPCOND_FLG(%a6) # was ea mode -(a7)
2137        beq.b           fu_out_exit_cont_p      # no
2138
2139        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2140        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2141        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2142
2143        mov.l           (%a6),%a6               # restore frame pointer
2144
2145        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2146        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2147
2148# now, copy the result to the proper place on the stack
2149        mov.l           LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
2150        mov.l           LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
2151        mov.l           LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
2152
2153        add.l           &LOCAL_SIZE-0x8,%sp
2154
2155        btst            &0x7,(%sp)
2156        bne.w           fu_trace_p
2157
2158        bra.l           _fpsp_done
2159
2160fu_out_ena_p:
2161        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enabled
2162        bfffo           %d0{&24:&8},%d0         # find highest priority exception
2163        beq.w           fu_out_exit_p
2164
2165        mov.l           EXC_A6(%a6),(%a6)       # restore a6
2166
2167# an exception occurred and that exception was enabled.
2168# the only exception possible on packed move out are INEX, OPERR, and SNAN.
2169fu_out_exc_p:
2170        cmpi.b          %d0,&0x1a
2171        bgt.w           fu_inex_p2
2172        beq.w           fu_operr_p
2173
2174fu_snan_p:
2175        btst            &0x5,EXC_SR(%a6)
2176        bne.b           fu_snan_s_p
2177
2178        mov.l           EXC_A7(%a6),%a0
2179        mov.l           %a0,%usp
2180        bra.w           fu_snan
2181
2182fu_snan_s_p:
2183        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
2184        bne.w           fu_snan
2185
2186# the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
2187# the strategy is to move the exception frame "down" 12 bytes. then, we
2188# can store the default result where the exception frame was.
2189        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2190        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2191        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2192
2193        mov.w           &0x30d8,EXC_VOFF(%a6)   # vector offset = 0xd0
2194        mov.w           &0xe006,2+FP_SRC(%a6)   # set fsave status
2195
2196        frestore        FP_SRC(%a6)             # restore src operand
2197
2198        mov.l           (%a6),%a6               # restore frame pointer
2199
2200        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2201        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2202        mov.l           LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
2203
2204# now, we copy the default result to its proper location
2205        mov.l           LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
2206        mov.l           LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
2207        mov.l           LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
2208
2209        add.l           &LOCAL_SIZE-0x8,%sp
2210
2211
2212        bra.l           _real_snan
2213
2214fu_operr_p:
2215        btst            &0x5,EXC_SR(%a6)
2216        bne.w           fu_operr_p_s
2217
2218        mov.l           EXC_A7(%a6),%a0
2219        mov.l           %a0,%usp
2220        bra.w           fu_operr
2221
2222fu_operr_p_s:
2223        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
2224        bne.w           fu_operr
2225
2226# the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
2227# the strategy is to move the exception frame "down" 12 bytes. then, we
2228# can store the default result where the exception frame was.
2229        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2230        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2231        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2232
2233        mov.w           &0x30d0,EXC_VOFF(%a6)   # vector offset = 0xd0
2234        mov.w           &0xe004,2+FP_SRC(%a6)   # set fsave status
2235
2236        frestore        FP_SRC(%a6)             # restore src operand
2237
2238        mov.l           (%a6),%a6               # restore frame pointer
2239
2240        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2241        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2242        mov.l           LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
2243
2244# now, we copy the default result to its proper location
2245        mov.l           LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
2246        mov.l           LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
2247        mov.l           LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
2248
2249        add.l           &LOCAL_SIZE-0x8,%sp
2250
2251
2252        bra.l           _real_operr
2253
2254fu_inex_p2:
2255        btst            &0x5,EXC_SR(%a6)
2256        bne.w           fu_inex_s_p2
2257
2258        mov.l           EXC_A7(%a6),%a0
2259        mov.l           %a0,%usp
2260        bra.w           fu_inex
2261
2262fu_inex_s_p2:
2263        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
2264        bne.w           fu_inex
2265
2266# the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
2267# the strategy is to move the exception frame "down" 12 bytes. then, we
2268# can store the default result where the exception frame was.
2269        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2270        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2271        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2272
2273        mov.w           &0x30c4,EXC_VOFF(%a6)   # vector offset = 0xc4
2274        mov.w           &0xe001,2+FP_SRC(%a6)   # set fsave status
2275
2276        frestore        FP_SRC(%a6)             # restore src operand
2277
2278        mov.l           (%a6),%a6               # restore frame pointer
2279
2280        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2281        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2282        mov.l           LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
2283
2284# now, we copy the default result to its proper location
2285        mov.l           LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
2286        mov.l           LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
2287        mov.l           LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
2288
2289        add.l           &LOCAL_SIZE-0x8,%sp
2290
2291
2292        bra.l           _real_inex
2293
2294#########################################################################
2295
2296#
2297# if we're stuffing a source operand back into an fsave frame then we
2298# have to make sure that for single or double source operands that the
2299# format stuffed is as weird as the hardware usually makes it.
2300#
2301        global          funimp_skew
2302funimp_skew:
2303        bfextu          EXC_EXTWORD(%a6){&3:&3},%d0 # extract src specifier
2304        cmpi.b          %d0,&0x1                # was src sgl?
2305        beq.b           funimp_skew_sgl         # yes
2306        cmpi.b          %d0,&0x5                # was src dbl?
2307        beq.b           funimp_skew_dbl         # yes
2308        rts
2309
2310funimp_skew_sgl:
2311        mov.w           FP_SRC_EX(%a6),%d0      # fetch DENORM exponent
2312        andi.w          &0x7fff,%d0             # strip sign
2313        beq.b           funimp_skew_sgl_not
2314        cmpi.w          %d0,&0x3f80
2315        bgt.b           funimp_skew_sgl_not
2316        neg.w           %d0                     # make exponent negative
2317        addi.w          &0x3f81,%d0             # find amt to shift
2318        mov.l           FP_SRC_HI(%a6),%d1      # fetch DENORM hi(man)
2319        lsr.l           %d0,%d1                 # shift it
2320        bset            &31,%d1                 # set j-bit
2321        mov.l           %d1,FP_SRC_HI(%a6)      # insert new hi(man)
2322        andi.w          &0x8000,FP_SRC_EX(%a6)  # clear old exponent
2323        ori.w           &0x3f80,FP_SRC_EX(%a6)  # insert new "skewed" exponent
2324funimp_skew_sgl_not:
2325        rts
2326
2327funimp_skew_dbl:
2328        mov.w           FP_SRC_EX(%a6),%d0      # fetch DENORM exponent
2329        andi.w          &0x7fff,%d0             # strip sign
2330        beq.b           funimp_skew_dbl_not
2331        cmpi.w          %d0,&0x3c00
2332        bgt.b           funimp_skew_dbl_not
2333
2334        tst.b           FP_SRC_EX(%a6)          # make "internal format"
2335        smi.b           0x2+FP_SRC(%a6)
2336        mov.w           %d0,FP_SRC_EX(%a6)      # insert exponent with cleared sign
2337        clr.l           %d0                     # clear g,r,s
2338        lea             FP_SRC(%a6),%a0         # pass ptr to src op
2339        mov.w           &0x3c01,%d1             # pass denorm threshold
2340        bsr.l           dnrm_lp                 # denorm it
2341        mov.w           &0x3c00,%d0             # new exponent
2342        tst.b           0x2+FP_SRC(%a6)         # is sign set?
2343        beq.b           fss_dbl_denorm_done     # no
2344        bset            &15,%d0                 # set sign
2345fss_dbl_denorm_done:
2346        bset            &0x7,FP_SRC_HI(%a6)     # set j-bit
2347        mov.w           %d0,FP_SRC_EX(%a6)      # insert new exponent
2348funimp_skew_dbl_not:
2349        rts
2350
2351#########################################################################
2352        global          _mem_write2
2353_mem_write2:
2354        btst            &0x5,EXC_SR(%a6)
2355        beq.l           _dmem_write
2356        mov.l           0x0(%a0),FP_DST_EX(%a6)
2357        mov.l           0x4(%a0),FP_DST_HI(%a6)
2358        mov.l           0x8(%a0),FP_DST_LO(%a6)
2359        clr.l           %d1
2360        rts
2361
2362#########################################################################
2363# XDEF **************************************************************** #
2364#       _fpsp_effadd(): 060FPSP entry point for FP "Unimplemented       #
2365#                       effective address" exception.                   #
2366#                                                                       #
2367#       This handler should be the first code executed upon taking the  #
2368#       FP Unimplemented Effective Address exception in an operating    #
2369#       system.                                                         #
2370#                                                                       #
2371# XREF **************************************************************** #
2372#       _imem_read_long() - read instruction longword                   #
2373#       fix_skewed_ops() - adjust src operand in fsave frame            #
2374#       set_tag_x() - determine optype of src/dst operands              #
2375#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
2376#       unnorm_fix() - change UNNORM operands to NORM or ZERO           #
2377#       load_fpn2() - load dst operand from FP regfile                  #
2378#       tbl_unsupp - add of table of emulation routines for opclass 0,2 #
2379#       decbin() - convert packed data to FP binary data                #
2380#       _real_fpu_disabled() - "callout" for "FPU disabled" exception   #
2381#       _real_access() - "callout" for access error exception           #
2382#       _mem_read() - read extended immediate operand from memory       #
2383#       _fpsp_done() - "callout" for exit; work all done                #
2384#       _real_trace() - "callout" for Trace enabled exception           #
2385#       fmovm_dynamic() - emulate dynamic fmovm instruction             #
2386#       fmovm_ctrl() - emulate fmovm control instruction                #
2387#                                                                       #
2388# INPUT *************************************************************** #
2389#       - The system stack contains the "Unimplemented <ea>" stk frame  #
2390#                                                                       #
2391# OUTPUT ************************************************************** #
2392#       If access error:                                                #
2393#       - The system stack is changed to an access error stack frame    #
2394#       If FPU disabled:                                                #
2395#       - The system stack is changed to an FPU disabled stack frame    #
2396#       If Trace exception enabled:                                     #
2397#       - The system stack is changed to a Trace exception stack frame  #
2398#       Else: (normal case)                                             #
2399#       - None (correct result has been stored as appropriate)          #
2400#                                                                       #
2401# ALGORITHM *********************************************************** #
2402#       This exception handles 3 types of operations:                   #
2403# (1) FP Instructions using extended precision or packed immediate      #
2404#     addressing mode.                                                  #
2405# (2) The "fmovm.x" instruction w/ dynamic register specification.      #
2406# (3) The "fmovm.l" instruction w/ 2 or 3 control registers.            #
2407#                                                                       #
2408#       For immediate data operations, the data is read in w/ a         #
2409# _mem_read() "callout", converted to FP binary (if packed), and used   #
2410# as the source operand to the instruction specified by the instruction #
2411# word. If no FP exception should be reported ads a result of the       #
2412# emulation, then the result is stored to the destination register and  #
2413# the handler exits through _fpsp_done(). If an enabled exc has been    #
2414# signalled as a result of emulation, then an fsave state frame         #
2415# corresponding to the FP exception type must be entered into the 060   #
2416# FPU before exiting. In either the enabled or disabled cases, we       #
2417# must also check if a Trace exception is pending, in which case, we    #
2418# must create a Trace exception stack frame from the current exception  #
2419# stack frame. If no Trace is pending, we simply exit through           #
2420# _fpsp_done().                                                         #
2421#       For "fmovm.x", call the routine fmovm_dynamic() which will      #
2422# decode and emulate the instruction. No FP exceptions can be pending   #
2423# as a result of this operation emulation. A Trace exception can be     #
2424# pending, though, which means the current stack frame must be changed  #
2425# to a Trace stack frame and an exit made through _real_trace().        #
2426# For the case of "fmovm.x Dn,-(a7)", where the offending instruction   #
2427# was executed from supervisor mode, this handler must store the FP     #
2428# register file values to the system stack by itself since              #
2429# fmovm_dynamic() can't handle this. A normal exit is made through      #
2430# fpsp_done().                                                          #
2431#       For "fmovm.l", fmovm_ctrl() is used to emulate the instruction. #
2432# Again, a Trace exception may be pending and an exit made through      #
2433# _real_trace(). Else, a normal exit is made through _fpsp_done().      #
2434#                                                                       #
2435#       Before any of the above is attempted, it must be checked to     #
2436# see if the FPU is disabled. Since the "Unimp <ea>" exception is taken #
2437# before the "FPU disabled" exception, but the "FPU disabled" exception #
2438# has higher priority, we check the disabled bit in the PCR. If set,    #
2439# then we must create an 8 word "FPU disabled" exception stack frame    #
2440# from the current 4 word exception stack frame. This includes          #
2441# reproducing the effective address of the instruction to put on the    #
2442# new stack frame.                                                      #
2443#                                                                       #
2444#       In the process of all emulation work, if a _mem_read()          #
2445# "callout" returns a failing result indicating an access error, then   #
2446# we must create an access error stack frame from the current stack     #
2447# frame. This information includes a faulting address and a fault-      #
2448# status-longword. These are created within this handler.               #
2449#                                                                       #
2450#########################################################################
2451
2452        global          _fpsp_effadd
2453_fpsp_effadd:
2454
2455# This exception type takes priority over the "Line F Emulator"
2456# exception. Therefore, the FPU could be disabled when entering here.
2457# So, we must check to see if it's disabled and handle that case separately.
2458        mov.l           %d0,-(%sp)              # save d0
2459        movc            %pcr,%d0                # load proc cr
2460        btst            &0x1,%d0                # is FPU disabled?
2461        bne.w           iea_disabled            # yes
2462        mov.l           (%sp)+,%d0              # restore d0
2463
2464        link            %a6,&-LOCAL_SIZE        # init stack frame
2465
2466        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
2467        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
2468        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
2469
2470# PC of instruction that took the exception is the PC in the frame
2471        mov.l           EXC_PC(%a6),EXC_EXTWPTR(%a6)
2472
2473        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
2474        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
2475        bsr.l           _imem_read_long         # fetch the instruction words
2476        mov.l           %d0,EXC_OPWORD(%a6)     # store OPWORD and EXTWORD
2477
2478#########################################################################
2479
2480        tst.w           %d0                     # is operation fmovem?
2481        bmi.w           iea_fmovm               # yes
2482
2483#
2484# here, we will have:
2485#       fabs    fdabs   fsabs           facos           fmod
2486#       fadd    fdadd   fsadd           fasin           frem
2487#       fcmp                            fatan           fscale
2488#       fdiv    fddiv   fsdiv           fatanh          fsin
2489#       fint                            fcos            fsincos
2490#       fintrz                          fcosh           fsinh
2491#       fmove   fdmove  fsmove          fetox           ftan
2492#       fmul    fdmul   fsmul           fetoxm1         ftanh
2493#       fneg    fdneg   fsneg           fgetexp         ftentox
2494#       fsgldiv                         fgetman         ftwotox
2495#       fsglmul                         flog10
2496#       fsqrt                           flog2
2497#       fsub    fdsub   fssub           flogn
2498#       ftst                            flognp1
2499# which can all use f<op>.{x,p}
2500# so, now it's immediate data extended precision AND PACKED FORMAT!
2501#
2502iea_op:
2503        andi.l          &0x00ff00ff,USER_FPSR(%a6)
2504
2505        btst            &0xa,%d0                # is src fmt x or p?
2506        bne.b           iea_op_pack             # packed
2507
2508
2509        mov.l           EXC_EXTWPTR(%a6),%a0    # pass: ptr to #<data>
2510        lea             FP_SRC(%a6),%a1         # pass: ptr to super addr
2511        mov.l           &0xc,%d0                # pass: 12 bytes
2512        bsr.l           _imem_read              # read extended immediate
2513
2514        tst.l           %d1                     # did ifetch fail?
2515        bne.w           iea_iacc                # yes
2516
2517        bra.b           iea_op_setsrc
2518
2519iea_op_pack:
2520
2521        mov.l           EXC_EXTWPTR(%a6),%a0    # pass: ptr to #<data>
2522        lea             FP_SRC(%a6),%a1         # pass: ptr to super dst
2523        mov.l           &0xc,%d0                # pass: 12 bytes
2524        bsr.l           _imem_read              # read packed operand
2525
2526        tst.l           %d1                     # did ifetch fail?
2527        bne.w           iea_iacc                # yes
2528
2529# The packed operand is an INF or a NAN if the exponent field is all ones.
2530        bfextu          FP_SRC(%a6){&1:&15},%d0 # get exp
2531        cmpi.w          %d0,&0x7fff             # INF or NAN?
2532        beq.b           iea_op_setsrc           # operand is an INF or NAN
2533
2534# The packed operand is a zero if the mantissa is all zero, else it's
2535# a normal packed op.
2536        mov.b           3+FP_SRC(%a6),%d0       # get byte 4
2537        andi.b          &0x0f,%d0               # clear all but last nybble
2538        bne.b           iea_op_gp_not_spec      # not a zero
2539        tst.l           FP_SRC_HI(%a6)          # is lw 2 zero?
2540        bne.b           iea_op_gp_not_spec      # not a zero
2541        tst.l           FP_SRC_LO(%a6)          # is lw 3 zero?
2542        beq.b           iea_op_setsrc           # operand is a ZERO
2543iea_op_gp_not_spec:
2544        lea             FP_SRC(%a6),%a0         # pass: ptr to packed op
2545        bsr.l           decbin                  # convert to extended
2546        fmovm.x         &0x80,FP_SRC(%a6)       # make this the srcop
2547
2548iea_op_setsrc:
2549        addi.l          &0xc,EXC_EXTWPTR(%a6)   # update extension word pointer
2550
2551# FP_SRC now holds the src operand.
2552        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
2553        bsr.l           set_tag_x               # tag the operand type
2554        mov.b           %d0,STAG(%a6)           # could be ANYTHING!!!
2555        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
2556        bne.b           iea_op_getdst           # no
2557        bsr.l           unnorm_fix              # yes; convert to NORM/DENORM/ZERO
2558        mov.b           %d0,STAG(%a6)           # set new optype tag
2559iea_op_getdst:
2560        clr.b           STORE_FLG(%a6)          # clear "store result" boolean
2561
2562        btst            &0x5,1+EXC_CMDREG(%a6)  # is operation monadic or dyadic?
2563        beq.b           iea_op_extract          # monadic
2564        btst            &0x4,1+EXC_CMDREG(%a6)  # is operation fsincos,ftst,fcmp?
2565        bne.b           iea_op_spec             # yes
2566
2567iea_op_loaddst:
2568        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno
2569        bsr.l           load_fpn2               # load dst operand
2570
2571        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
2572        bsr.l           set_tag_x               # tag the operand type
2573        mov.b           %d0,DTAG(%a6)           # could be ANYTHING!!!
2574        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
2575        bne.b           iea_op_extract          # no
2576        bsr.l           unnorm_fix              # yes; convert to NORM/DENORM/ZERO
2577        mov.b           %d0,DTAG(%a6)           # set new optype tag
2578        bra.b           iea_op_extract
2579
2580# the operation is fsincos, ftst, or fcmp. only fcmp is dyadic
2581iea_op_spec:
2582        btst            &0x3,1+EXC_CMDREG(%a6)  # is operation fsincos?
2583        beq.b           iea_op_extract          # yes
2584# now, we're left with ftst and fcmp. so, first let's tag them so that they don't
2585# store a result. then, only fcmp will branch back and pick up a dst operand.
2586        st              STORE_FLG(%a6)          # don't store a final result
2587        btst            &0x1,1+EXC_CMDREG(%a6)  # is operation fcmp?
2588        beq.b           iea_op_loaddst          # yes
2589
2590iea_op_extract:
2591        clr.l           %d0
2592        mov.b           FPCR_MODE(%a6),%d0      # pass: rnd mode,prec
2593
2594        mov.b           1+EXC_CMDREG(%a6),%d1
2595        andi.w          &0x007f,%d1             # extract extension
2596
2597        fmov.l          &0x0,%fpcr
2598        fmov.l          &0x0,%fpsr
2599
2600        lea             FP_SRC(%a6),%a0
2601        lea             FP_DST(%a6),%a1
2602
2603        mov.l           (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
2604        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
2605
2606#
2607# Exceptions in order of precedence:
2608#       BSUN    : none
2609#       SNAN    : all operations
2610#       OPERR   : all reg-reg or mem-reg operations that can normally operr
2611#       OVFL    : same as OPERR
2612#       UNFL    : same as OPERR
2613#       DZ      : same as OPERR
2614#       INEX2   : same as OPERR
2615#       INEX1   : all packed immediate operations
2616#
2617
2618# we determine the highest priority exception(if any) set by the
2619# emulation routine that has also been enabled by the user.
2620        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions enabled
2621        bne.b           iea_op_ena              # some are enabled
2622
2623# now, we save the result, unless, of course, the operation was ftst or fcmp.
2624# these don't save results.
2625iea_op_save:
2626        tst.b           STORE_FLG(%a6)          # does this op store a result?
2627        bne.b           iea_op_exit1            # exit with no frestore
2628
2629iea_op_store:
2630        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno
2631        bsr.l           store_fpreg             # store the result
2632
2633iea_op_exit1:
2634        mov.l           EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC"
2635        mov.l           EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame
2636
2637        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
2638        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2639        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2640
2641        unlk            %a6                     # unravel the frame
2642
2643        btst            &0x7,(%sp)              # is trace on?
2644        bne.w           iea_op_trace            # yes
2645
2646        bra.l           _fpsp_done              # exit to os
2647
2648iea_op_ena:
2649        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enable and set
2650        bfffo           %d0{&24:&8},%d0         # find highest priority exception
2651        bne.b           iea_op_exc              # at least one was set
2652
2653# no exception occurred. now, did a disabled, exact overflow occur with inexact
2654# enabled? if so, then we have to stuff an overflow frame into the FPU.
2655        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur?
2656        beq.b           iea_op_save
2657
2658iea_op_ovfl:
2659        btst            &inex2_bit,FPCR_ENABLE(%a6) # is inexact enabled?
2660        beq.b           iea_op_store            # no
2661        bra.b           iea_op_exc_ovfl         # yes
2662
2663# an enabled exception occurred. we have to insert the exception type back into
2664# the machine.
2665iea_op_exc:
2666        subi.l          &24,%d0                 # fix offset to be 0-8
2667        cmpi.b          %d0,&0x6                # is exception INEX?
2668        bne.b           iea_op_exc_force        # no
2669
2670# the enabled exception was inexact. so, if it occurs with an overflow
2671# or underflow that was disabled, then we have to force an overflow or
2672# underflow frame.
2673        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur?
2674        bne.b           iea_op_exc_ovfl         # yes
2675        btst            &unfl_bit,FPSR_EXCEPT(%a6) # did underflow occur?
2676        bne.b           iea_op_exc_unfl         # yes
2677
2678iea_op_exc_force:
2679        mov.w           (tbl_iea_except.b,%pc,%d0.w*2),2+FP_SRC(%a6)
2680        bra.b           iea_op_exit2            # exit with frestore
2681
2682tbl_iea_except:
2683        short           0xe002, 0xe006, 0xe004, 0xe005
2684        short           0xe003, 0xe002, 0xe001, 0xe001
2685
2686iea_op_exc_ovfl:
2687        mov.w           &0xe005,2+FP_SRC(%a6)
2688        bra.b           iea_op_exit2
2689
2690iea_op_exc_unfl:
2691        mov.w           &0xe003,2+FP_SRC(%a6)
2692
2693iea_op_exit2:
2694        mov.l           EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC"
2695        mov.l           EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame
2696
2697        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
2698        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2699        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2700
2701        frestore        FP_SRC(%a6)             # restore exceptional state
2702
2703        unlk            %a6                     # unravel the frame
2704
2705        btst            &0x7,(%sp)              # is trace on?
2706        bne.b           iea_op_trace            # yes
2707
2708        bra.l           _fpsp_done              # exit to os
2709
2710#
2711# The opclass two instruction that took an "Unimplemented Effective Address"
2712# exception was being traced. Make the "current" PC the FPIAR and put it in
2713# the trace stack frame then jump to _real_trace().
2714#
2715#                UNIMP EA FRAME            TRACE FRAME
2716#               *****************       *****************
2717#               * 0x0 *  0x0f0  *       *    Current    *
2718#               *****************       *      PC       *
2719#               *    Current    *       *****************
2720#               *      PC       *       * 0x2 *  0x024  *
2721#               *****************       *****************
2722#               *      SR       *       *     Next      *
2723#               *****************       *      PC       *
2724#                                       *****************
2725#                                       *      SR       *
2726#                                       *****************
2727iea_op_trace:
2728        mov.l           (%sp),-(%sp)            # shift stack frame "down"
2729        mov.w           0x8(%sp),0x4(%sp)
2730        mov.w           &0x2024,0x6(%sp)        # stk fmt = 0x2; voff = 0x024
2731        fmov.l          %fpiar,0x8(%sp)         # "Current PC" is in FPIAR
2732
2733        bra.l           _real_trace
2734
2735#########################################################################
2736iea_fmovm:
2737        btst            &14,%d0                 # ctrl or data reg
2738        beq.w           iea_fmovm_ctrl
2739
2740iea_fmovm_data:
2741
2742        btst            &0x5,EXC_SR(%a6)        # user or supervisor mode
2743        bne.b           iea_fmovm_data_s
2744
2745iea_fmovm_data_u:
2746        mov.l           %usp,%a0
2747        mov.l           %a0,EXC_A7(%a6)         # store current a7
2748        bsr.l           fmovm_dynamic           # do dynamic fmovm
2749        mov.l           EXC_A7(%a6),%a0         # load possibly new a7
2750        mov.l           %a0,%usp                # update usp
2751        bra.w           iea_fmovm_exit
2752
2753iea_fmovm_data_s:
2754        clr.b           SPCOND_FLG(%a6)
2755        lea             0x2+EXC_VOFF(%a6),%a0
2756        mov.l           %a0,EXC_A7(%a6)
2757        bsr.l           fmovm_dynamic           # do dynamic fmovm
2758
2759        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
2760        beq.w           iea_fmovm_data_predec
2761        cmpi.b          SPCOND_FLG(%a6),&mia7_flg
2762        bne.w           iea_fmovm_exit
2763
2764# right now, d0 = the size.
2765# the data has been fetched from the supervisor stack, but we have not
2766# incremented the stack pointer by the appropriate number of bytes.
2767# do it here.
2768iea_fmovm_data_postinc:
2769        btst            &0x7,EXC_SR(%a6)
2770        bne.b           iea_fmovm_data_pi_trace
2771
2772        mov.w           EXC_SR(%a6),(EXC_SR,%a6,%d0)
2773        mov.l           EXC_EXTWPTR(%a6),(EXC_PC,%a6,%d0)
2774        mov.w           &0x00f0,(EXC_VOFF,%a6,%d0)
2775
2776        lea             (EXC_SR,%a6,%d0),%a0
2777        mov.l           %a0,EXC_SR(%a6)
2778
2779        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
2780        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2781        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2782
2783        unlk            %a6
2784        mov.l           (%sp)+,%sp
2785        bra.l           _fpsp_done
2786
2787iea_fmovm_data_pi_trace:
2788        mov.w           EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0)
2789        mov.l           EXC_EXTWPTR(%a6),(EXC_PC-0x4,%a6,%d0)
2790        mov.w           &0x2024,(EXC_VOFF-0x4,%a6,%d0)
2791        mov.l           EXC_PC(%a6),(EXC_VOFF+0x2-0x4,%a6,%d0)
2792
2793        lea             (EXC_SR-0x4,%a6,%d0),%a0
2794        mov.l           %a0,EXC_SR(%a6)
2795
2796        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
2797        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2798        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2799
2800        unlk            %a6
2801        mov.l           (%sp)+,%sp
2802        bra.l           _real_trace
2803
2804# right now, d1 = size and d0 = the strg.
2805iea_fmovm_data_predec:
2806        mov.b           %d1,EXC_VOFF(%a6)       # store strg
2807        mov.b           %d0,0x1+EXC_VOFF(%a6)   # store size
2808
2809        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
2810        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2811        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2812
2813        mov.l           (%a6),-(%sp)            # make a copy of a6
2814        mov.l           %d0,-(%sp)              # save d0
2815        mov.l           %d1,-(%sp)              # save d1
2816        mov.l           EXC_EXTWPTR(%a6),-(%sp) # make a copy of Next PC
2817
2818        clr.l           %d0
2819        mov.b           0x1+EXC_VOFF(%a6),%d0   # fetch size
2820        neg.l           %d0                     # get negative of size
2821
2822        btst            &0x7,EXC_SR(%a6)        # is trace enabled?
2823        beq.b           iea_fmovm_data_p2
2824
2825        mov.w           EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0)
2826        mov.l           EXC_PC(%a6),(EXC_VOFF-0x2,%a6,%d0)
2827        mov.l           (%sp)+,(EXC_PC-0x4,%a6,%d0)
2828        mov.w           &0x2024,(EXC_VOFF-0x4,%a6,%d0)
2829
2830        pea             (%a6,%d0)               # create final sp
2831        bra.b           iea_fmovm_data_p3
2832
2833iea_fmovm_data_p2:
2834        mov.w           EXC_SR(%a6),(EXC_SR,%a6,%d0)
2835        mov.l           (%sp)+,(EXC_PC,%a6,%d0)
2836        mov.w           &0x00f0,(EXC_VOFF,%a6,%d0)
2837
2838        pea             (0x4,%a6,%d0)           # create final sp
2839
2840iea_fmovm_data_p3:
2841        clr.l           %d1
2842        mov.b           EXC_VOFF(%a6),%d1       # fetch strg
2843
2844        tst.b           %d1
2845        bpl.b           fm_1
2846        fmovm.x         &0x80,(0x4+0x8,%a6,%d0)
2847        addi.l          &0xc,%d0
2848fm_1:
2849        lsl.b           &0x1,%d1
2850        bpl.b           fm_2
2851        fmovm.x         &0x40,(0x4+0x8,%a6,%d0)
2852        addi.l          &0xc,%d0
2853fm_2:
2854        lsl.b           &0x1,%d1
2855        bpl.b           fm_3
2856        fmovm.x         &0x20,(0x4+0x8,%a6,%d0)
2857        addi.l          &0xc,%d0
2858fm_3:
2859        lsl.b           &0x1,%d1
2860        bpl.b           fm_4
2861        fmovm.x         &0x10,(0x4+0x8,%a6,%d0)
2862        addi.l          &0xc,%d0
2863fm_4:
2864        lsl.b           &0x1,%d1
2865        bpl.b           fm_5
2866        fmovm.x         &0x08,(0x4+0x8,%a6,%d0)
2867        addi.l          &0xc,%d0
2868fm_5:
2869        lsl.b           &0x1,%d1
2870        bpl.b           fm_6
2871        fmovm.x         &0x04,(0x4+0x8,%a6,%d0)
2872        addi.l          &0xc,%d0
2873fm_6:
2874        lsl.b           &0x1,%d1
2875        bpl.b           fm_7
2876        fmovm.x         &0x02,(0x4+0x8,%a6,%d0)
2877        addi.l          &0xc,%d0
2878fm_7:
2879        lsl.b           &0x1,%d1
2880        bpl.b           fm_end
2881        fmovm.x         &0x01,(0x4+0x8,%a6,%d0)
2882fm_end:
2883        mov.l           0x4(%sp),%d1
2884        mov.l           0x8(%sp),%d0
2885        mov.l           0xc(%sp),%a6
2886        mov.l           (%sp)+,%sp
2887
2888        btst            &0x7,(%sp)              # is trace enabled?
2889        beq.l           _fpsp_done
2890        bra.l           _real_trace
2891
2892#########################################################################
2893iea_fmovm_ctrl:
2894
2895        bsr.l           fmovm_ctrl              # load ctrl regs
2896
2897iea_fmovm_exit:
2898        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
2899        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2900        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2901
2902        btst            &0x7,EXC_SR(%a6)        # is trace on?
2903        bne.b           iea_fmovm_trace         # yes
2904
2905        mov.l           EXC_EXTWPTR(%a6),EXC_PC(%a6) # set Next PC
2906
2907        unlk            %a6                     # unravel the frame
2908
2909        bra.l           _fpsp_done              # exit to os
2910
2911#
2912# The control reg instruction that took an "Unimplemented Effective Address"
2913# exception was being traced. The "Current PC" for the trace frame is the
2914# PC stacked for Unimp EA. The "Next PC" is in EXC_EXTWPTR.
2915# After fixing the stack frame, jump to _real_trace().
2916#
2917#                UNIMP EA FRAME            TRACE FRAME
2918#               *****************       *****************
2919#               * 0x0 *  0x0f0  *       *    Current    *
2920#               *****************       *      PC       *
2921#               *    Current    *       *****************
2922#               *      PC       *       * 0x2 *  0x024  *
2923#               *****************       *****************
2924#               *      SR       *       *     Next      *
2925#               *****************       *      PC       *
2926#                                       *****************
2927#                                       *      SR       *
2928#                                       *****************
2929# this ain't a pretty solution, but it works:
2930# -restore a6 (not with unlk)
2931# -shift stack frame down over where old a6 used to be
2932# -add LOCAL_SIZE to stack pointer
2933iea_fmovm_trace:
2934        mov.l           (%a6),%a6               # restore frame pointer
2935        mov.w           EXC_SR+LOCAL_SIZE(%sp),0x0+LOCAL_SIZE(%sp)
2936        mov.l           EXC_PC+LOCAL_SIZE(%sp),0x8+LOCAL_SIZE(%sp)
2937        mov.l           EXC_EXTWPTR+LOCAL_SIZE(%sp),0x2+LOCAL_SIZE(%sp)
2938        mov.w           &0x2024,0x6+LOCAL_SIZE(%sp) # stk fmt = 0x2; voff = 0x024
2939        add.l           &LOCAL_SIZE,%sp         # clear stack frame
2940
2941        bra.l           _real_trace
2942
2943#########################################################################
2944# The FPU is disabled and so we should really have taken the "Line
2945# F Emulator" exception. So, here we create an 8-word stack frame
2946# from our 4-word stack frame. This means we must calculate the length
2947# the faulting instruction to get the "next PC". This is trivial for
2948# immediate operands but requires some extra work for fmovm dynamic
2949# which can use most addressing modes.
2950iea_disabled:
2951        mov.l           (%sp)+,%d0              # restore d0
2952
2953        link            %a6,&-LOCAL_SIZE        # init stack frame
2954
2955        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
2956
2957# PC of instruction that took the exception is the PC in the frame
2958        mov.l           EXC_PC(%a6),EXC_EXTWPTR(%a6)
2959        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
2960        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
2961        bsr.l           _imem_read_long         # fetch the instruction words
2962        mov.l           %d0,EXC_OPWORD(%a6)     # store OPWORD and EXTWORD
2963
2964        tst.w           %d0                     # is instr fmovm?
2965        bmi.b           iea_dis_fmovm           # yes
2966# instruction is using an extended precision immediate operand. Therefore,
2967# the total instruction length is 16 bytes.
2968iea_dis_immed:
2969        mov.l           &0x10,%d0               # 16 bytes of instruction
2970        bra.b           iea_dis_cont
2971iea_dis_fmovm:
2972        btst            &0xe,%d0                # is instr fmovm ctrl
2973        bne.b           iea_dis_fmovm_data      # no
2974# the instruction is a fmovm.l with 2 or 3 registers.
2975        bfextu          %d0{&19:&3},%d1
2976        mov.l           &0xc,%d0
2977        cmpi.b          %d1,&0x7                # move all regs?
2978        bne.b           iea_dis_cont
2979        addq.l          &0x4,%d0
2980        bra.b           iea_dis_cont
2981# the instruction is an fmovm.x dynamic which can use many addressing
2982# modes and thus can have several different total instruction lengths.
2983# call fmovm_calc_ea which will go through the ea calc process and,
2984# as a by-product, will tell us how long the instruction is.
2985iea_dis_fmovm_data:
2986        clr.l           %d0
2987        bsr.l           fmovm_calc_ea
2988        mov.l           EXC_EXTWPTR(%a6),%d0
2989        sub.l           EXC_PC(%a6),%d0
2990iea_dis_cont:
2991        mov.w           %d0,EXC_VOFF(%a6)       # store stack shift value
2992
2993        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2994
2995        unlk            %a6
2996
2997# here, we actually create the 8-word frame from the 4-word frame,
2998# with the "next PC" as additional info.
2999# the <ea> field is let as undefined.
3000        subq.l          &0x8,%sp                # make room for new stack
3001        mov.l           %d0,-(%sp)              # save d0
3002        mov.w           0xc(%sp),0x4(%sp)       # move SR
3003        mov.l           0xe(%sp),0x6(%sp)       # move Current PC
3004        clr.l           %d0
3005        mov.w           0x12(%sp),%d0
3006        mov.l           0x6(%sp),0x10(%sp)      # move Current PC
3007        add.l           %d0,0x6(%sp)            # make Next PC
3008        mov.w           &0x402c,0xa(%sp)        # insert offset,frame format
3009        mov.l           (%sp)+,%d0              # restore d0
3010
3011        bra.l           _real_fpu_disabled
3012
3013##########
3014
3015iea_iacc:
3016        movc            %pcr,%d0
3017        btst            &0x1,%d0
3018        bne.b           iea_iacc_cont
3019        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3020        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1 on stack
3021iea_iacc_cont:
3022        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3023
3024        unlk            %a6
3025
3026        subq.w          &0x8,%sp                # make stack frame bigger
3027        mov.l           0x8(%sp),(%sp)          # store SR,hi(PC)
3028        mov.w           0xc(%sp),0x4(%sp)       # store lo(PC)
3029        mov.w           &0x4008,0x6(%sp)        # store voff
3030        mov.l           0x2(%sp),0x8(%sp)       # store ea
3031        mov.l           &0x09428001,0xc(%sp)    # store fslw
3032
3033iea_acc_done:
3034        btst            &0x5,(%sp)              # user or supervisor mode?
3035        beq.b           iea_acc_done2           # user
3036        bset            &0x2,0xd(%sp)           # set supervisor TM bit
3037
3038iea_acc_done2:
3039        bra.l           _real_access
3040
3041iea_dacc:
3042        lea             -LOCAL_SIZE(%a6),%sp
3043
3044        movc            %pcr,%d1
3045        btst            &0x1,%d1
3046        bne.b           iea_dacc_cont
3047        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1 on stack
3048        fmovm.l         LOCAL_SIZE+USER_FPCR(%sp),%fpcr,%fpsr,%fpiar # restore ctrl regs
3049iea_dacc_cont:
3050        mov.l           (%a6),%a6
3051
3052        mov.l           0x4+LOCAL_SIZE(%sp),-0x8+0x4+LOCAL_SIZE(%sp)
3053        mov.w           0x8+LOCAL_SIZE(%sp),-0x8+0x8+LOCAL_SIZE(%sp)
3054        mov.w           &0x4008,-0x8+0xa+LOCAL_SIZE(%sp)
3055        mov.l           %a0,-0x8+0xc+LOCAL_SIZE(%sp)
3056        mov.w           %d0,-0x8+0x10+LOCAL_SIZE(%sp)
3057        mov.w           &0x0001,-0x8+0x12+LOCAL_SIZE(%sp)
3058
3059        movm.l          LOCAL_SIZE+EXC_DREGS(%sp),&0x0303 # restore d0-d1/a0-a1
3060        add.w           &LOCAL_SIZE-0x4,%sp
3061
3062        bra.b           iea_acc_done
3063
3064#########################################################################
3065# XDEF **************************************************************** #
3066#       _fpsp_operr(): 060FPSP entry point for FP Operr exception.      #
3067#                                                                       #
3068#       This handler should be the first code executed upon taking the  #
3069#       FP Operand Error exception in an operating system.              #
3070#                                                                       #
3071# XREF **************************************************************** #
3072#       _imem_read_long() - read instruction longword                   #
3073#       fix_skewed_ops() - adjust src operand in fsave frame            #
3074#       _real_operr() - "callout" to operating system operr handler     #
3075#       _dmem_write_{byte,word,long}() - store data to mem (opclass 3)  #
3076#       store_dreg_{b,w,l}() - store data to data regfile (opclass 3)   #
3077#       facc_out_{b,w,l}() - store to memory took access error (opcl 3) #
3078#                                                                       #
3079# INPUT *************************************************************** #
3080#       - The system stack contains the FP Operr exception frame        #
3081#       - The fsave frame contains the source operand                   #
3082#                                                                       #
3083# OUTPUT ************************************************************** #
3084#       No access error:                                                #
3085#       - The system stack is unchanged                                 #
3086#       - The fsave frame contains the adjusted src op for opclass 0,2  #
3087#                                                                       #
3088# ALGORITHM *********************************************************** #
3089#       In a system where the FP Operr exception is enabled, the goal   #
3090# is to get to the handler specified at _real_operr(). But, on the 060, #
3091# for opclass zero and two instruction taking this exception, the       #
3092# input operand in the fsave frame may be incorrect for some cases      #
3093# and needs to be corrected. This handler calls fix_skewed_ops() to     #
3094# do just this and then exits through _real_operr().                    #
3095#       For opclass 3 instructions, the 060 doesn't store the default   #
3096# operr result out to memory or data register file as it should.        #
3097# This code must emulate the move out before finally exiting through    #
3098# _real_inex(). The move out, if to memory, is performed using          #
3099# _mem_write() "callout" routines that may return a failing result.     #
3100# In this special case, the handler must exit through facc_out()        #
3101# which creates an access error stack frame from the current operr      #
3102# stack frame.                                                          #
3103#                                                                       #
3104#########################################################################
3105
3106        global          _fpsp_operr
3107_fpsp_operr:
3108
3109        link.w          %a6,&-LOCAL_SIZE        # init stack frame
3110
3111        fsave           FP_SRC(%a6)             # grab the "busy" frame
3112
3113        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3114        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3115        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
3116
3117# the FPIAR holds the "current PC" of the faulting instruction
3118        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3119
3120        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3121        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3122        bsr.l           _imem_read_long         # fetch the instruction words
3123        mov.l           %d0,EXC_OPWORD(%a6)
3124
3125##############################################################################
3126
3127        btst            &13,%d0                 # is instr an fmove out?
3128        bne.b           foperr_out              # fmove out
3129
3130
3131# here, we simply see if the operand in the fsave frame needs to be "unskewed".
3132# this would be the case for opclass two operations with a source infinity or
3133# denorm operand in the sgl or dbl format. NANs also become skewed, but can't
3134# cause an operr so we don't need to check for them here.
3135        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3136        bsr.l           fix_skewed_ops          # fix src op
3137
3138foperr_exit:
3139        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3140        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3141        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3142
3143        frestore        FP_SRC(%a6)
3144
3145        unlk            %a6
3146        bra.l           _real_operr
3147
3148########################################################################
3149
3150#
3151# the hardware does not save the default result to memory on enabled
3152# operand error exceptions. we do this here before passing control to
3153# the user operand error handler.
3154#
3155# byte, word, and long destination format operations can pass
3156# through here. we simply need to test the sign of the src
3157# operand and save the appropriate minimum or maximum integer value
3158# to the effective address as pointed to by the stacked effective address.
3159#
3160# although packed opclass three operations can take operand error
3161# exceptions, they won't pass through here since they are caught
3162# first by the unsupported data format exception handler. that handler
3163# sends them directly to _real_operr() if necessary.
3164#
3165foperr_out:
3166
3167        mov.w           FP_SRC_EX(%a6),%d1      # fetch exponent
3168        andi.w          &0x7fff,%d1
3169        cmpi.w          %d1,&0x7fff
3170        bne.b           foperr_out_not_qnan
3171# the operand is either an infinity or a QNAN.
3172        tst.l           FP_SRC_LO(%a6)
3173        bne.b           foperr_out_qnan
3174        mov.l           FP_SRC_HI(%a6),%d1
3175        andi.l          &0x7fffffff,%d1
3176        beq.b           foperr_out_not_qnan
3177foperr_out_qnan:
3178        mov.l           FP_SRC_HI(%a6),L_SCR1(%a6)
3179        bra.b           foperr_out_jmp
3180
3181foperr_out_not_qnan:
3182        mov.l           &0x7fffffff,%d1
3183        tst.b           FP_SRC_EX(%a6)
3184        bpl.b           foperr_out_not_qnan2
3185        addq.l          &0x1,%d1
3186foperr_out_not_qnan2:
3187        mov.l           %d1,L_SCR1(%a6)
3188
3189foperr_out_jmp:
3190        bfextu          %d0{&19:&3},%d0         # extract dst format field
3191        mov.b           1+EXC_OPWORD(%a6),%d1   # extract <ea> mode,reg
3192        mov.w           (tbl_operr.b,%pc,%d0.w*2),%a0
3193        jmp             (tbl_operr.b,%pc,%a0)
3194
3195tbl_operr:
3196        short           foperr_out_l - tbl_operr # long word integer
3197        short           tbl_operr    - tbl_operr # sgl prec shouldn't happen
3198        short           tbl_operr    - tbl_operr # ext prec shouldn't happen
3199        short           foperr_exit  - tbl_operr # packed won't enter here
3200        short           foperr_out_w - tbl_operr # word integer
3201        short           tbl_operr    - tbl_operr # dbl prec shouldn't happen
3202        short           foperr_out_b - tbl_operr # byte integer
3203        short           tbl_operr    - tbl_operr # packed won't enter here
3204
3205foperr_out_b:
3206        mov.b           L_SCR1(%a6),%d0         # load positive default result
3207        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3208        ble.b           foperr_out_b_save_dn    # yes
3209        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3210        bsr.l           _dmem_write_byte        # write the default result
3211
3212        tst.l           %d1                     # did dstore fail?
3213        bne.l           facc_out_b              # yes
3214
3215        bra.w           foperr_exit
3216foperr_out_b_save_dn:
3217        andi.w          &0x0007,%d1
3218        bsr.l           store_dreg_b            # store result to regfile
3219        bra.w           foperr_exit
3220
3221foperr_out_w:
3222        mov.w           L_SCR1(%a6),%d0         # load positive default result
3223        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3224        ble.b           foperr_out_w_save_dn    # yes
3225        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3226        bsr.l           _dmem_write_word        # write the default result
3227
3228        tst.l           %d1                     # did dstore fail?
3229        bne.l           facc_out_w              # yes
3230
3231        bra.w           foperr_exit
3232foperr_out_w_save_dn:
3233        andi.w          &0x0007,%d1
3234        bsr.l           store_dreg_w            # store result to regfile
3235        bra.w           foperr_exit
3236
3237foperr_out_l:
3238        mov.l           L_SCR1(%a6),%d0         # load positive default result
3239        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3240        ble.b           foperr_out_l_save_dn    # yes
3241        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3242        bsr.l           _dmem_write_long        # write the default result
3243
3244        tst.l           %d1                     # did dstore fail?
3245        bne.l           facc_out_l              # yes
3246
3247        bra.w           foperr_exit
3248foperr_out_l_save_dn:
3249        andi.w          &0x0007,%d1
3250        bsr.l           store_dreg_l            # store result to regfile
3251        bra.w           foperr_exit
3252
3253#########################################################################
3254# XDEF **************************************************************** #
3255#       _fpsp_snan(): 060FPSP entry point for FP SNAN exception.        #
3256#                                                                       #
3257#       This handler should be the first code executed upon taking the  #
3258#       FP Signalling NAN exception in an operating system.             #
3259#                                                                       #
3260# XREF **************************************************************** #
3261#       _imem_read_long() - read instruction longword                   #
3262#       fix_skewed_ops() - adjust src operand in fsave frame            #
3263#       _real_snan() - "callout" to operating system SNAN handler       #
3264#       _dmem_write_{byte,word,long}() - store data to mem (opclass 3)  #
3265#       store_dreg_{b,w,l}() - store data to data regfile (opclass 3)   #
3266#       facc_out_{b,w,l,d,x}() - store to mem took acc error (opcl 3)   #
3267#       _calc_ea_fout() - fix An if <ea> is -() or ()+; also get <ea>   #
3268#                                                                       #
3269# INPUT *************************************************************** #
3270#       - The system stack contains the FP SNAN exception frame         #
3271#       - The fsave frame contains the source operand                   #
3272#                                                                       #
3273# OUTPUT ************************************************************** #
3274#       No access error:                                                #
3275#       - The system stack is unchanged                                 #
3276#       - The fsave frame contains the adjusted src op for opclass 0,2  #
3277#                                                                       #
3278# ALGORITHM *********************************************************** #
3279#       In a system where the FP SNAN exception is enabled, the goal    #
3280# is to get to the handler specified at _real_snan(). But, on the 060,  #
3281# for opclass zero and two instructions taking this exception, the      #
3282# input operand in the fsave frame may be incorrect for some cases      #
3283# and needs to be corrected. This handler calls fix_skewed_ops() to     #
3284# do just this and then exits through _real_snan().                     #
3285#       For opclass 3 instructions, the 060 doesn't store the default   #
3286# SNAN result out to memory or data register file as it should.         #
3287# This code must emulate the move out before finally exiting through    #
3288# _real_snan(). The move out, if to memory, is performed using          #
3289# _mem_write() "callout" routines that may return a failing result.     #
3290# In this special case, the handler must exit through facc_out()        #
3291# which creates an access error stack frame from the current SNAN       #
3292# stack frame.                                                          #
3293#       For the case of an extended precision opclass 3 instruction,    #
3294# if the effective addressing mode was -() or ()+, then the address     #
3295# register must get updated by calling _calc_ea_fout(). If the <ea>     #
3296# was -(a7) from supervisor mode, then the exception frame currently    #
3297# on the system stack must be carefully moved "down" to make room       #
3298# for the operand being moved.                                          #
3299#                                                                       #
3300#########################################################################
3301
3302        global          _fpsp_snan
3303_fpsp_snan:
3304
3305        link.w          %a6,&-LOCAL_SIZE        # init stack frame
3306
3307        fsave           FP_SRC(%a6)             # grab the "busy" frame
3308
3309        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3310        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3311        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
3312
3313# the FPIAR holds the "current PC" of the faulting instruction
3314        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3315
3316        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3317        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3318        bsr.l           _imem_read_long         # fetch the instruction words
3319        mov.l           %d0,EXC_OPWORD(%a6)
3320
3321##############################################################################
3322
3323        btst            &13,%d0                 # is instr an fmove out?
3324        bne.w           fsnan_out               # fmove out
3325
3326
3327# here, we simply see if the operand in the fsave frame needs to be "unskewed".
3328# this would be the case for opclass two operations with a source infinity or
3329# denorm operand in the sgl or dbl format. NANs also become skewed and must be
3330# fixed here.
3331        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3332        bsr.l           fix_skewed_ops          # fix src op
3333
3334fsnan_exit:
3335        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3336        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3337        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3338
3339        frestore        FP_SRC(%a6)
3340
3341        unlk            %a6
3342        bra.l           _real_snan
3343
3344########################################################################
3345
3346#
3347# the hardware does not save the default result to memory on enabled
3348# snan exceptions. we do this here before passing control to
3349# the user snan handler.
3350#
3351# byte, word, long, and packed destination format operations can pass
3352# through here. since packed format operations already were handled by
3353# fpsp_unsupp(), then we need to do nothing else for them here.
3354# for byte, word, and long, we simply need to test the sign of the src
3355# operand and save the appropriate minimum or maximum integer value
3356# to the effective address as pointed to by the stacked effective address.
3357#
3358fsnan_out:
3359
3360        bfextu          %d0{&19:&3},%d0         # extract dst format field
3361        mov.b           1+EXC_OPWORD(%a6),%d1   # extract <ea> mode,reg
3362        mov.w           (tbl_snan.b,%pc,%d0.w*2),%a0
3363        jmp             (tbl_snan.b,%pc,%a0)
3364
3365tbl_snan:
3366        short           fsnan_out_l - tbl_snan # long word integer
3367        short           fsnan_out_s - tbl_snan # sgl prec shouldn't happen
3368        short           fsnan_out_x - tbl_snan # ext prec shouldn't happen
3369        short           tbl_snan    - tbl_snan # packed needs no help
3370        short           fsnan_out_w - tbl_snan # word integer
3371        short           fsnan_out_d - tbl_snan # dbl prec shouldn't happen
3372        short           fsnan_out_b - tbl_snan # byte integer
3373        short           tbl_snan    - tbl_snan # packed needs no help
3374
3375fsnan_out_b:
3376        mov.b           FP_SRC_HI(%a6),%d0      # load upper byte of SNAN
3377        bset            &6,%d0                  # set SNAN bit
3378        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3379        ble.b           fsnan_out_b_dn          # yes
3380        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3381        bsr.l           _dmem_write_byte        # write the default result
3382
3383        tst.l           %d1                     # did dstore fail?
3384        bne.l           facc_out_b              # yes
3385
3386        bra.w           fsnan_exit
3387fsnan_out_b_dn:
3388        andi.w          &0x0007,%d1
3389        bsr.l           store_dreg_b            # store result to regfile
3390        bra.w           fsnan_exit
3391
3392fsnan_out_w:
3393        mov.w           FP_SRC_HI(%a6),%d0      # load upper word of SNAN
3394        bset            &14,%d0                 # set SNAN bit
3395        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3396        ble.b           fsnan_out_w_dn          # yes
3397        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3398        bsr.l           _dmem_write_word        # write the default result
3399
3400        tst.l           %d1                     # did dstore fail?
3401        bne.l           facc_out_w              # yes
3402
3403        bra.w           fsnan_exit
3404fsnan_out_w_dn:
3405        andi.w          &0x0007,%d1
3406        bsr.l           store_dreg_w            # store result to regfile
3407        bra.w           fsnan_exit
3408
3409fsnan_out_l:
3410        mov.l           FP_SRC_HI(%a6),%d0      # load upper longword of SNAN
3411        bset            &30,%d0                 # set SNAN bit
3412        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3413        ble.b           fsnan_out_l_dn          # yes
3414        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3415        bsr.l           _dmem_write_long        # write the default result
3416
3417        tst.l           %d1                     # did dstore fail?
3418        bne.l           facc_out_l              # yes
3419
3420        bra.w           fsnan_exit
3421fsnan_out_l_dn:
3422        andi.w          &0x0007,%d1
3423        bsr.l           store_dreg_l            # store result to regfile
3424        bra.w           fsnan_exit
3425
3426fsnan_out_s:
3427        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3428        ble.b           fsnan_out_d_dn          # yes
3429        mov.l           FP_SRC_EX(%a6),%d0      # fetch SNAN sign
3430        andi.l          &0x80000000,%d0         # keep sign
3431        ori.l           &0x7fc00000,%d0         # insert new exponent,SNAN bit
3432        mov.l           FP_SRC_HI(%a6),%d1      # load mantissa
3433        lsr.l           &0x8,%d1                # shift mantissa for sgl
3434        or.l            %d1,%d0                 # create sgl SNAN
3435        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3436        bsr.l           _dmem_write_long        # write the default result
3437
3438        tst.l           %d1                     # did dstore fail?
3439        bne.l           facc_out_l              # yes
3440
3441        bra.w           fsnan_exit
3442fsnan_out_d_dn:
3443        mov.l           FP_SRC_EX(%a6),%d0      # fetch SNAN sign
3444        andi.l          &0x80000000,%d0         # keep sign
3445        ori.l           &0x7fc00000,%d0         # insert new exponent,SNAN bit
3446        mov.l           %d1,-(%sp)
3447        mov.l           FP_SRC_HI(%a6),%d1      # load mantissa
3448        lsr.l           &0x8,%d1                # shift mantissa for sgl
3449        or.l            %d1,%d0                 # create sgl SNAN
3450        mov.l           (%sp)+,%d1
3451        andi.w          &0x0007,%d1
3452        bsr.l           store_dreg_l            # store result to regfile
3453        bra.w           fsnan_exit
3454
3455fsnan_out_d:
3456        mov.l           FP_SRC_EX(%a6),%d0      # fetch SNAN sign
3457        andi.l          &0x80000000,%d0         # keep sign
3458        ori.l           &0x7ff80000,%d0         # insert new exponent,SNAN bit
3459        mov.l           FP_SRC_HI(%a6),%d1      # load hi mantissa
3460        mov.l           %d0,FP_SCR0_EX(%a6)     # store to temp space
3461        mov.l           &11,%d0                 # load shift amt
3462        lsr.l           %d0,%d1
3463        or.l            %d1,FP_SCR0_EX(%a6)     # create dbl hi
3464        mov.l           FP_SRC_HI(%a6),%d1      # load hi mantissa
3465        andi.l          &0x000007ff,%d1
3466        ror.l           %d0,%d1
3467        mov.l           %d1,FP_SCR0_HI(%a6)     # store to temp space
3468        mov.l           FP_SRC_LO(%a6),%d1      # load lo mantissa
3469        lsr.l           %d0,%d1
3470        or.l            %d1,FP_SCR0_HI(%a6)     # create dbl lo
3471        lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
3472        mov.l           EXC_EA(%a6),%a1         # pass: dst addr
3473        movq.l          &0x8,%d0                # pass: size of 8 bytes
3474        bsr.l           _dmem_write             # write the default result
3475
3476        tst.l           %d1                     # did dstore fail?
3477        bne.l           facc_out_d              # yes
3478
3479        bra.w           fsnan_exit
3480
3481# for extended precision, if the addressing mode is pre-decrement or
3482# post-increment, then the address register did not get updated.
3483# in addition, for pre-decrement, the stacked <ea> is incorrect.
3484fsnan_out_x:
3485        clr.b           SPCOND_FLG(%a6)         # clear special case flag
3486
3487        mov.w           FP_SRC_EX(%a6),FP_SCR0_EX(%a6)
3488        clr.w           2+FP_SCR0(%a6)
3489        mov.l           FP_SRC_HI(%a6),%d0
3490        bset            &30,%d0
3491        mov.l           %d0,FP_SCR0_HI(%a6)
3492        mov.l           FP_SRC_LO(%a6),FP_SCR0_LO(%a6)
3493
3494        btst            &0x5,EXC_SR(%a6)        # supervisor mode exception?
3495        bne.b           fsnan_out_x_s           # yes
3496
3497        mov.l           %usp,%a0                # fetch user stack pointer
3498        mov.l           %a0,EXC_A7(%a6)         # save on stack for calc_ea()
3499        mov.l           (%a6),EXC_A6(%a6)
3500
3501        bsr.l           _calc_ea_fout           # find the correct ea,update An
3502        mov.l           %a0,%a1
3503        mov.l           %a0,EXC_EA(%a6)         # stack correct <ea>
3504
3505        mov.l           EXC_A7(%a6),%a0
3506        mov.l           %a0,%usp                # restore user stack pointer
3507        mov.l           EXC_A6(%a6),(%a6)
3508
3509fsnan_out_x_save:
3510        lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
3511        movq.l          &0xc,%d0                # pass: size of extended
3512        bsr.l           _dmem_write             # write the default result
3513
3514        tst.l           %d1                     # did dstore fail?
3515        bne.l           facc_out_x              # yes
3516
3517        bra.w           fsnan_exit
3518
3519fsnan_out_x_s:
3520        mov.l           (%a6),EXC_A6(%a6)
3521
3522        bsr.l           _calc_ea_fout           # find the correct ea,update An
3523        mov.l           %a0,%a1
3524        mov.l           %a0,EXC_EA(%a6)         # stack correct <ea>
3525
3526        mov.l           EXC_A6(%a6),(%a6)
3527
3528        cmpi.b          SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)?
3529        bne.b           fsnan_out_x_save        # no
3530
3531# the operation was "fmove.x SNAN,-(a7)" from supervisor mode.
3532        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3533        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3534        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3535
3536        frestore        FP_SRC(%a6)
3537
3538        mov.l           EXC_A6(%a6),%a6         # restore frame pointer
3539
3540        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
3541        mov.l           LOCAL_SIZE+EXC_PC+0x2(%sp),LOCAL_SIZE+EXC_PC+0x2-0xc(%sp)
3542        mov.l           LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
3543
3544        mov.l           LOCAL_SIZE+FP_SCR0_EX(%sp),LOCAL_SIZE+EXC_SR(%sp)
3545        mov.l           LOCAL_SIZE+FP_SCR0_HI(%sp),LOCAL_SIZE+EXC_PC+0x2(%sp)
3546        mov.l           LOCAL_SIZE+FP_SCR0_LO(%sp),LOCAL_SIZE+EXC_EA(%sp)
3547
3548        add.l           &LOCAL_SIZE-0x8,%sp
3549
3550        bra.l           _real_snan
3551
3552#########################################################################
3553# XDEF **************************************************************** #
3554#       _fpsp_inex(): 060FPSP entry point for FP Inexact exception.     #
3555#                                                                       #
3556#       This handler should be the first code executed upon taking the  #
3557#       FP Inexact exception in an operating system.                    #
3558#                                                                       #
3559# XREF **************************************************************** #
3560#       _imem_read_long() - read instruction longword                   #
3561#       fix_skewed_ops() - adjust src operand in fsave frame            #
3562#       set_tag_x() - determine optype of src/dst operands              #
3563#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
3564#       unnorm_fix() - change UNNORM operands to NORM or ZERO           #
3565#       load_fpn2() - load dst operand from FP regfile                  #
3566#       smovcr() - emulate an "fmovcr" instruction                      #
3567#       fout() - emulate an opclass 3 instruction                       #
3568#       tbl_unsupp - add of table of emulation routines for opclass 0,2 #
3569#       _real_inex() - "callout" to operating system inexact handler    #
3570#                                                                       #
3571# INPUT *************************************************************** #
3572#       - The system stack contains the FP Inexact exception frame      #
3573#       - The fsave frame contains the source operand                   #
3574#                                                                       #
3575# OUTPUT ************************************************************** #
3576#       - The system stack is unchanged                                 #
3577#       - The fsave frame contains the adjusted src op for opclass 0,2  #
3578#                                                                       #
3579# ALGORITHM *********************************************************** #
3580#       In a system where the FP Inexact exception is enabled, the goal #
3581# is to get to the handler specified at _real_inex(). But, on the 060,  #
3582# for opclass zero and two instruction taking this exception, the       #
3583# hardware doesn't store the correct result to the destination FP       #
3584# register as did the '040 and '881/2. This handler must emulate the    #
3585# instruction in order to get this value and then store it to the       #
3586# correct register before calling _real_inex().                         #
3587#       For opclass 3 instructions, the 060 doesn't store the default   #
3588# inexact result out to memory or data register file as it should.      #
3589# This code must emulate the move out by calling fout() before finally  #
3590# exiting through _real_inex().                                         #
3591#                                                                       #
3592#########################################################################
3593
3594        global          _fpsp_inex
3595_fpsp_inex:
3596
3597        link.w          %a6,&-LOCAL_SIZE        # init stack frame
3598
3599        fsave           FP_SRC(%a6)             # grab the "busy" frame
3600
3601        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3602        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3603        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
3604
3605# the FPIAR holds the "current PC" of the faulting instruction
3606        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3607
3608        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3609        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3610        bsr.l           _imem_read_long         # fetch the instruction words
3611        mov.l           %d0,EXC_OPWORD(%a6)
3612
3613##############################################################################
3614
3615        btst            &13,%d0                 # is instr an fmove out?
3616        bne.w           finex_out               # fmove out
3617
3618
3619# the hardware, for "fabs" and "fneg" w/ a long source format, puts the
3620# longword integer directly into the upper longword of the mantissa along
3621# w/ an exponent value of 0x401e. we convert this to extended precision here.
3622        bfextu          %d0{&19:&3},%d0         # fetch instr size
3623        bne.b           finex_cont              # instr size is not long
3624        cmpi.w          FP_SRC_EX(%a6),&0x401e  # is exponent 0x401e?
3625        bne.b           finex_cont              # no
3626        fmov.l          &0x0,%fpcr
3627        fmov.l          FP_SRC_HI(%a6),%fp0     # load integer src
3628        fmov.x          %fp0,FP_SRC(%a6)        # store integer as extended precision
3629        mov.w           &0xe001,0x2+FP_SRC(%a6)
3630
3631finex_cont:
3632        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3633        bsr.l           fix_skewed_ops          # fix src op
3634
3635# Here, we zero the ccode and exception byte field since we're going to
3636# emulate the whole instruction. Notice, though, that we don't kill the
3637# INEX1 bit. This is because a packed op has long since been converted
3638# to extended before arriving here. Therefore, we need to retain the
3639# INEX1 bit from when the operand was first converted.
3640        andi.l          &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field
3641
3642        fmov.l          &0x0,%fpcr              # zero current control regs
3643        fmov.l          &0x0,%fpsr
3644
3645        bfextu          EXC_EXTWORD(%a6){&0:&6},%d1 # extract upper 6 of cmdreg
3646        cmpi.b          %d1,&0x17               # is op an fmovecr?
3647        beq.w           finex_fmovcr            # yes
3648
3649        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3650        bsr.l           set_tag_x               # tag the operand type
3651        mov.b           %d0,STAG(%a6)           # maybe NORM,DENORM
3652
3653# bits four and five of the fp extension word separate the monadic and dyadic
3654# operations that can pass through fpsp_inex(). remember that fcmp and ftst
3655# will never take this exception, but fsincos will.
3656        btst            &0x5,1+EXC_CMDREG(%a6)  # is operation monadic or dyadic?
3657        beq.b           finex_extract           # monadic
3658
3659        btst            &0x4,1+EXC_CMDREG(%a6)  # is operation an fsincos?
3660        bne.b           finex_extract           # yes
3661
3662        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
3663        bsr.l           load_fpn2               # load dst into FP_DST
3664
3665        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
3666        bsr.l           set_tag_x               # tag the operand type
3667        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
3668        bne.b           finex_op2_done          # no
3669        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
3670finex_op2_done:
3671        mov.b           %d0,DTAG(%a6)           # save dst optype tag
3672
3673finex_extract:
3674        clr.l           %d0
3675        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec/mode
3676
3677        mov.b           1+EXC_CMDREG(%a6),%d1
3678        andi.w          &0x007f,%d1             # extract extension
3679
3680        lea             FP_SRC(%a6),%a0
3681        lea             FP_DST(%a6),%a1
3682
3683        mov.l           (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
3684        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
3685
3686# the operation has been emulated. the result is in fp0.
3687finex_save:
3688        bfextu          EXC_CMDREG(%a6){&6:&3},%d0
3689        bsr.l           store_fpreg
3690
3691finex_exit:
3692        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3693        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3694        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3695
3696        frestore        FP_SRC(%a6)
3697
3698        unlk            %a6
3699        bra.l           _real_inex
3700
3701finex_fmovcr:
3702        clr.l           %d0
3703        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec,mode
3704        mov.b           1+EXC_CMDREG(%a6),%d1
3705        andi.l          &0x0000007f,%d1         # pass rom offset
3706        bsr.l           smovcr
3707        bra.b           finex_save
3708
3709########################################################################
3710
3711#
3712# the hardware does not save the default result to memory on enabled
3713# inexact exceptions. we do this here before passing control to
3714# the user inexact handler.
3715#
3716# byte, word, and long destination format operations can pass
3717# through here. so can double and single precision.
3718# although packed opclass three operations can take inexact
3719# exceptions, they won't pass through here since they are caught
3720# first by the unsupported data format exception handler. that handler
3721# sends them directly to _real_inex() if necessary.
3722#
3723finex_out:
3724
3725        mov.b           &NORM,STAG(%a6)         # src is a NORM
3726
3727        clr.l           %d0
3728        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec,mode
3729
3730        andi.l          &0xffff00ff,USER_FPSR(%a6) # zero exception field
3731
3732        lea             FP_SRC(%a6),%a0         # pass ptr to src operand
3733
3734        bsr.l           fout                    # store the default result
3735
3736        bra.b           finex_exit
3737
3738#########################################################################
3739# XDEF **************************************************************** #
3740#       _fpsp_dz(): 060FPSP entry point for FP DZ exception.            #
3741#                                                                       #
3742#       This handler should be the first code executed upon taking      #
3743#       the FP DZ exception in an operating system.                     #
3744#                                                                       #
3745# XREF **************************************************************** #
3746#       _imem_read_long() - read instruction longword from memory       #
3747#       fix_skewed_ops() - adjust fsave operand                         #
3748#       _real_dz() - "callout" exit point from FP DZ handler            #
3749#                                                                       #
3750# INPUT *************************************************************** #
3751#       - The system stack contains the FP DZ exception stack.          #
3752#       - The fsave frame contains the source operand.                  #
3753#                                                                       #
3754# OUTPUT ************************************************************** #
3755#       - The system stack contains the FP DZ exception stack.          #
3756#       - The fsave frame contains the adjusted source operand.         #
3757#                                                                       #
3758# ALGORITHM *********************************************************** #
3759#       In a system where the DZ exception is enabled, the goal is to   #
3760# get to the handler specified at _real_dz(). But, on the 060, when the #
3761# exception is taken, the input operand in the fsave state frame may    #
3762# be incorrect for some cases and need to be adjusted. So, this package #
3763# adjusts the operand using fix_skewed_ops() and then branches to       #
3764# _real_dz().                                                           #
3765#                                                                       #
3766#########################################################################
3767
3768        global          _fpsp_dz
3769_fpsp_dz:
3770
3771        link.w          %a6,&-LOCAL_SIZE        # init stack frame
3772
3773        fsave           FP_SRC(%a6)             # grab the "busy" frame
3774
3775        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3776        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3777        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
3778
3779# the FPIAR holds the "current PC" of the faulting instruction
3780        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3781
3782        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3783        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3784        bsr.l           _imem_read_long         # fetch the instruction words
3785        mov.l           %d0,EXC_OPWORD(%a6)
3786
3787##############################################################################
3788
3789
3790# here, we simply see if the operand in the fsave frame needs to be "unskewed".
3791# this would be the case for opclass two operations with a source zero
3792# in the sgl or dbl format.
3793        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3794        bsr.l           fix_skewed_ops          # fix src op
3795
3796fdz_exit:
3797        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3798        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3799        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3800
3801        frestore        FP_SRC(%a6)
3802
3803        unlk            %a6
3804        bra.l           _real_dz
3805
3806#########################################################################
3807# XDEF **************************************************************** #
3808#       _fpsp_fline(): 060FPSP entry point for "Line F emulator" exc.   #
3809#                                                                       #
3810#       This handler should be the first code executed upon taking the  #
3811#       "Line F Emulator" exception in an operating system.             #
3812#                                                                       #
3813# XREF **************************************************************** #
3814#       _fpsp_unimp() - handle "FP Unimplemented" exceptions            #
3815#       _real_fpu_disabled() - handle "FPU disabled" exceptions         #
3816#       _real_fline() - handle "FLINE" exceptions                       #
3817#       _imem_read_long() - read instruction longword                   #
3818#                                                                       #
3819# INPUT *************************************************************** #
3820#       - The system stack contains a "Line F Emulator" exception       #
3821#         stack frame.                                                  #
3822#                                                                       #
3823# OUTPUT ************************************************************** #
3824#       - The system stack is unchanged                                 #
3825#                                                                       #
3826# ALGORITHM *********************************************************** #
3827#       When a "Line F Emulator" exception occurs, there are 3 possible #
3828# exception types, denoted by the exception stack frame format number:  #
3829#       (1) FPU unimplemented instruction (6 word stack frame)          #
3830#       (2) FPU disabled (8 word stack frame)                           #
3831#       (3) Line F (4 word stack frame)                                 #
3832#                                                                       #
3833#       This module determines which and forks the flow off to the      #
3834# appropriate "callout" (for "disabled" and "Line F") or to the         #
3835# correct emulation code (for "FPU unimplemented").                     #
3836#       This code also must check for "fmovecr" instructions w/ a       #
3837# non-zero <ea> field. These may get flagged as "Line F" but should     #
3838# really be flagged as "FPU Unimplemented". (This is a "feature" on     #
3839# the '060.                                                             #
3840#                                                                       #
3841#########################################################################
3842
3843        global          _fpsp_fline
3844_fpsp_fline:
3845
3846# check to see if this exception is a "FP Unimplemented Instruction"
3847# exception. if so, branch directly to that handler's entry point.
3848        cmpi.w          0x6(%sp),&0x202c
3849        beq.l           _fpsp_unimp
3850
3851# check to see if the FPU is disabled. if so, jump to the OS entry
3852# point for that condition.
3853        cmpi.w          0x6(%sp),&0x402c
3854        beq.l           _real_fpu_disabled
3855
3856# the exception was an "F-Line Illegal" exception. we check to see
3857# if the F-Line instruction is an "fmovecr" w/ a non-zero <ea>. if
3858# so, convert the F-Line exception stack frame to an FP Unimplemented
3859# Instruction exception stack frame else branch to the OS entry
3860# point for the F-Line exception handler.
3861        link.w          %a6,&-LOCAL_SIZE        # init stack frame
3862
3863        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3864
3865        mov.l           EXC_PC(%a6),EXC_EXTWPTR(%a6)
3866        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3867        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3868        bsr.l           _imem_read_long         # fetch instruction words
3869
3870        bfextu          %d0{&0:&10},%d1         # is it an fmovecr?
3871        cmpi.w          %d1,&0x03c8
3872        bne.b           fline_fline             # no
3873
3874        bfextu          %d0{&16:&6},%d1         # is it an fmovecr?
3875        cmpi.b          %d1,&0x17
3876        bne.b           fline_fline             # no
3877
3878# it's an fmovecr w/ a non-zero <ea> that has entered through
3879# the F-Line Illegal exception.
3880# so, we need to convert the F-Line exception stack frame into an
3881# FP Unimplemented Instruction stack frame and jump to that entry
3882# point.
3883#
3884# but, if the FPU is disabled, then we need to jump to the FPU disabled
3885# entry point.
3886        movc            %pcr,%d0
3887        btst            &0x1,%d0
3888        beq.b           fline_fmovcr
3889
3890        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3891
3892        unlk            %a6
3893
3894        sub.l           &0x8,%sp                # make room for "Next PC", <ea>
3895        mov.w           0x8(%sp),(%sp)
3896        mov.l           0xa(%sp),0x2(%sp)       # move "Current PC"
3897        mov.w           &0x402c,0x6(%sp)
3898        mov.l           0x2(%sp),0xc(%sp)
3899        addq.l          &0x4,0x2(%sp)           # set "Next PC"
3900
3901        bra.l           _real_fpu_disabled
3902
3903fline_fmovcr:
3904        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3905
3906        unlk            %a6
3907
3908        fmov.l          0x2(%sp),%fpiar         # set current PC
3909        addq.l          &0x4,0x2(%sp)           # set Next PC
3910
3911        mov.l           (%sp),-(%sp)
3912        mov.l           0x8(%sp),0x4(%sp)
3913        mov.b           &0x20,0x6(%sp)
3914
3915        bra.l           _fpsp_unimp
3916
3917fline_fline:
3918        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3919
3920        unlk            %a6
3921
3922        bra.l           _real_fline
3923
3924#########################################################################
3925# XDEF **************************************************************** #
3926#       _fpsp_unimp(): 060FPSP entry point for FP "Unimplemented        #
3927#                      Instruction" exception.                          #
3928#                                                                       #
3929#       This handler should be the first code executed upon taking the  #
3930#       FP Unimplemented Instruction exception in an operating system.  #
3931#                                                                       #
3932# XREF **************************************************************** #
3933#       _imem_read_{word,long}() - read instruction word/longword       #
3934#       load_fop() - load src/dst ops from memory and/or FP regfile     #
3935#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
3936#       tbl_trans - addr of table of emulation routines for trnscndls   #
3937#       _real_access() - "callout" for access error exception           #
3938#       _fpsp_done() - "callout" for exit; work all done                #
3939#       _real_trace() - "callout" for Trace enabled exception           #
3940#       smovcr() - emulate "fmovecr" instruction                        #
3941#       funimp_skew() - adjust fsave src ops to "incorrect" value       #
3942#       _ftrapcc() - emulate an "ftrapcc" instruction                   #
3943#       _fdbcc() - emulate an "fdbcc" instruction                       #
3944#       _fscc() - emulate an "fscc" instruction                         #
3945#       _real_trap() - "callout" for Trap exception                     #
3946#       _real_bsun() - "callout" for enabled Bsun exception             #
3947#                                                                       #
3948# INPUT *************************************************************** #
3949#       - The system stack contains the "Unimplemented Instr" stk frame #
3950#                                                                       #
3951# OUTPUT ************************************************************** #
3952#       If access error:                                                #
3953#       - The system stack is changed to an access error stack frame    #
3954#       If Trace exception enabled:                                     #
3955#       - The system stack is changed to a Trace exception stack frame  #
3956#       Else: (normal case)                                             #
3957#       - Correct result has been stored as appropriate                 #
3958#                                                                       #
3959# ALGORITHM *********************************************************** #
3960#       There are two main cases of instructions that may enter here to #
3961# be emulated: (1) the FPgen instructions, most of which were also      #
3962# unimplemented on the 040, and (2) "ftrapcc", "fscc", and "fdbcc".     #
3963#       For the first set, this handler calls the routine load_fop()    #
3964# to load the source and destination (for dyadic) operands to be used   #
3965# for instruction emulation. The correct emulation routine is then      #
3966# chosen by decoding the instruction type and indexing into an          #
3967# emulation subroutine index table. After emulation returns, this       #
3968# handler checks to see if an exception should occur as a result of the #
3969# FP instruction emulation. If so, then an FP exception of the correct  #
3970# type is inserted into the FPU state frame using the "frestore"        #
3971# instruction before exiting through _fpsp_done(). In either the        #
3972# exceptional or non-exceptional cases, we must check to see if the     #
3973# Trace exception is enabled. If so, then we must create a Trace        #
3974# exception frame from the current exception frame and exit through     #
3975# _real_trace().                                                        #
3976#       For "fdbcc", "ftrapcc", and "fscc", the emulation subroutines   #
3977# _fdbcc(), _ftrapcc(), and _fscc() respectively are used. All three    #
3978# may flag that a BSUN exception should be taken. If so, then the       #
3979# current exception stack frame is converted into a BSUN exception      #
3980# stack frame and an exit is made through _real_bsun(). If the          #
3981# instruction was "ftrapcc" and a Trap exception should result, a Trap  #
3982# exception stack frame is created from the current frame and an exit   #
3983# is made through _real_trap(). If a Trace exception is pending, then   #
3984# a Trace exception frame is created from the current frame and a jump  #
3985# is made to _real_trace(). Finally, if none of these conditions exist, #
3986# then the handler exits though the callout _fpsp_done().               #
3987#                                                                       #
3988#       In any of the above scenarios, if a _mem_read() or _mem_write() #
3989# "callout" returns a failing value, then an access error stack frame   #
3990# is created from the current stack frame and an exit is made through   #
3991# _real_access().                                                       #
3992#                                                                       #
3993#########################################################################
3994
3995#
3996# FP UNIMPLEMENTED INSTRUCTION STACK FRAME:
3997#
3998#       *****************
3999#       *               * => <ea> of fp unimp instr.
4000#       -      EA       -
4001#       *               *
4002#       *****************
4003#       * 0x2 *  0x02c  * => frame format and vector offset(vector #11)
4004#       *****************
4005#       *               *
4006#       -    Next PC    - => PC of instr to execute after exc handling
4007#       *               *
4008#       *****************
4009#       *      SR       * => SR at the time the exception was taken
4010#       *****************
4011#
4012# Note: the !NULL bit does not get set in the fsave frame when the
4013# machine encounters an fp unimp exception. Therefore, it must be set
4014# before leaving this handler.
4015#
4016        global          _fpsp_unimp
4017_fpsp_unimp:
4018
4019        link.w          %a6,&-LOCAL_SIZE        # init stack frame
4020
4021        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
4022        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
4023        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1
4024
4025        btst            &0x5,EXC_SR(%a6)        # user mode exception?
4026        bne.b           funimp_s                # no; supervisor mode
4027
4028# save the value of the user stack pointer onto the stack frame
4029funimp_u:
4030        mov.l           %usp,%a0                # fetch user stack pointer
4031        mov.l           %a0,EXC_A7(%a6)         # store in stack frame
4032        bra.b           funimp_cont
4033
4034# store the value of the supervisor stack pointer BEFORE the exc occurred.
4035# old_sp is address just above stacked effective address.
4036funimp_s:
4037        lea             4+EXC_EA(%a6),%a0       # load old a7'
4038        mov.l           %a0,EXC_A7(%a6)         # store a7'
4039        mov.l           %a0,OLD_A7(%a6)         # make a copy
4040
4041funimp_cont:
4042
4043# the FPIAR holds the "current PC" of the faulting instruction.
4044        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
4045
4046        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4047        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
4048        bsr.l           _imem_read_long         # fetch the instruction words
4049        mov.l           %d0,EXC_OPWORD(%a6)
4050
4051############################################################################
4052
4053        fmov.l          &0x0,%fpcr              # clear FPCR
4054        fmov.l          &0x0,%fpsr              # clear FPSR
4055
4056        clr.b           SPCOND_FLG(%a6)         # clear "special case" flag
4057
4058# Divide the fp instructions into 8 types based on the TYPE field in
4059# bits 6-8 of the opword(classes 6,7 are undefined).
4060# (for the '060, only two types  can take this exception)
4061#       bftst           %d0{&7:&3}              # test TYPE
4062        btst            &22,%d0                 # type 0 or 1 ?
4063        bne.w           funimp_misc             # type 1
4064
4065#########################################
4066# TYPE == 0: General instructions       #
4067#########################################
4068funimp_gen:
4069
4070        clr.b           STORE_FLG(%a6)          # clear "store result" flag
4071
4072# clear the ccode byte and exception status byte
4073        andi.l          &0x00ff00ff,USER_FPSR(%a6)
4074
4075        bfextu          %d0{&16:&6},%d1         # extract upper 6 of cmdreg
4076        cmpi.b          %d1,&0x17               # is op an fmovecr?
4077        beq.w           funimp_fmovcr           # yes
4078
4079funimp_gen_op:
4080        bsr.l           _load_fop               # load
4081
4082        clr.l           %d0
4083        mov.b           FPCR_MODE(%a6),%d0      # fetch rnd mode
4084
4085        mov.b           1+EXC_CMDREG(%a6),%d1
4086        andi.w          &0x003f,%d1             # extract extension bits
4087        lsl.w           &0x3,%d1                # shift right 3 bits
4088        or.b            STAG(%a6),%d1           # insert src optag bits
4089
4090        lea             FP_DST(%a6),%a1         # pass dst ptr in a1
4091        lea             FP_SRC(%a6),%a0         # pass src ptr in a0
4092
4093        mov.w           (tbl_trans.w,%pc,%d1.w*2),%d1
4094        jsr             (tbl_trans.w,%pc,%d1.w*1) # emulate
4095
4096funimp_fsave:
4097        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions enabled
4098        bne.w           funimp_ena              # some are enabled
4099
4100funimp_store:
4101        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # fetch Dn
4102        bsr.l           store_fpreg             # store result to fp regfile
4103
4104funimp_gen_exit:
4105        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
4106        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
4107        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
4108
4109funimp_gen_exit_cmp:
4110        cmpi.b          SPCOND_FLG(%a6),&mia7_flg # was the ea mode (sp)+ ?
4111        beq.b           funimp_gen_exit_a7      # yes
4112
4113        cmpi.b          SPCOND_FLG(%a6),&mda7_flg # was the ea mode -(sp) ?
4114        beq.b           funimp_gen_exit_a7      # yes
4115
4116funimp_gen_exit_cont:
4117        unlk            %a6
4118
4119funimp_gen_exit_cont2:
4120        btst            &0x7,(%sp)              # is trace on?
4121        beq.l           _fpsp_done              # no
4122
4123# this catches a problem with the case where an exception will be re-inserted
4124# into the machine. the frestore has already been executed...so, the fmov.l
4125# alone of the control register would trigger an unwanted exception.
4126# until I feel like fixing this, we'll sidestep the exception.
4127        fsave           -(%sp)
4128        fmov.l          %fpiar,0x14(%sp)        # "Current PC" is in FPIAR
4129        frestore        (%sp)+
4130        mov.w           &0x2024,0x6(%sp)        # stk fmt = 0x2; voff = 0x24
4131        bra.l           _real_trace
4132
4133funimp_gen_exit_a7:
4134        btst            &0x5,EXC_SR(%a6)        # supervisor or user mode?
4135        bne.b           funimp_gen_exit_a7_s    # supervisor
4136
4137        mov.l           %a0,-(%sp)
4138        mov.l           EXC_A7(%a6),%a0
4139        mov.l           %a0,%usp
4140        mov.l           (%sp)+,%a0
4141        bra.b           funimp_gen_exit_cont
4142
4143# if the instruction was executed from supervisor mode and the addressing
4144# mode was (a7)+, then the stack frame for the rte must be shifted "up"
4145# "n" bytes where "n" is the size of the src operand type.
4146# f<op>.{b,w,l,s,d,x,p}
4147funimp_gen_exit_a7_s:
4148        mov.l           %d0,-(%sp)              # save d0
4149        mov.l           EXC_A7(%a6),%d0         # load new a7'
4150        sub.l           OLD_A7(%a6),%d0         # subtract old a7'
4151        mov.l           0x2+EXC_PC(%a6),(0x2+EXC_PC,%a6,%d0) # shift stack frame
4152        mov.l           EXC_SR(%a6),(EXC_SR,%a6,%d0) # shift stack frame
4153        mov.w           %d0,EXC_SR(%a6)         # store incr number
4154        mov.l           (%sp)+,%d0              # restore d0
4155
4156        unlk            %a6
4157
4158        add.w           (%sp),%sp               # stack frame shifted
4159        bra.b           funimp_gen_exit_cont2
4160
4161######################
4162# fmovecr.x #ccc,fpn #
4163######################
4164funimp_fmovcr:
4165        clr.l           %d0
4166        mov.b           FPCR_MODE(%a6),%d0
4167        mov.b           1+EXC_CMDREG(%a6),%d1
4168        andi.l          &0x0000007f,%d1         # pass rom offset in d1
4169        bsr.l           smovcr
4170        bra.w           funimp_fsave
4171
4172#########################################################################
4173
4174#
4175# the user has enabled some exceptions. we figure not to see this too
4176# often so that's why it gets lower priority.
4177#
4178funimp_ena:
4179
4180# was an exception set that was also enabled?
4181        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enabled and set
4182        bfffo           %d0{&24:&8},%d0         # find highest priority exception
4183        bne.b           funimp_exc              # at least one was set
4184
4185# no exception that was enabled was set BUT if we got an exact overflow
4186# and overflow wasn't enabled but inexact was (yech!) then this is
4187# an inexact exception; otherwise, return to normal non-exception flow.
4188        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur?
4189        beq.w           funimp_store            # no; return to normal flow
4190
4191# the overflow w/ exact result happened but was inexact set in the FPCR?
4192funimp_ovfl:
4193        btst            &inex2_bit,FPCR_ENABLE(%a6) # is inexact enabled?
4194        beq.w           funimp_store            # no; return to normal flow
4195        bra.b           funimp_exc_ovfl         # yes
4196
4197# some exception happened that was actually enabled.
4198# we'll insert this new exception into the FPU and then return.
4199funimp_exc:
4200        subi.l          &24,%d0                 # fix offset to be 0-8
4201        cmpi.b          %d0,&0x6                # is exception INEX?
4202        bne.b           funimp_exc_force        # no
4203
4204# the enabled exception was inexact. so, if it occurs with an overflow
4205# or underflow that was disabled, then we have to force an overflow or
4206# underflow frame. the eventual overflow or underflow handler will see that
4207# it's actually an inexact and act appropriately. this is the only easy
4208# way to have the EXOP available for the enabled inexact handler when
4209# a disabled overflow or underflow has also happened.
4210        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur?
4211        bne.b           funimp_exc_ovfl         # yes
4212        btst            &unfl_bit,FPSR_EXCEPT(%a6) # did underflow occur?
4213        bne.b           funimp_exc_unfl         # yes
4214
4215# force the fsave exception status bits to signal an exception of the
4216# appropriate type. don't forget to "skew" the source operand in case we
4217# "unskewed" the one the hardware initially gave us.
4218funimp_exc_force:
4219        mov.l           %d0,-(%sp)              # save d0
4220        bsr.l           funimp_skew             # check for special case
4221        mov.l           (%sp)+,%d0              # restore d0
4222        mov.w           (tbl_funimp_except.b,%pc,%d0.w*2),2+FP_SRC(%a6)
4223        bra.b           funimp_gen_exit2        # exit with frestore
4224
4225tbl_funimp_except:
4226        short           0xe002, 0xe006, 0xe004, 0xe005
4227        short           0xe003, 0xe002, 0xe001, 0xe001
4228
4229# insert an overflow frame
4230funimp_exc_ovfl:
4231        bsr.l           funimp_skew             # check for special case
4232        mov.w           &0xe005,2+FP_SRC(%a6)
4233        bra.b           funimp_gen_exit2
4234
4235# insert an underflow frame
4236funimp_exc_unfl:
4237        bsr.l           funimp_skew             # check for special case
4238        mov.w           &0xe003,2+FP_SRC(%a6)
4239
4240# this is the general exit point for an enabled exception that will be
4241# restored into the machine for the instruction just emulated.
4242funimp_gen_exit2:
4243        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
4244        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
4245        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
4246
4247        frestore        FP_SRC(%a6)             # insert exceptional status
4248
4249        bra.w           funimp_gen_exit_cmp
4250
4251############################################################################
4252
4253#
4254# TYPE == 1: FDB<cc>, FS<cc>, FTRAP<cc>
4255#
4256# These instructions were implemented on the '881/2 and '040 in hardware but
4257# are emulated in software on the '060.
4258#
4259funimp_misc:
4260        bfextu          %d0{&10:&3},%d1         # extract mode field
4261        cmpi.b          %d1,&0x1                # is it an fdb<cc>?
4262        beq.w           funimp_fdbcc            # yes
4263        cmpi.b          %d1,&0x7                # is it an fs<cc>?
4264        bne.w           funimp_fscc             # yes
4265        bfextu          %d0{&13:&3},%d1
4266        cmpi.b          %d1,&0x2                # is it an fs<cc>?
4267        blt.w           funimp_fscc             # yes
4268
4269#########################
4270# ftrap<cc>             #
4271# ftrap<cc>.w #<data>   #
4272# ftrap<cc>.l #<data>   #
4273#########################
4274funimp_ftrapcc:
4275
4276        bsr.l           _ftrapcc                # FTRAP<cc>()
4277
4278        cmpi.b          SPCOND_FLG(%a6),&fbsun_flg # is enabled bsun occurring?
4279        beq.w           funimp_bsun             # yes
4280
4281        cmpi.b          SPCOND_FLG(%a6),&ftrapcc_flg # should a trap occur?
4282        bne.w           funimp_done             # no
4283
4284#        FP UNIMP FRAME            TRAP  FRAME
4285#       *****************       *****************
4286#       **    <EA>     **       **  Current PC **
4287#       *****************       *****************
4288#       * 0x2 *  0x02c  *       * 0x2 *  0x01c  *
4289#       *****************       *****************
4290#       **   Next PC   **       **   Next PC   **
4291#       *****************       *****************
4292#       *      SR       *       *      SR       *
4293#       *****************       *****************
4294#           (6 words)               (6 words)
4295#
4296# the ftrapcc instruction should take a trap. so, here we must create a
4297# trap stack frame from an unimplemented fp instruction stack frame and
4298# jump to the user supplied entry point for the trap exception
4299funimp_ftrapcc_tp:
4300        mov.l           USER_FPIAR(%a6),EXC_EA(%a6) # Address = Current PC
4301        mov.w           &0x201c,EXC_VOFF(%a6)   # Vector Offset = 0x01c
4302
4303        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
4304        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
4305        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
4306
4307        unlk            %a6
4308        bra.l           _real_trap
4309
4310#########################
4311# fdb<cc> Dn,<label>    #
4312#########################
4313funimp_fdbcc:
4314
4315        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4316        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4317        bsr.l           _imem_read_word         # read displacement
4318
4319        tst.l           %d1                     # did ifetch fail?
4320        bne.w           funimp_iacc             # yes
4321
4322        ext.l           %d0                     # sign extend displacement
4323
4324        bsr.l           _fdbcc                  # FDB<cc>()
4325
4326        cmpi.b          SPCOND_FLG(%a6),&fbsun_flg # is enabled bsun occurring?
4327        beq.w           funimp_bsun
4328
4329        bra.w           funimp_done             # branch to finish
4330
4331#################
4332# fs<cc>.b <ea> #
4333#################
4334funimp_fscc:
4335
4336        bsr.l           _fscc                   # FS<cc>()
4337
4338# I am assuming here that an "fs<cc>.b -(An)" or "fs<cc>.b (An)+" instruction
4339# does not need to update "An" before taking a bsun exception.
4340        cmpi.b          SPCOND_FLG(%a6),&fbsun_flg # is enabled bsun occurring?
4341        beq.w           funimp_bsun
4342
4343        btst            &0x5,EXC_SR(%a6)        # yes; is it a user mode exception?
4344        bne.b           funimp_fscc_s           # no
4345
4346funimp_fscc_u:
4347        mov.l           EXC_A7(%a6),%a0         # yes; set new USP
4348        mov.l           %a0,%usp
4349        bra.w           funimp_done             # branch to finish
4350
4351# remember, I'm assuming that post-increment is bogus...(it IS!!!)
4352# so, the least significant WORD of the stacked effective address got
4353# overwritten by the "fs<cc> -(An)". We must shift the stack frame "down"
4354# so that the rte will work correctly without destroying the result.
4355# even though the operation size is byte, the stack ptr is decr by 2.
4356#
4357# remember, also, this instruction may be traced.
4358funimp_fscc_s:
4359        cmpi.b          SPCOND_FLG(%a6),&mda7_flg # was a7 modified?
4360        bne.w           funimp_done             # no
4361
4362        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
4363        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
4364        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
4365
4366        unlk            %a6
4367
4368        btst            &0x7,(%sp)              # is trace enabled?
4369        bne.b           funimp_fscc_s_trace     # yes
4370
4371        subq.l          &0x2,%sp
4372        mov.l           0x2(%sp),(%sp)          # shift SR,hi(PC) "down"
4373        mov.l           0x6(%sp),0x4(%sp)       # shift lo(PC),voff "down"
4374        bra.l           _fpsp_done
4375
4376funimp_fscc_s_trace:
4377        subq.l          &0x2,%sp
4378        mov.l           0x2(%sp),(%sp)          # shift SR,hi(PC) "down"
4379        mov.w           0x6(%sp),0x4(%sp)       # shift lo(PC)
4380        mov.w           &0x2024,0x6(%sp)        # fmt/voff = $2024
4381        fmov.l          %fpiar,0x8(%sp)         # insert "current PC"
4382
4383        bra.l           _real_trace
4384
4385#
4386# The ftrap<cc>, fs<cc>, or fdb<cc> is to take an enabled bsun. we must convert
4387# the fp unimplemented instruction exception stack frame into a bsun stack frame,
4388# restore a bsun exception into the machine, and branch to the user
4389# supplied bsun hook.
4390#
4391#        FP UNIMP FRAME            BSUN FRAME
4392#       *****************       *****************
4393#       **    <EA>     **       * 0x0 * 0x0c0   *
4394#       *****************       *****************
4395#       * 0x2 *  0x02c  *       ** Current PC  **
4396#       *****************       *****************
4397#       **   Next PC   **       *      SR       *
4398#       *****************       *****************
4399#       *      SR       *           (4 words)
4400#       *****************
4401#           (6 words)
4402#
4403funimp_bsun:
4404        mov.w           &0x00c0,2+EXC_EA(%a6)   # Fmt = 0x0; Vector Offset = 0x0c0
4405        mov.l           USER_FPIAR(%a6),EXC_VOFF(%a6) # PC = Current PC
4406        mov.w           EXC_SR(%a6),2+EXC_PC(%a6) # shift SR "up"
4407
4408        mov.w           &0xe000,2+FP_SRC(%a6)   # bsun exception enabled
4409
4410        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
4411        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
4412        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
4413
4414        frestore        FP_SRC(%a6)             # restore bsun exception
4415
4416        unlk            %a6
4417
4418        addq.l          &0x4,%sp                # erase sludge
4419
4420        bra.l           _real_bsun              # branch to user bsun hook
4421
4422#
4423# all ftrapcc/fscc/fdbcc processing has been completed. unwind the stack frame
4424# and return.
4425#
4426# as usual, we have to check for trace mode being on here. since instructions
4427# modifying the supervisor stack frame don't pass through here, this is a
4428# relatively easy task.
4429#
4430funimp_done:
4431        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
4432        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
4433        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
4434
4435        unlk            %a6
4436
4437        btst            &0x7,(%sp)              # is trace enabled?
4438        bne.b           funimp_trace            # yes
4439
4440        bra.l           _fpsp_done
4441
4442#        FP UNIMP FRAME           TRACE  FRAME
4443#       *****************       *****************
4444#       **    <EA>     **       **  Current PC **
4445#       *****************       *****************
4446#       * 0x2 *  0x02c  *       * 0x2 *  0x024  *
4447#       *****************       *****************
4448#       **   Next PC   **       **   Next PC   **
4449#       *****************       *****************
4450#       *      SR       *       *      SR       *
4451#       *****************       *****************
4452#           (6 words)               (6 words)
4453#
4454# the fscc instruction should take a trace trap. so, here we must create a
4455# trace stack frame from an unimplemented fp instruction stack frame and
4456# jump to the user supplied entry point for the trace exception
4457funimp_trace:
4458        fmov.l          %fpiar,0x8(%sp)         # current PC is in fpiar
4459        mov.b           &0x24,0x7(%sp)          # vector offset = 0x024
4460
4461        bra.l           _real_trace
4462
4463################################################################
4464
4465        global          tbl_trans
4466        swbeg           &0x1c0
4467tbl_trans:
4468        short           tbl_trans - tbl_trans   # $00-0 fmovecr all
4469        short           tbl_trans - tbl_trans   # $00-1 fmovecr all
4470        short           tbl_trans - tbl_trans   # $00-2 fmovecr all
4471        short           tbl_trans - tbl_trans   # $00-3 fmovecr all
4472        short           tbl_trans - tbl_trans   # $00-4 fmovecr all
4473        short           tbl_trans - tbl_trans   # $00-5 fmovecr all
4474        short           tbl_trans - tbl_trans   # $00-6 fmovecr all
4475        short           tbl_trans - tbl_trans   # $00-7 fmovecr all
4476
4477        short           tbl_trans - tbl_trans   # $01-0 fint norm
4478        short           tbl_trans - tbl_trans   # $01-1 fint zero
4479        short           tbl_trans - tbl_trans   # $01-2 fint inf
4480        short           tbl_trans - tbl_trans   # $01-3 fint qnan
4481        short           tbl_trans - tbl_trans   # $01-5 fint denorm
4482        short           tbl_trans - tbl_trans   # $01-4 fint snan
4483        short           tbl_trans - tbl_trans   # $01-6 fint unnorm
4484        short           tbl_trans - tbl_trans   # $01-7 ERROR
4485
4486        short           ssinh    - tbl_trans    # $02-0 fsinh norm
4487        short           src_zero - tbl_trans    # $02-1 fsinh zero
4488        short           src_inf  - tbl_trans    # $02-2 fsinh inf
4489        short           src_qnan - tbl_trans    # $02-3 fsinh qnan
4490        short           ssinhd   - tbl_trans    # $02-5 fsinh denorm
4491        short           src_snan - tbl_trans    # $02-4 fsinh snan
4492        short           tbl_trans - tbl_trans   # $02-6 fsinh unnorm
4493        short           tbl_trans - tbl_trans   # $02-7 ERROR
4494
4495        short           tbl_trans - tbl_trans   # $03-0 fintrz norm
4496        short           tbl_trans - tbl_trans   # $03-1 fintrz zero
4497        short           tbl_trans - tbl_trans   # $03-2 fintrz inf
4498        short           tbl_trans - tbl_trans   # $03-3 fintrz qnan
4499        short           tbl_trans - tbl_trans   # $03-5 fintrz denorm
4500        short           tbl_trans - tbl_trans   # $03-4 fintrz snan
4501        short           tbl_trans - tbl_trans   # $03-6 fintrz unnorm
4502        short           tbl_trans - tbl_trans   # $03-7 ERROR
4503
4504        short           tbl_trans - tbl_trans   # $04-0 fsqrt norm
4505        short           tbl_trans - tbl_trans   # $04-1 fsqrt zero
4506        short           tbl_trans - tbl_trans   # $04-2 fsqrt inf
4507        short           tbl_trans - tbl_trans   # $04-3 fsqrt qnan
4508        short           tbl_trans - tbl_trans   # $04-5 fsqrt denorm
4509        short           tbl_trans - tbl_trans   # $04-4 fsqrt snan
4510        short           tbl_trans - tbl_trans   # $04-6 fsqrt unnorm
4511        short           tbl_trans - tbl_trans   # $04-7 ERROR
4512
4513        short           tbl_trans - tbl_trans   # $05-0 ERROR
4514        short           tbl_trans - tbl_trans   # $05-1 ERROR
4515        short           tbl_trans - tbl_trans   # $05-2 ERROR
4516        short           tbl_trans - tbl_trans   # $05-3 ERROR
4517        short           tbl_trans - tbl_trans   # $05-4 ERROR
4518        short           tbl_trans - tbl_trans   # $05-5 ERROR
4519        short           tbl_trans - tbl_trans   # $05-6 ERROR
4520        short           tbl_trans - tbl_trans   # $05-7 ERROR
4521
4522        short           slognp1  - tbl_trans    # $06-0 flognp1 norm
4523        short           src_zero - tbl_trans    # $06-1 flognp1 zero
4524        short           sopr_inf - tbl_trans    # $06-2 flognp1 inf
4525        short           src_qnan - tbl_trans    # $06-3 flognp1 qnan
4526        short           slognp1d - tbl_trans    # $06-5 flognp1 denorm
4527        short           src_snan - tbl_trans    # $06-4 flognp1 snan
4528        short           tbl_trans - tbl_trans   # $06-6 flognp1 unnorm
4529        short           tbl_trans - tbl_trans   # $06-7 ERROR
4530
4531        short           tbl_trans - tbl_trans   # $07-0 ERROR
4532        short           tbl_trans - tbl_trans   # $07-1 ERROR
4533        short           tbl_trans - tbl_trans   # $07-2 ERROR
4534        short           tbl_trans - tbl_trans   # $07-3 ERROR
4535        short           tbl_trans - tbl_trans   # $07-4 ERROR
4536        short           tbl_trans - tbl_trans   # $07-5 ERROR
4537        short           tbl_trans - tbl_trans   # $07-6 ERROR
4538        short           tbl_trans - tbl_trans   # $07-7 ERROR
4539
4540        short           setoxm1  - tbl_trans    # $08-0 fetoxm1 norm
4541        short           src_zero - tbl_trans    # $08-1 fetoxm1 zero
4542        short           setoxm1i - tbl_trans    # $08-2 fetoxm1 inf
4543        short           src_qnan - tbl_trans    # $08-3 fetoxm1 qnan
4544        short           setoxm1d - tbl_trans    # $08-5 fetoxm1 denorm
4545        short           src_snan - tbl_trans    # $08-4 fetoxm1 snan
4546        short           tbl_trans - tbl_trans   # $08-6 fetoxm1 unnorm
4547        short           tbl_trans - tbl_trans   # $08-7 ERROR
4548
4549        short           stanh    - tbl_trans    # $09-0 ftanh norm
4550        short           src_zero - tbl_trans    # $09-1 ftanh zero
4551        short           src_one  - tbl_trans    # $09-2 ftanh inf
4552        short           src_qnan - tbl_trans    # $09-3 ftanh qnan
4553        short           stanhd   - tbl_trans    # $09-5 ftanh denorm
4554        short           src_snan - tbl_trans    # $09-4 ftanh snan
4555        short           tbl_trans - tbl_trans   # $09-6 ftanh unnorm
4556        short           tbl_trans - tbl_trans   # $09-7 ERROR
4557
4558        short           satan    - tbl_trans    # $0a-0 fatan norm
4559        short           src_zero - tbl_trans    # $0a-1 fatan zero
4560        short           spi_2    - tbl_trans    # $0a-2 fatan inf
4561        short           src_qnan - tbl_trans    # $0a-3 fatan qnan
4562        short           satand   - tbl_trans    # $0a-5 fatan denorm
4563        short           src_snan - tbl_trans    # $0a-4 fatan snan
4564        short           tbl_trans - tbl_trans   # $0a-6 fatan unnorm
4565        short           tbl_trans - tbl_trans   # $0a-7 ERROR
4566
4567        short           tbl_trans - tbl_trans   # $0b-0 ERROR
4568        short           tbl_trans - tbl_trans   # $0b-1 ERROR
4569        short           tbl_trans - tbl_trans   # $0b-2 ERROR
4570        short           tbl_trans - tbl_trans   # $0b-3 ERROR
4571        short           tbl_trans - tbl_trans   # $0b-4 ERROR
4572        short           tbl_trans - tbl_trans   # $0b-5 ERROR
4573        short           tbl_trans - tbl_trans   # $0b-6 ERROR
4574        short           tbl_trans - tbl_trans   # $0b-7 ERROR
4575
4576        short           sasin    - tbl_trans    # $0c-0 fasin norm
4577        short           src_zero - tbl_trans    # $0c-1 fasin zero
4578        short           t_operr  - tbl_trans    # $0c-2 fasin inf
4579        short           src_qnan - tbl_trans    # $0c-3 fasin qnan
4580        short           sasind   - tbl_trans    # $0c-5 fasin denorm
4581        short           src_snan - tbl_trans    # $0c-4 fasin snan
4582        short           tbl_trans - tbl_trans   # $0c-6 fasin unnorm
4583        short           tbl_trans - tbl_trans   # $0c-7 ERROR
4584
4585        short           satanh   - tbl_trans    # $0d-0 fatanh norm
4586        short           src_zero - tbl_trans    # $0d-1 fatanh zero
4587        short           t_operr  - tbl_trans    # $0d-2 fatanh inf
4588        short           src_qnan - tbl_trans    # $0d-3 fatanh qnan
4589        short           satanhd  - tbl_trans    # $0d-5 fatanh denorm
4590        short           src_snan - tbl_trans    # $0d-4 fatanh snan
4591        short           tbl_trans - tbl_trans   # $0d-6 fatanh unnorm
4592        short           tbl_trans - tbl_trans   # $0d-7 ERROR
4593
4594        short           ssin     - tbl_trans    # $0e-0 fsin norm
4595        short           src_zero - tbl_trans    # $0e-1 fsin zero
4596        short           t_operr  - tbl_trans    # $0e-2 fsin inf
4597        short           src_qnan - tbl_trans    # $0e-3 fsin qnan
4598        short           ssind    - tbl_trans    # $0e-5 fsin denorm
4599        short           src_snan - tbl_trans    # $0e-4 fsin snan
4600        short           tbl_trans - tbl_trans   # $0e-6 fsin unnorm
4601        short           tbl_trans - tbl_trans   # $0e-7 ERROR
4602
4603        short           stan     - tbl_trans    # $0f-0 ftan norm
4604        short           src_zero - tbl_trans    # $0f-1 ftan zero
4605        short           t_operr  - tbl_trans    # $0f-2 ftan inf
4606        short           src_qnan - tbl_trans    # $0f-3 ftan qnan
4607        short           stand    - tbl_trans    # $0f-5 ftan denorm
4608        short           src_snan - tbl_trans    # $0f-4 ftan snan
4609        short           tbl_trans - tbl_trans   # $0f-6 ftan unnorm
4610        short           tbl_trans - tbl_trans   # $0f-7 ERROR
4611
4612        short           setox    - tbl_trans    # $10-0 fetox norm
4613        short           ld_pone  - tbl_trans    # $10-1 fetox zero
4614        short           szr_inf  - tbl_trans    # $10-2 fetox inf
4615        short           src_qnan - tbl_trans    # $10-3 fetox qnan
4616        short           setoxd   - tbl_trans    # $10-5 fetox denorm
4617        short           src_snan - tbl_trans    # $10-4 fetox snan
4618        short           tbl_trans - tbl_trans   # $10-6 fetox unnorm
4619        short           tbl_trans - tbl_trans   # $10-7 ERROR
4620
4621        short           stwotox  - tbl_trans    # $11-0 ftwotox norm
4622        short           ld_pone  - tbl_trans    # $11-1 ftwotox zero
4623        short           szr_inf  - tbl_trans    # $11-2 ftwotox inf
4624        short           src_qnan - tbl_trans    # $11-3 ftwotox qnan
4625        short           stwotoxd - tbl_trans    # $11-5 ftwotox denorm
4626        short           src_snan - tbl_trans    # $11-4 ftwotox snan
4627        short           tbl_trans - tbl_trans   # $11-6 ftwotox unnorm
4628        short           tbl_trans - tbl_trans   # $11-7 ERROR
4629
4630        short           stentox  - tbl_trans    # $12-0 ftentox norm
4631        short           ld_pone  - tbl_trans    # $12-1 ftentox zero
4632        short           szr_inf  - tbl_trans    # $12-2 ftentox inf
4633        short           src_qnan - tbl_trans    # $12-3 ftentox qnan
4634        short           stentoxd - tbl_trans    # $12-5 ftentox denorm
4635        short           src_snan - tbl_trans    # $12-4 ftentox snan
4636        short           tbl_trans - tbl_trans   # $12-6 ftentox unnorm
4637        short           tbl_trans - tbl_trans   # $12-7 ERROR
4638
4639        short           tbl_trans - tbl_trans   # $13-0 ERROR
4640        short           tbl_trans - tbl_trans   # $13-1 ERROR
4641        short           tbl_trans - tbl_trans   # $13-2 ERROR
4642        short           tbl_trans - tbl_trans   # $13-3 ERROR
4643        short           tbl_trans - tbl_trans   # $13-4 ERROR
4644        short           tbl_trans - tbl_trans   # $13-5 ERROR
4645        short           tbl_trans - tbl_trans   # $13-6 ERROR
4646        short           tbl_trans - tbl_trans   # $13-7 ERROR
4647
4648        short           slogn    - tbl_trans    # $14-0 flogn norm
4649        short           t_dz2    - tbl_trans    # $14-1 flogn zero
4650        short           sopr_inf - tbl_trans    # $14-2 flogn inf
4651        short           src_qnan - tbl_trans    # $14-3 flogn qnan
4652        short           slognd   - tbl_trans    # $14-5 flogn denorm
4653        short           src_snan - tbl_trans    # $14-4 flogn snan
4654        short           tbl_trans - tbl_trans   # $14-6 flogn unnorm
4655        short           tbl_trans - tbl_trans   # $14-7 ERROR
4656
4657        short           slog10   - tbl_trans    # $15-0 flog10 norm
4658        short           t_dz2    - tbl_trans    # $15-1 flog10 zero
4659        short           sopr_inf - tbl_trans    # $15-2 flog10 inf
4660        short           src_qnan - tbl_trans    # $15-3 flog10 qnan
4661        short           slog10d  - tbl_trans    # $15-5 flog10 denorm
4662        short           src_snan - tbl_trans    # $15-4 flog10 snan
4663        short           tbl_trans - tbl_trans   # $15-6 flog10 unnorm
4664        short           tbl_trans - tbl_trans   # $15-7 ERROR
4665
4666        short           slog2    - tbl_trans    # $16-0 flog2 norm
4667        short           t_dz2    - tbl_trans    # $16-1 flog2 zero
4668        short           sopr_inf - tbl_trans    # $16-2 flog2 inf
4669        short           src_qnan - tbl_trans    # $16-3 flog2 qnan
4670        short           slog2d   - tbl_trans    # $16-5 flog2 denorm
4671        short           src_snan - tbl_trans    # $16-4 flog2 snan
4672        short           tbl_trans - tbl_trans   # $16-6 flog2 unnorm
4673        short           tbl_trans - tbl_trans   # $16-7 ERROR
4674
4675        short           tbl_trans - tbl_trans   # $17-0 ERROR
4676        short           tbl_trans - tbl_trans   # $17-1 ERROR
4677        short           tbl_trans - tbl_trans   # $17-2 ERROR
4678        short           tbl_trans - tbl_trans   # $17-3 ERROR
4679        short           tbl_trans - tbl_trans   # $17-4 ERROR
4680        short           tbl_trans - tbl_trans   # $17-5 ERROR
4681        short           tbl_trans - tbl_trans   # $17-6 ERROR
4682        short           tbl_trans - tbl_trans   # $17-7 ERROR
4683
4684        short           tbl_trans - tbl_trans   # $18-0 fabs norm
4685        short           tbl_trans - tbl_trans   # $18-1 fabs zero
4686        short           tbl_trans - tbl_trans   # $18-2 fabs inf
4687        short           tbl_trans - tbl_trans   # $18-3 fabs qnan
4688        short           tbl_trans - tbl_trans   # $18-5 fabs denorm
4689        short           tbl_trans - tbl_trans   # $18-4 fabs snan
4690        short           tbl_trans - tbl_trans   # $18-6 fabs unnorm
4691        short           tbl_trans - tbl_trans   # $18-7 ERROR
4692
4693        short           scosh    - tbl_trans    # $19-0 fcosh norm
4694        short           ld_pone  - tbl_trans    # $19-1 fcosh zero
4695        short           ld_pinf  - tbl_trans    # $19-2 fcosh inf
4696        short           src_qnan - tbl_trans    # $19-3 fcosh qnan
4697        short           scoshd   - tbl_trans    # $19-5 fcosh denorm
4698        short           src_snan - tbl_trans    # $19-4 fcosh snan
4699        short           tbl_trans - tbl_trans   # $19-6 fcosh unnorm
4700        short           tbl_trans - tbl_trans   # $19-7 ERROR
4701
4702        short           tbl_trans - tbl_trans   # $1a-0 fneg norm
4703        short           tbl_trans - tbl_trans   # $1a-1 fneg zero
4704        short           tbl_trans - tbl_trans   # $1a-2 fneg inf
4705        short           tbl_trans - tbl_trans   # $1a-3 fneg qnan
4706        short           tbl_trans - tbl_trans   # $1a-5 fneg denorm
4707        short           tbl_trans - tbl_trans   # $1a-4 fneg snan
4708        short           tbl_trans - tbl_trans   # $1a-6 fneg unnorm
4709        short           tbl_trans - tbl_trans   # $1a-7 ERROR
4710
4711        short           tbl_trans - tbl_trans   # $1b-0 ERROR
4712        short           tbl_trans - tbl_trans   # $1b-1 ERROR
4713        short           tbl_trans - tbl_trans   # $1b-2 ERROR
4714        short           tbl_trans - tbl_trans   # $1b-3 ERROR
4715        short           tbl_trans - tbl_trans   # $1b-4 ERROR
4716        short           tbl_trans - tbl_trans   # $1b-5 ERROR
4717        short           tbl_trans - tbl_trans   # $1b-6 ERROR
4718        short           tbl_trans - tbl_trans   # $1b-7 ERROR
4719
4720        short           sacos    - tbl_trans    # $1c-0 facos norm
4721        short           ld_ppi2  - tbl_trans    # $1c-1 facos zero
4722        short           t_operr  - tbl_trans    # $1c-2 facos inf
4723        short           src_qnan - tbl_trans    # $1c-3 facos qnan
4724        short           sacosd   - tbl_trans    # $1c-5 facos denorm
4725        short           src_snan - tbl_trans    # $1c-4 facos snan
4726        short           tbl_trans - tbl_trans   # $1c-6 facos unnorm
4727        short           tbl_trans - tbl_trans   # $1c-7 ERROR
4728
4729        short           scos     - tbl_trans    # $1d-0 fcos norm
4730        short           ld_pone  - tbl_trans    # $1d-1 fcos zero
4731        short           t_operr  - tbl_trans    # $1d-2 fcos inf
4732        short           src_qnan - tbl_trans    # $1d-3 fcos qnan
4733        short           scosd    - tbl_trans    # $1d-5 fcos denorm
4734        short           src_snan - tbl_trans    # $1d-4 fcos snan
4735        short           tbl_trans - tbl_trans   # $1d-6 fcos unnorm
4736        short           tbl_trans - tbl_trans   # $1d-7 ERROR
4737
4738        short           sgetexp  - tbl_trans    # $1e-0 fgetexp norm
4739        short           src_zero - tbl_trans    # $1e-1 fgetexp zero
4740        short           t_operr  - tbl_trans    # $1e-2 fgetexp inf
4741        short           src_qnan - tbl_trans    # $1e-3 fgetexp qnan
4742        short           sgetexpd - tbl_trans    # $1e-5 fgetexp denorm
4743        short           src_snan - tbl_trans    # $1e-4 fgetexp snan
4744        short           tbl_trans - tbl_trans   # $1e-6 fgetexp unnorm
4745        short           tbl_trans - tbl_trans   # $1e-7 ERROR
4746
4747        short           sgetman  - tbl_trans    # $1f-0 fgetman norm
4748        short           src_zero - tbl_trans    # $1f-1 fgetman zero
4749        short           t_operr  - tbl_trans    # $1f-2 fgetman inf
4750        short           src_qnan - tbl_trans    # $1f-3 fgetman qnan
4751        short           sgetmand - tbl_trans    # $1f-5 fgetman denorm
4752        short           src_snan - tbl_trans    # $1f-4 fgetman snan
4753        short           tbl_trans - tbl_trans   # $1f-6 fgetman unnorm
4754        short           tbl_trans - tbl_trans   # $1f-7 ERROR
4755
4756        short           tbl_trans - tbl_trans   # $20-0 fdiv norm
4757        short           tbl_trans - tbl_trans   # $20-1 fdiv zero
4758        short           tbl_trans - tbl_trans   # $20-2 fdiv inf
4759        short           tbl_trans - tbl_trans   # $20-3 fdiv qnan
4760        short           tbl_trans - tbl_trans   # $20-5 fdiv denorm
4761        short           tbl_trans - tbl_trans   # $20-4 fdiv snan
4762        short           tbl_trans - tbl_trans   # $20-6 fdiv unnorm
4763        short           tbl_trans - tbl_trans   # $20-7 ERROR
4764
4765        short           smod_snorm - tbl_trans  # $21-0 fmod norm
4766        short           smod_szero - tbl_trans  # $21-1 fmod zero
4767        short           smod_sinf - tbl_trans   # $21-2 fmod inf
4768        short           sop_sqnan - tbl_trans   # $21-3 fmod qnan
4769        short           smod_sdnrm - tbl_trans  # $21-5 fmod denorm
4770        short           sop_ssnan - tbl_trans   # $21-4 fmod snan
4771        short           tbl_trans - tbl_trans   # $21-6 fmod unnorm
4772        short           tbl_trans - tbl_trans   # $21-7 ERROR
4773
4774        short           tbl_trans - tbl_trans   # $22-0 fadd norm
4775        short           tbl_trans - tbl_trans   # $22-1 fadd zero
4776        short           tbl_trans - tbl_trans   # $22-2 fadd inf
4777        short           tbl_trans - tbl_trans   # $22-3 fadd qnan
4778        short           tbl_trans - tbl_trans   # $22-5 fadd denorm
4779        short           tbl_trans - tbl_trans   # $22-4 fadd snan
4780        short           tbl_trans - tbl_trans   # $22-6 fadd unnorm
4781        short           tbl_trans - tbl_trans   # $22-7 ERROR
4782
4783        short           tbl_trans - tbl_trans   # $23-0 fmul norm
4784        short           tbl_trans - tbl_trans   # $23-1 fmul zero
4785        short           tbl_trans - tbl_trans   # $23-2 fmul inf
4786        short           tbl_trans - tbl_trans   # $23-3 fmul qnan
4787        short           tbl_trans - tbl_trans   # $23-5 fmul denorm
4788        short           tbl_trans - tbl_trans   # $23-4 fmul snan
4789        short           tbl_trans - tbl_trans   # $23-6 fmul unnorm
4790        short           tbl_trans - tbl_trans   # $23-7 ERROR
4791
4792        short           tbl_trans - tbl_trans   # $24-0 fsgldiv norm
4793        short           tbl_trans - tbl_trans   # $24-1 fsgldiv zero
4794        short           tbl_trans - tbl_trans   # $24-2 fsgldiv inf
4795        short           tbl_trans - tbl_trans   # $24-3 fsgldiv qnan
4796        short           tbl_trans - tbl_trans   # $24-5 fsgldiv denorm
4797        short           tbl_trans - tbl_trans   # $24-4 fsgldiv snan
4798        short           tbl_trans - tbl_trans   # $24-6 fsgldiv unnorm
4799        short           tbl_trans - tbl_trans   # $24-7 ERROR
4800
4801        short           srem_snorm - tbl_trans  # $25-0 frem norm
4802        short           srem_szero - tbl_trans  # $25-1 frem zero
4803        short           srem_sinf - tbl_trans   # $25-2 frem inf
4804        short           sop_sqnan - tbl_trans   # $25-3 frem qnan
4805        short           srem_sdnrm - tbl_trans  # $25-5 frem denorm
4806        short           sop_ssnan - tbl_trans   # $25-4 frem snan
4807        short           tbl_trans - tbl_trans   # $25-6 frem unnorm
4808        short           tbl_trans - tbl_trans   # $25-7 ERROR
4809
4810        short           sscale_snorm - tbl_trans # $26-0 fscale norm
4811        short           sscale_szero - tbl_trans # $26-1 fscale zero
4812        short           sscale_sinf - tbl_trans # $26-2 fscale inf
4813        short           sop_sqnan - tbl_trans   # $26-3 fscale qnan
4814        short           sscale_sdnrm - tbl_trans # $26-5 fscale denorm
4815        short           sop_ssnan - tbl_trans   # $26-4 fscale snan
4816        short           tbl_trans - tbl_trans   # $26-6 fscale unnorm
4817        short           tbl_trans - tbl_trans   # $26-7 ERROR
4818
4819        short           tbl_trans - tbl_trans   # $27-0 fsglmul norm
4820        short           tbl_trans - tbl_trans   # $27-1 fsglmul zero
4821        short           tbl_trans - tbl_trans   # $27-2 fsglmul inf
4822        short           tbl_trans - tbl_trans   # $27-3 fsglmul qnan
4823        short           tbl_trans - tbl_trans   # $27-5 fsglmul denorm
4824        short           tbl_trans - tbl_trans   # $27-4 fsglmul snan
4825        short           tbl_trans - tbl_trans   # $27-6 fsglmul unnorm
4826        short           tbl_trans - tbl_trans   # $27-7 ERROR
4827
4828        short           tbl_trans - tbl_trans   # $28-0 fsub norm
4829        short           tbl_trans - tbl_trans   # $28-1 fsub zero
4830        short           tbl_trans - tbl_trans   # $28-2 fsub inf
4831        short           tbl_trans - tbl_trans   # $28-3 fsub qnan
4832        short           tbl_trans - tbl_trans   # $28-5 fsub denorm
4833        short           tbl_trans - tbl_trans   # $28-4 fsub snan
4834        short           tbl_trans - tbl_trans   # $28-6 fsub unnorm
4835        short           tbl_trans - tbl_trans   # $28-7 ERROR
4836
4837        short           tbl_trans - tbl_trans   # $29-0 ERROR
4838        short           tbl_trans - tbl_trans   # $29-1 ERROR
4839        short           tbl_trans - tbl_trans   # $29-2 ERROR
4840        short           tbl_trans - tbl_trans   # $29-3 ERROR
4841        short           tbl_trans - tbl_trans   # $29-4 ERROR
4842        short           tbl_trans - tbl_trans   # $29-5 ERROR
4843        short           tbl_trans - tbl_trans   # $29-6 ERROR
4844        short           tbl_trans - tbl_trans   # $29-7 ERROR
4845
4846        short           tbl_trans - tbl_trans   # $2a-0 ERROR
4847        short           tbl_trans - tbl_trans   # $2a-1 ERROR
4848        short           tbl_trans - tbl_trans   # $2a-2 ERROR
4849        short           tbl_trans - tbl_trans   # $2a-3 ERROR
4850        short           tbl_trans - tbl_trans   # $2a-4 ERROR
4851        short           tbl_trans - tbl_trans   # $2a-5 ERROR
4852        short           tbl_trans - tbl_trans   # $2a-6 ERROR
4853        short           tbl_trans - tbl_trans   # $2a-7 ERROR
4854
4855        short           tbl_trans - tbl_trans   # $2b-0 ERROR
4856        short           tbl_trans - tbl_trans   # $2b-1 ERROR
4857        short           tbl_trans - tbl_trans   # $2b-2 ERROR
4858        short           tbl_trans - tbl_trans   # $2b-3 ERROR
4859        short           tbl_trans - tbl_trans   # $2b-4 ERROR
4860        short           tbl_trans - tbl_trans   # $2b-5 ERROR
4861        short           tbl_trans - tbl_trans   # $2b-6 ERROR
4862        short           tbl_trans - tbl_trans   # $2b-7 ERROR
4863
4864        short           tbl_trans - tbl_trans   # $2c-0 ERROR
4865        short           tbl_trans - tbl_trans   # $2c-1 ERROR
4866        short           tbl_trans - tbl_trans   # $2c-2 ERROR
4867        short           tbl_trans - tbl_trans   # $2c-3 ERROR
4868        short           tbl_trans - tbl_trans   # $2c-4 ERROR
4869        short           tbl_trans - tbl_trans   # $2c-5 ERROR
4870        short           tbl_trans - tbl_trans   # $2c-6 ERROR
4871        short           tbl_trans - tbl_trans   # $2c-7 ERROR
4872
4873        short           tbl_trans - tbl_trans   # $2d-0 ERROR
4874        short           tbl_trans - tbl_trans   # $2d-1 ERROR
4875        short           tbl_trans - tbl_trans   # $2d-2 ERROR
4876        short           tbl_trans - tbl_trans   # $2d-3 ERROR
4877        short           tbl_trans - tbl_trans   # $2d-4 ERROR
4878        short           tbl_trans - tbl_trans   # $2d-5 ERROR
4879        short           tbl_trans - tbl_trans   # $2d-6 ERROR
4880        short           tbl_trans - tbl_trans   # $2d-7 ERROR
4881
4882        short           tbl_trans - tbl_trans   # $2e-0 ERROR
4883        short           tbl_trans - tbl_trans   # $2e-1 ERROR
4884        short           tbl_trans - tbl_trans   # $2e-2 ERROR
4885        short           tbl_trans - tbl_trans   # $2e-3 ERROR
4886        short           tbl_trans - tbl_trans   # $2e-4 ERROR
4887        short           tbl_trans - tbl_trans   # $2e-5 ERROR
4888        short           tbl_trans - tbl_trans   # $2e-6 ERROR
4889        short           tbl_trans - tbl_trans   # $2e-7 ERROR
4890
4891        short           tbl_trans - tbl_trans   # $2f-0 ERROR
4892        short           tbl_trans - tbl_trans   # $2f-1 ERROR
4893        short           tbl_trans - tbl_trans   # $2f-2 ERROR
4894        short           tbl_trans - tbl_trans   # $2f-3 ERROR
4895        short           tbl_trans - tbl_trans   # $2f-4 ERROR
4896        short           tbl_trans - tbl_trans   # $2f-5 ERROR
4897        short           tbl_trans - tbl_trans   # $2f-6 ERROR
4898        short           tbl_trans - tbl_trans   # $2f-7 ERROR
4899
4900        short           ssincos  - tbl_trans    # $30-0 fsincos norm
4901        short           ssincosz - tbl_trans    # $30-1 fsincos zero
4902        short           ssincosi - tbl_trans    # $30-2 fsincos inf
4903        short           ssincosqnan - tbl_trans # $30-3 fsincos qnan
4904        short           ssincosd - tbl_trans    # $30-5 fsincos denorm
4905        short           ssincossnan - tbl_trans # $30-4 fsincos snan
4906        short           tbl_trans - tbl_trans   # $30-6 fsincos unnorm
4907        short           tbl_trans - tbl_trans   # $30-7 ERROR
4908
4909        short           ssincos  - tbl_trans    # $31-0 fsincos norm
4910        short           ssincosz - tbl_trans    # $31-1 fsincos zero
4911        short           ssincosi - tbl_trans    # $31-2 fsincos inf
4912        short           ssincosqnan - tbl_trans # $31-3 fsincos qnan
4913        short           ssincosd - tbl_trans    # $31-5 fsincos denorm
4914        short           ssincossnan - tbl_trans # $31-4 fsincos snan
4915        short           tbl_trans - tbl_trans   # $31-6 fsincos unnorm
4916        short           tbl_trans - tbl_trans   # $31-7 ERROR
4917
4918        short           ssincos  - tbl_trans    # $32-0 fsincos norm
4919        short           ssincosz - tbl_trans    # $32-1 fsincos zero
4920        short           ssincosi - tbl_trans    # $32-2 fsincos inf
4921        short           ssincosqnan - tbl_trans # $32-3 fsincos qnan
4922        short           ssincosd - tbl_trans    # $32-5 fsincos denorm
4923        short           ssincossnan - tbl_trans # $32-4 fsincos snan
4924        short           tbl_trans - tbl_trans   # $32-6 fsincos unnorm
4925        short           tbl_trans - tbl_trans   # $32-7 ERROR
4926
4927        short           ssincos  - tbl_trans    # $33-0 fsincos norm
4928        short           ssincosz - tbl_trans    # $33-1 fsincos zero
4929        short           ssincosi - tbl_trans    # $33-2 fsincos inf
4930        short           ssincosqnan - tbl_trans # $33-3 fsincos qnan
4931        short           ssincosd - tbl_trans    # $33-5 fsincos denorm
4932        short           ssincossnan - tbl_trans # $33-4 fsincos snan
4933        short           tbl_trans - tbl_trans   # $33-6 fsincos unnorm
4934        short           tbl_trans - tbl_trans   # $33-7 ERROR
4935
4936        short           ssincos  - tbl_trans    # $34-0 fsincos norm
4937        short           ssincosz - tbl_trans    # $34-1 fsincos zero
4938        short           ssincosi - tbl_trans    # $34-2 fsincos inf
4939        short           ssincosqnan - tbl_trans # $34-3 fsincos qnan
4940        short           ssincosd - tbl_trans    # $34-5 fsincos denorm
4941        short           ssincossnan - tbl_trans # $34-4 fsincos snan
4942        short           tbl_trans - tbl_trans   # $34-6 fsincos unnorm
4943        short           tbl_trans - tbl_trans   # $34-7 ERROR
4944
4945        short           ssincos  - tbl_trans    # $35-0 fsincos norm
4946        short           ssincosz - tbl_trans    # $35-1 fsincos zero
4947        short           ssincosi - tbl_trans    # $35-2 fsincos inf
4948        short           ssincosqnan - tbl_trans # $35-3 fsincos qnan
4949        short           ssincosd - tbl_trans    # $35-5 fsincos denorm
4950        short           ssincossnan - tbl_trans # $35-4 fsincos snan
4951        short           tbl_trans - tbl_trans   # $35-6 fsincos unnorm
4952        short           tbl_trans - tbl_trans   # $35-7 ERROR
4953
4954        short           ssincos  - tbl_trans    # $36-0 fsincos norm
4955        short           ssincosz - tbl_trans    # $36-1 fsincos zero
4956        short           ssincosi - tbl_trans    # $36-2 fsincos inf
4957        short           ssincosqnan - tbl_trans # $36-3 fsincos qnan
4958        short           ssincosd - tbl_trans    # $36-5 fsincos denorm
4959        short           ssincossnan - tbl_trans # $36-4 fsincos snan
4960        short           tbl_trans - tbl_trans   # $36-6 fsincos unnorm
4961        short           tbl_trans - tbl_trans   # $36-7 ERROR
4962
4963        short           ssincos  - tbl_trans    # $37-0 fsincos norm
4964        short           ssincosz - tbl_trans    # $37-1 fsincos zero
4965        short           ssincosi - tbl_trans    # $37-2 fsincos inf
4966        short           ssincosqnan - tbl_trans # $37-3 fsincos qnan
4967        short           ssincosd - tbl_trans    # $37-5 fsincos denorm
4968        short           ssincossnan - tbl_trans # $37-4 fsincos snan
4969        short           tbl_trans - tbl_trans   # $37-6 fsincos unnorm
4970        short           tbl_trans - tbl_trans   # $37-7 ERROR
4971
4972##########
4973
4974# the instruction fetch access for the displacement word for the
4975# fdbcc emulation failed. here, we create an access error frame
4976# from the current frame and branch to _real_access().
4977funimp_iacc:
4978        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
4979        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
4980        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
4981
4982        mov.l           USER_FPIAR(%a6),EXC_PC(%a6) # store current PC
4983
4984        unlk            %a6
4985
4986        mov.l           (%sp),-(%sp)            # store SR,hi(PC)
4987        mov.w           0x8(%sp),0x4(%sp)       # store lo(PC)
4988        mov.w           &0x4008,0x6(%sp)        # store voff
4989        mov.l           0x2(%sp),0x8(%sp)       # store EA
4990        mov.l           &0x09428001,0xc(%sp)    # store FSLW
4991
4992        btst            &0x5,(%sp)              # user or supervisor mode?
4993        beq.b           funimp_iacc_end         # user
4994        bset            &0x2,0xd(%sp)           # set supervisor TM bit
4995
4996funimp_iacc_end:
4997        bra.l           _real_access
4998
4999#########################################################################
5000# ssin():     computes the sine of a normalized input                   #
5001# ssind():    computes the sine of a denormalized input                 #
5002# scos():     computes the cosine of a normalized input                 #
5003# scosd():    computes the cosine of a denormalized input               #
5004# ssincos():  computes the sine and cosine of a normalized input        #
5005# ssincosd(): computes the sine and cosine of a denormalized input      #
5006#                                                                       #
5007# INPUT *************************************************************** #
5008#       a0 = pointer to extended precision input                        #
5009#       d0 = round precision,mode                                       #
5010#                                                                       #
5011# OUTPUT ************************************************************** #
5012#       fp0 = sin(X) or cos(X)                                          #
5013#                                                                       #
5014#    For ssincos(X):                                                    #
5015#       fp0 = sin(X)                                                    #
5016#       fp1 = cos(X)                                                    #
5017#                                                                       #
5018# ACCURACY and MONOTONICITY ******************************************* #
5019#       The returned result is within 1 ulp in 64 significant bit, i.e. #
5020#       within 0.5001 ulp to 53 bits if the result is subsequently      #
5021#       rounded to double precision. The result is provably monotonic   #
5022#       in double precision.                                            #
5023#                                                                       #
5024# ALGORITHM *********************************************************** #
5025#                                                                       #
5026#       SIN and COS:                                                    #
5027#       1. If SIN is invoked, set AdjN := 0; otherwise, set AdjN := 1.  #
5028#                                                                       #
5029#       2. If |X| >= 15Pi or |X| < 2**(-40), go to 7.                   #
5030#                                                                       #
5031#       3. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let        #
5032#               k = N mod 4, so in particular, k = 0,1,2,or 3.          #
5033#               Overwrite k by k := k + AdjN.                           #
5034#                                                                       #
5035#       4. If k is even, go to 6.                                       #
5036#                                                                       #
5037#       5. (k is odd) Set j := (k-1)/2, sgn := (-1)**j.                 #
5038#               Return sgn*cos(r) where cos(r) is approximated by an    #
5039#               even polynomial in r, 1 + r*r*(B1+s*(B2+ ... + s*B8)),  #
5040#               s = r*r.                                                #
5041#               Exit.                                                   #
5042#                                                                       #
5043#       6. (k is even) Set j := k/2, sgn := (-1)**j. Return sgn*sin(r)  #
5044#               where sin(r) is approximated by an odd polynomial in r  #
5045#               r + r*s*(A1+s*(A2+ ... + s*A7)),        s = r*r.        #
5046#               Exit.                                                   #
5047#                                                                       #
5048#       7. If |X| > 1, go to 9.                                         #
5049#                                                                       #
5050#       8. (|X|<2**(-40)) If SIN is invoked, return X;                  #
5051#               otherwise return 1.                                     #
5052#                                                                       #
5053#       9. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi,           #
5054#               go back to 3.                                           #
5055#                                                                       #
5056#       SINCOS:                                                         #
5057#       1. If |X| >= 15Pi or |X| < 2**(-40), go to 6.                   #
5058#                                                                       #
5059#       2. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let        #
5060#               k = N mod 4, so in particular, k = 0,1,2,or 3.          #
5061#                                                                       #
5062#       3. If k is even, go to 5.                                       #
5063#                                                                       #
5064#       4. (k is odd) Set j1 := (k-1)/2, j2 := j1 (EOR) (k mod 2), ie.  #
5065#               j1 exclusive or with the l.s.b. of k.                   #
5066#               sgn1 := (-1)**j1, sgn2 := (-1)**j2.                     #
5067#               SIN(X) = sgn1 * cos(r) and COS(X) = sgn2*sin(r) where   #
5068#               sin(r) and cos(r) are computed as odd and even          #
5069#               polynomials in r, respectively. Exit                    #
5070#                                                                       #
5071#       5. (k is even) Set j1 := k/2, sgn1 := (-1)**j1.                 #
5072#               SIN(X) = sgn1 * sin(r) and COS(X) = sgn1*cos(r) where   #
5073#               sin(r) and cos(r) are computed as odd and even          #
5074#               polynomials in r, respectively. Exit                    #
5075#                                                                       #
5076#       6. If |X| > 1, go to 8.                                         #
5077#                                                                       #
5078#       7. (|X|<2**(-40)) SIN(X) = X and COS(X) = 1. Exit.              #
5079#                                                                       #
5080#       8. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi,           #
5081#               go back to 2.                                           #
5082#                                                                       #
5083#########################################################################
5084
5085SINA7:  long            0xBD6AAA77,0xCCC994F5
5086SINA6:  long            0x3DE61209,0x7AAE8DA1
5087SINA5:  long            0xBE5AE645,0x2A118AE4
5088SINA4:  long            0x3EC71DE3,0xA5341531
5089SINA3:  long            0xBF2A01A0,0x1A018B59,0x00000000,0x00000000
5090SINA2:  long            0x3FF80000,0x88888888,0x888859AF,0x00000000
5091SINA1:  long            0xBFFC0000,0xAAAAAAAA,0xAAAAAA99,0x00000000
5092
5093COSB8:  long            0x3D2AC4D0,0xD6011EE3
5094COSB7:  long            0xBDA9396F,0x9F45AC19
5095COSB6:  long            0x3E21EED9,0x0612C972
5096COSB5:  long            0xBE927E4F,0xB79D9FCF
5097COSB4:  long            0x3EFA01A0,0x1A01D423,0x00000000,0x00000000
5098COSB3:  long            0xBFF50000,0xB60B60B6,0x0B61D438,0x00000000
5099COSB2:  long            0x3FFA0000,0xAAAAAAAA,0xAAAAAB5E
5100COSB1:  long            0xBF000000
5101
5102        set             INARG,FP_SCR0
5103
5104        set             X,FP_SCR0
5105#       set             XDCARE,X+2
5106        set             XFRAC,X+4
5107
5108        set             RPRIME,FP_SCR0
5109        set             SPRIME,FP_SCR1
5110
5111        set             POSNEG1,L_SCR1
5112        set             TWOTO63,L_SCR1
5113
5114        set             ENDFLAG,L_SCR2
5115        set             INT,L_SCR2
5116
5117        set             ADJN,L_SCR3
5118
5119############################################
5120        global          ssin
5121ssin:
5122        mov.l           &0,ADJN(%a6)            # yes; SET ADJN TO 0
5123        bra.b           SINBGN
5124
5125############################################
5126        global          scos
5127scos:
5128        mov.l           &1,ADJN(%a6)            # yes; SET ADJN TO 1
5129
5130############################################
5131SINBGN:
5132#--SAVE FPCR, FP1. CHECK IF |X| IS TOO SMALL OR LARGE
5133
5134        fmov.x          (%a0),%fp0              # LOAD INPUT
5135        fmov.x          %fp0,X(%a6)             # save input at X
5136
5137# "COMPACTIFY" X
5138        mov.l           (%a0),%d1               # put exp in hi word
5139        mov.w           4(%a0),%d1              # fetch hi(man)
5140        and.l           &0x7FFFFFFF,%d1         # strip sign
5141
5142        cmpi.l          %d1,&0x3FD78000         # is |X| >= 2**(-40)?
5143        bge.b           SOK1                    # no
5144        bra.w           SINSM                   # yes; input is very small
5145
5146SOK1:
5147        cmp.l           %d1,&0x4004BC7E         # is |X| < 15 PI?
5148        blt.b           SINMAIN                 # no
5149        bra.w           SREDUCEX                # yes; input is very large
5150
5151#--THIS IS THE USUAL CASE, |X| <= 15 PI.
5152#--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP.
5153SINMAIN:
5154        fmov.x          %fp0,%fp1
5155        fmul.d          TWOBYPI(%pc),%fp1       # X*2/PI
5156
5157        lea             PITBL+0x200(%pc),%a1    # TABLE OF N*PI/2, N = -32,...,32
5158
5159        fmov.l          %fp1,INT(%a6)           # CONVERT TO INTEGER
5160
5161        mov.l           INT(%a6),%d1            # make a copy of N
5162        asl.l           &4,%d1                  # N *= 16
5163        add.l           %d1,%a1                 # tbl_addr = a1 + (N*16)
5164
5165# A1 IS THE ADDRESS OF N*PIBY2
5166# ...WHICH IS IN TWO PIECES Y1 & Y2
5167        fsub.x          (%a1)+,%fp0             # X-Y1
5168        fsub.s          (%a1),%fp0              # fp0 = R = (X-Y1)-Y2
5169
5170SINCONT:
5171#--continuation from REDUCEX
5172
5173#--GET N+ADJN AND SEE IF SIN(R) OR COS(R) IS NEEDED
5174        mov.l           INT(%a6),%d1
5175        add.l           ADJN(%a6),%d1           # SEE IF D0 IS ODD OR EVEN
5176        ror.l           &1,%d1                  # D0 WAS ODD IFF D0 IS NEGATIVE
5177        cmp.l           %d1,&0
5178        blt.w           COSPOLY
5179
5180#--LET J BE THE LEAST SIG. BIT OF D0, LET SGN := (-1)**J.
5181#--THEN WE RETURN       SGN*SIN(R). SGN*SIN(R) IS COMPUTED BY
5182#--R' + R'*S*(A1 + S(A2 + S(A3 + S(A4 + ... + SA7)))), WHERE
5183#--R' = SGN*R, S=R*R. THIS CAN BE REWRITTEN AS
5184#--R' + R'*S*( [A1+T(A3+T(A5+TA7))] + [S(A2+T(A4+TA6))])
5185#--WHERE T=S*S.
5186#--NOTE THAT A3 THROUGH A7 ARE STORED IN DOUBLE PRECISION
5187#--WHILE A1 AND A2 ARE IN DOUBLE-EXTENDED FORMAT.
5188SINPOLY:
5189        fmovm.x         &0x0c,-(%sp)            # save fp2/fp3
5190
5191        fmov.x          %fp0,X(%a6)             # X IS R
5192        fmul.x          %fp0,%fp0               # FP0 IS S
5193
5194        fmov.d          SINA7(%pc),%fp3
5195        fmov.d          SINA6(%pc),%fp2
5196
5197        fmov.x          %fp0,%fp1
5198        fmul.x          %fp1,%fp1               # FP1 IS T
5199
5200        ror.l           &1,%d1
5201        and.l           &0x80000000,%d1
5202# ...LEAST SIG. BIT OF D0 IN SIGN POSITION
5203        eor.l           %d1,X(%a6)              # X IS NOW R'= SGN*R
5204
5205        fmul.x          %fp1,%fp3               # TA7
5206        fmul.x          %fp1,%fp2               # TA6
5207
5208        fadd.d          SINA5(%pc),%fp3         # A5+TA7
5209        fadd.d          SINA4(%pc),%fp2         # A4+TA6
5210
5211        fmul.x          %fp1,%fp3               # T(A5+TA7)
5212        fmul.x          %fp1,%fp2               # T(A4+TA6)
5213
5214        fadd.d          SINA3(%pc),%fp3         # A3+T(A5+TA7)
5215        fadd.x          SINA2(%pc),%fp2         # A2+T(A4+TA6)
5216
5217        fmul.x          %fp3,%fp1               # T(A3+T(A5+TA7))
5218
5219        fmul.x          %fp0,%fp2               # S(A2+T(A4+TA6))
5220        fadd.x          SINA1(%pc),%fp1         # A1+T(A3+T(A5+TA7))
5221        fmul.x          X(%a6),%fp0             # R'*S
5222
5223        fadd.x          %fp2,%fp1               # [A1+T(A3+T(A5+TA7))]+[S(A2+T(A4+TA6))]
5224
5225        fmul.x          %fp1,%fp0               # SIN(R')-R'
5226
5227        fmovm.x         (%sp)+,&0x30            # restore fp2/fp3
5228
5229        fmov.l          %d0,%fpcr               # restore users round mode,prec
5230        fadd.x          X(%a6),%fp0             # last inst - possible exception set
5231        bra             t_inx2
5232
5233#--LET J BE THE LEAST SIG. BIT OF D0, LET SGN := (-1)**J.
5234#--THEN WE RETURN       SGN*COS(R). SGN*COS(R) IS COMPUTED BY
5235#--SGN + S'*(B1 + S(B2 + S(B3 + S(B4 + ... + SB8)))), WHERE
5236#--S=R*R AND S'=SGN*S. THIS CAN BE REWRITTEN AS
5237#--SGN + S'*([B1+T(B3+T(B5+TB7))] + [S(B2+T(B4+T(B6+TB8)))])
5238#--WHERE T=S*S.
5239#--NOTE THAT B4 THROUGH B8 ARE STORED IN DOUBLE PRECISION
5240#--WHILE B2 AND B3 ARE IN DOUBLE-EXTENDED FORMAT, B1 IS -1/2
5241#--AND IS THEREFORE STORED AS SINGLE PRECISION.
5242COSPOLY:
5243        fmovm.x         &0x0c,-(%sp)            # save fp2/fp3
5244
5245        fmul.x          %fp0,%fp0               # FP0 IS S
5246
5247        fmov.d          COSB8(%pc),%fp2
5248        fmov.d          COSB7(%pc),%fp3
5249
5250        fmov.x          %fp0,%fp1
5251        fmul.x          %fp1,%fp1               # FP1 IS T
5252
5253        fmov.x          %fp0,X(%a6)             # X IS S
5254        ror.l           &1,%d1
5255        and.l           &0x80000000,%d1
5256# ...LEAST SIG. BIT OF D0 IN SIGN POSITION
5257
5258        fmul.x          %fp1,%fp2               # TB8
5259
5260        eor.l           %d1,X(%a6)              # X IS NOW S'= SGN*S
5261        and.l           &0x80000000,%d1
5262
5263        fmul.x          %fp1,%fp3               # TB7
5264
5265        or.l            &0x3F800000,%d1         # D0 IS SGN IN SINGLE
5266        mov.l           %d1,POSNEG1(%a6)
5267
5268        fadd.d          COSB6(%pc),%fp2         # B6+TB8
5269        fadd.d          COSB5(%pc),%fp3         # B5+TB7
5270
5271        fmul.x          %fp1,%fp2               # T(B6+TB8)
5272        fmul.x          %fp1,%fp3               # T(B5+TB7)
5273
5274        fadd.d          COSB4(%pc),%fp2         # B4+T(B6+TB8)
5275        fadd.x          COSB3(%pc),%fp3         # B3+T(B5+TB7)
5276
5277        fmul.x          %fp1,%fp2               # T(B4+T(B6+TB8))
5278        fmul.x          %fp3,%fp1               # T(B3+T(B5+TB7))
5279
5280        fadd.x          COSB2(%pc),%fp2         # B2+T(B4+T(B6+TB8))
5281        fadd.s          COSB1(%pc),%fp1         # B1+T(B3+T(B5+TB7))
5282
5283        fmul.x          %fp2,%fp0               # S(B2+T(B4+T(B6+TB8)))
5284
5285        fadd.x          %fp1,%fp0
5286
5287        fmul.x          X(%a6),%fp0
5288
5289        fmovm.x         (%sp)+,&0x30            # restore fp2/fp3
5290
5291        fmov.l          %d0,%fpcr               # restore users round mode,prec
5292        fadd.s          POSNEG1(%a6),%fp0       # last inst - possible exception set
5293        bra             t_inx2
5294
5295##############################################
5296
5297# SINe: Big OR Small?
5298#--IF |X| > 15PI, WE USE THE GENERAL ARGUMENT REDUCTION.
5299#--IF |X| < 2**(-40), RETURN X OR 1.
5300SINBORS:
5301        cmp.l           %d1,&0x3FFF8000
5302        bgt.l           SREDUCEX
5303
5304SINSM:
5305        mov.l           ADJN(%a6),%d1
5306        cmp.l           %d1,&0
5307        bgt.b           COSTINY
5308
5309# here, the operation may underflow iff the precision is sgl or dbl.
5310# extended denorms are handled through another entry point.
5311SINTINY:
5312#       mov.w           &0x0000,XDCARE(%a6)     # JUST IN CASE
5313
5314        fmov.l          %d0,%fpcr               # restore users round mode,prec
5315        mov.b           &FMOV_OP,%d1            # last inst is MOVE
5316        fmov.x          X(%a6),%fp0             # last inst - possible exception set
5317        bra             t_catch
5318
5319COSTINY:
5320        fmov.s          &0x3F800000,%fp0        # fp0 = 1.0
5321        fmov.l          %d0,%fpcr               # restore users round mode,prec
5322        fadd.s          &0x80800000,%fp0        # last inst - possible exception set
5323        bra             t_pinx2
5324
5325################################################
5326        global          ssind
5327#--SIN(X) = X FOR DENORMALIZED X
5328ssind:
5329        bra             t_extdnrm
5330
5331############################################
5332        global          scosd
5333#--COS(X) = 1 FOR DENORMALIZED X
5334scosd:
5335        fmov.s          &0x3F800000,%fp0        # fp0 = 1.0
5336        bra             t_pinx2
5337
5338##################################################
5339
5340        global          ssincos
5341ssincos:
5342#--SET ADJN TO 4
5343        mov.l           &4,ADJN(%a6)
5344
5345        fmov.x          (%a0),%fp0              # LOAD INPUT
5346        fmov.x          %fp0,X(%a6)
5347
5348        mov.l           (%a0),%d1
5349        mov.w           4(%a0),%d1
5350        and.l           &0x7FFFFFFF,%d1         # COMPACTIFY X
5351
5352        cmp.l           %d1,&0x3FD78000         # |X| >= 2**(-40)?
5353        bge.b           SCOK1
5354        bra.w           SCSM
5355
5356SCOK1:
5357        cmp.l           %d1,&0x4004BC7E         # |X| < 15 PI?
5358        blt.b           SCMAIN
5359        bra.w           SREDUCEX
5360
5361
5362#--THIS IS THE USUAL CASE, |X| <= 15 PI.
5363#--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP.
5364SCMAIN:
5365        fmov.x          %fp0,%fp1
5366
5367        fmul.d          TWOBYPI(%pc),%fp1       # X*2/PI
5368
5369        lea             PITBL+0x200(%pc),%a1    # TABLE OF N*PI/2, N = -32,...,32
5370
5371        fmov.l          %fp1,INT(%a6)           # CONVERT TO INTEGER
5372
5373        mov.l           INT(%a6),%d1
5374        asl.l           &4,%d1
5375        add.l           %d1,%a1                 # ADDRESS OF N*PIBY2, IN Y1, Y2
5376
5377        fsub.x          (%a1)+,%fp0             # X-Y1
5378        fsub.s          (%a1),%fp0              # FP0 IS R = (X-Y1)-Y2
5379
5380SCCONT:
5381#--continuation point from REDUCEX
5382
5383        mov.l           INT(%a6),%d1
5384        ror.l           &1,%d1
5385        cmp.l           %d1,&0                  # D0 < 0 IFF N IS ODD
5386        bge.w           NEVEN
5387
5388SNODD:
5389#--REGISTERS SAVED SO FAR: D0, A0, FP2.
5390        fmovm.x         &0x04,-(%sp)            # save fp2
5391
5392        fmov.x          %fp0,RPRIME(%a6)
5393        fmul.x          %fp0,%fp0               # FP0 IS S = R*R
5394        fmov.d          SINA7(%pc),%fp1         # A7
5395        fmov.d          COSB8(%pc),%fp2         # B8
5396        fmul.x          %fp0,%fp1               # SA7
5397        fmul.x          %fp0,%fp2               # SB8
5398
5399        mov.l           %d2,-(%sp)
5400        mov.l           %d1,%d2
5401        ror.l           &1,%d2
5402        and.l           &0x80000000,%d2
5403        eor.l           %d1,%d2
5404        and.l           &0x80000000,%d2
5405
5406        fadd.d          SINA6(%pc),%fp1         # A6+SA7
5407        fadd.d          COSB7(%pc),%fp2         # B7+SB8
5408
5409        fmul.x          %fp0,%fp1               # S(A6+SA7)
5410        eor.l           %d2,RPRIME(%a6)
5411        mov.l           (%sp)+,%d2
5412        fmul.x          %fp0,%fp2               # S(B7+SB8)
5413        ror.l           &1,%d1
5414        and.l           &0x80000000,%d1
5415        mov.l           &0x3F800000,POSNEG1(%a6)
5416        eor.l           %d1,POSNEG1(%a6)
5417
5418        fadd.d          SINA5(%pc),%fp1         # A5+S(A6+SA7)
5419        fadd.d          COSB6(%pc),%fp2         # B6+S(B7+SB8)
5420
5421        fmul.x          %fp0,%fp1               # S(A5+S(A6+SA7))
5422        fmul.x          %fp0,%fp2               # S(B6+S(B7+SB8))
5423        fmov.x          %fp0,SPRIME(%a6)
5424
5425        fadd.d          SINA4(%pc),%fp1         # A4+S(A5+S(A6+SA7))
5426        eor.l           %d1,SPRIME(%a6)
5427        fadd.d          COSB5(%pc),%fp2         # B5+S(B6+S(B7+SB8))
5428
5429        fmul.x          %fp0,%fp1               # S(A4+...)
5430        fmul.x          %fp0,%fp2               # S(B5+...)
5431
5432        fadd.d          SINA3(%pc),%fp1         # A3+S(A4+...)
5433        fadd.d          COSB4(%pc),%fp2         # B4+S(B5+...)
5434
5435        fmul.x          %fp0,%fp1               # S(A3+...)
5436        fmul.x          %fp0,%fp2               # S(B4+...)
5437
5438        fadd.x          SINA2(%pc),%fp1         # A2+S(A3+...)
5439        fadd.x          COSB3(%pc),%fp2         # B3+S(B4+...)
5440
5441        fmul.x          %fp0,%fp1               # S(A2+...)
5442        fmul.x          %fp0,%fp2               # S(B3+...)
5443
5444        fadd.x          SINA1(%pc),%fp1         # A1+S(A2+...)
5445        fadd.x          COSB2(%pc),%fp2         # B2+S(B3+...)
5446
5447        fmul.x          %fp0,%fp1               # S(A1+...)
5448        fmul.x          %fp2,%fp0               # S(B2+...)
5449
5450        fmul.x          RPRIME(%a6),%fp1        # R'S(A1+...)
5451        fadd.s          COSB1(%pc),%fp0         # B1+S(B2...)
5452        fmul.x          SPRIME(%a6),%fp0        # S'(B1+S(B2+...))
5453
5454        fmovm.x         (%sp)+,&0x20            # restore fp2
5455
5456        fmov.l          %d0,%fpcr
5457        fadd.x          RPRIME(%a6),%fp1        # COS(X)
5458        bsr             sto_cos                 # store cosine result
5459        fadd.s          POSNEG1(%a6),%fp0       # SIN(X)
5460        bra             t_inx2
5461
5462NEVEN:
5463#--REGISTERS SAVED SO FAR: FP2.
5464        fmovm.x         &0x04,-(%sp)            # save fp2
5465
5466        fmov.x          %fp0,RPRIME(%a6)
5467        fmul.x          %fp0,%fp0               # FP0 IS S = R*R
5468
5469        fmov.d          COSB8(%pc),%fp1         # B8
5470        fmov.d          SINA7(%pc),%fp2         # A7
5471
5472        fmul.x          %fp0,%fp1               # SB8
5473        fmov.x          %fp0,SPRIME(%a6)
5474        fmul.x          %fp0,%fp2               # SA7
5475
5476        ror.l           &1,%d1
5477        and.l           &0x80000000,%d1
5478
5479        fadd.d          COSB7(%pc),%fp1         # B7+SB8
5480        fadd.d          SINA6(%pc),%fp2         # A6+SA7
5481
5482        eor.l           %d1,RPRIME(%a6)
5483        eor.l           %d1,SPRIME(%a6)
5484
5485        fmul.x          %fp0,%fp1               # S(B7+SB8)
5486
5487        or.l            &0x3F800000,%d1
5488        mov.l           %d1,POSNEG1(%a6)
5489
5490        fmul.x          %fp0,%fp2               # S(A6+SA7)
5491
5492        fadd.d          COSB6(%pc),%fp1         # B6+S(B7+SB8)
5493        fadd.d          SINA5(%pc),%fp2         # A5+S(A6+SA7)
5494
5495        fmul.x          %fp0,%fp1               # S(B6+S(B7+SB8))
5496        fmul.x          %fp0,%fp2               # S(A5+S(A6+SA7))
5497
5498        fadd.d          COSB5(%pc),%fp1         # B5+S(B6+S(B7+SB8))
5499        fadd.d          SINA4(%pc),%fp2         # A4+S(A5+S(A6+SA7))
5500
5501        fmul.x          %fp0,%fp1               # S(B5+...)
5502        fmul.x          %fp0,%fp2               # S(A4+...)
5503
5504        fadd.d          COSB4(%pc),%fp1         # B4+S(B5+...)
5505        fadd.d          SINA3(%pc),%fp2         # A3+S(A4+...)
5506
5507        fmul.x          %fp0,%fp1               # S(B4+...)
5508        fmul.x          %fp0,%fp2               # S(A3+...)
5509
5510        fadd.x          COSB3(%pc),%fp1         # B3+S(B4+...)
5511        fadd.x          SINA2(%pc),%fp2         # A2+S(A3+...)
5512
5513        fmul.x          %fp0,%fp1               # S(B3+...)
5514        fmul.x          %fp0,%fp2               # S(A2+...)
5515
5516        fadd.x          COSB2(%pc),%fp1         # B2+S(B3+...)
5517        fadd.x          SINA1(%pc),%fp2         # A1+S(A2+...)
5518
5519        fmul.x          %fp0,%fp1               # S(B2+...)
5520        fmul.x          %fp2,%fp0               # s(a1+...)
5521
5522
5523        fadd.s          COSB1(%pc),%fp1         # B1+S(B2...)
5524        fmul.x          RPRIME(%a6),%fp0        # R'S(A1+...)
5525        fmul.x          SPRIME(%a6),%fp1        # S'(B1+S(B2+...))
5526
5527        fmovm.x         (%sp)+,&0x20            # restore fp2
5528
5529        fmov.l          %d0,%fpcr
5530        fadd.s          POSNEG1(%a6),%fp1       # COS(X)
5531        bsr             sto_cos                 # store cosine result
5532        fadd.x          RPRIME(%a6),%fp0        # SIN(X)
5533        bra             t_inx2
5534
5535################################################
5536
5537SCBORS:
5538        cmp.l           %d1,&0x3FFF8000
5539        bgt.w           SREDUCEX
5540
5541################################################
5542
5543SCSM:
5544#       mov.w           &0x0000,XDCARE(%a6)
5545        fmov.s          &0x3F800000,%fp1
5546
5547        fmov.l          %d0,%fpcr
5548        fsub.s          &0x00800000,%fp1
5549        bsr             sto_cos                 # store cosine result
5550        fmov.l          %fpcr,%d0               # d0 must have fpcr,too
5551        mov.b           &FMOV_OP,%d1            # last inst is MOVE
5552        fmov.x          X(%a6),%fp0
5553        bra             t_catch
5554
5555##############################################
5556
5557        global          ssincosd
5558#--SIN AND COS OF X FOR DENORMALIZED X
5559ssincosd:
5560        mov.l           %d0,-(%sp)              # save d0
5561        fmov.s          &0x3F800000,%fp1
5562        bsr             sto_cos                 # store cosine result
5563        mov.l           (%sp)+,%d0              # restore d0
5564        bra             t_extdnrm
5565
5566############################################
5567
5568#--WHEN REDUCEX IS USED, THE CODE WILL INEVITABLY BE SLOW.
5569#--THIS REDUCTION METHOD, HOWEVER, IS MUCH FASTER THAN USING
5570#--THE REMAINDER INSTRUCTION WHICH IS NOW IN SOFTWARE.
5571SREDUCEX:
5572        fmovm.x         &0x3c,-(%sp)            # save {fp2-fp5}
5573        mov.l           %d2,-(%sp)              # save d2
5574        fmov.s          &0x00000000,%fp1        # fp1 = 0
5575
5576#--If compact form of abs(arg) in d0=$7ffeffff, argument is so large that
5577#--there is a danger of unwanted overflow in first LOOP iteration.  In this
5578#--case, reduce argument by one remainder step to make subsequent reduction
5579#--safe.
5580        cmp.l           %d1,&0x7ffeffff         # is arg dangerously large?
5581        bne.b           SLOOP                   # no
5582
5583# yes; create 2**16383*PI/2
5584        mov.w           &0x7ffe,FP_SCR0_EX(%a6)
5585        mov.l           &0xc90fdaa2,FP_SCR0_HI(%a6)
5586        clr.l           FP_SCR0_LO(%a6)
5587
5588# create low half of 2**16383*PI/2 at FP_SCR1
5589        mov.w           &0x7fdc,FP_SCR1_EX(%a6)
5590        mov.l           &0x85a308d3,FP_SCR1_HI(%a6)
5591        clr.l           FP_SCR1_LO(%a6)
5592
5593        ftest.x         %fp0                    # test sign of argument
5594        fblt.w          sred_neg
5595
5596        or.b            &0x80,FP_SCR0_EX(%a6)   # positive arg
5597        or.b            &0x80,FP_SCR1_EX(%a6)
5598sred_neg:
5599        fadd.x          FP_SCR0(%a6),%fp0       # high part of reduction is exact
5600        fmov.x          %fp0,%fp1               # save high result in fp1
5601        fadd.x          FP_SCR1(%a6),%fp0       # low part of reduction
5602        fsub.x          %fp0,%fp1               # determine low component of result
5603        fadd.x          FP_SCR1(%a6),%fp1       # fp0/fp1 are reduced argument.
5604
5605#--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4.
5606#--integer quotient will be stored in N
5607#--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1)
5608SLOOP:
5609        fmov.x          %fp0,INARG(%a6)         # +-2**K * F, 1 <= F < 2
5610        mov.w           INARG(%a6),%d1
5611        mov.l           %d1,%a1                 # save a copy of D0
5612        and.l           &0x00007FFF,%d1
5613        sub.l           &0x00003FFF,%d1         # d0 = K
5614        cmp.l           %d1,&28
5615        ble.b           SLASTLOOP
5616SCONTLOOP:
5617        sub.l           &27,%d1                 # d0 = L := K-27
5618        mov.b           &0,ENDFLAG(%a6)
5619        bra.b           SWORK
5620SLASTLOOP:
5621        clr.l           %d1                     # d0 = L := 0
5622        mov.b           &1,ENDFLAG(%a6)
5623
5624SWORK:
5625#--FIND THE REMAINDER OF (R,r) W.R.T.   2**L * (PI/2). L IS SO CHOSEN
5626#--THAT INT( X * (2/PI) / 2**(L) ) < 2**29.
5627
5628#--CREATE 2**(-L) * (2/PI), SIGN(INARG)*2**(63),
5629#--2**L * (PIby2_1), 2**L * (PIby2_2)
5630
5631        mov.l           &0x00003FFE,%d2         # BIASED EXP OF 2/PI
5632        sub.l           %d1,%d2                 # BIASED EXP OF 2**(-L)*(2/PI)
5633
5634        mov.l           &0xA2F9836E,FP_SCR0_HI(%a6)
5635        mov.l           &0x4E44152A,FP_SCR0_LO(%a6)
5636        mov.w           %d2,FP_SCR0_EX(%a6)     # FP_SCR0 = 2**(-L)*(2/PI)
5637
5638        fmov.x          %fp0,%fp2
5639        fmul.x          FP_SCR0(%a6),%fp2       # fp2 = X * 2**(-L)*(2/PI)
5640
5641#--WE MUST NOW FIND INT(FP2). SINCE WE NEED THIS VALUE IN
5642#--FLOATING POINT FORMAT, THE TWO FMOVE'S       FMOVE.L FP <--> N
5643#--WILL BE TOO INEFFICIENT. THE WAY AROUND IT IS THAT
5644#--(SIGN(INARG)*2**63   +       FP2) - SIGN(INARG)*2**63 WILL GIVE
5645#--US THE DESIRED VALUE IN FLOATING POINT.
5646        mov.l           %a1,%d2
5647        swap            %d2
5648        and.l           &0x80000000,%d2
5649        or.l            &0x5F000000,%d2         # d2 = SIGN(INARG)*2**63 IN SGL
5650        mov.l           %d2,TWOTO63(%a6)
5651        fadd.s          TWOTO63(%a6),%fp2       # THE FRACTIONAL PART OF FP1 IS ROUNDED
5652        fsub.s          TWOTO63(%a6),%fp2       # fp2 = N
5653#       fint.x          %fp2
5654
5655#--CREATING 2**(L)*Piby2_1 and 2**(L)*Piby2_2
5656        mov.l           %d1,%d2                 # d2 = L
5657
5658        add.l           &0x00003FFF,%d2         # BIASED EXP OF 2**L * (PI/2)
5659        mov.w           %d2,FP_SCR0_EX(%a6)
5660        mov.l           &0xC90FDAA2,FP_SCR0_HI(%a6)
5661        clr.l           FP_SCR0_LO(%a6)         # FP_SCR0 = 2**(L) * Piby2_1
5662
5663        add.l           &0x00003FDD,%d1
5664        mov.w           %d1,FP_SCR1_EX(%a6)
5665        mov.l           &0x85A308D3,FP_SCR1_HI(%a6)
5666        clr.l           FP_SCR1_LO(%a6)         # FP_SCR1 = 2**(L) * Piby2_2
5667
5668        mov.b           ENDFLAG(%a6),%d1
5669
5670#--We are now ready to perform (R+r) - N*P1 - N*P2, P1 = 2**(L) * Piby2_1 and
5671#--P2 = 2**(L) * Piby2_2
5672        fmov.x          %fp2,%fp4               # fp4 = N
5673        fmul.x          FP_SCR0(%a6),%fp4       # fp4 = W = N*P1
5674        fmov.x          %fp2,%fp5               # fp5 = N
5675        fmul.x          FP_SCR1(%a6),%fp5       # fp5 = w = N*P2
5676        fmov.x          %fp4,%fp3               # fp3 = W = N*P1
5677
5678#--we want P+p = W+w  but  |p| <= half ulp of P
5679#--Then, we need to compute  A := R-P   and  a := r-p
5680        fadd.x          %fp5,%fp3               # fp3 = P
5681        fsub.x          %fp3,%fp4               # fp4 = W-P
5682
5683        fsub.x          %fp3,%fp0               # fp0 = A := R - P
5684        fadd.x          %fp5,%fp4               # fp4 = p = (W-P)+w
5685
5686        fmov.x          %fp0,%fp3               # fp3 = A
5687        fsub.x          %fp4,%fp1               # fp1 = a := r - p
5688
5689#--Now we need to normalize (A,a) to  "new (R,r)" where R+r = A+a but
5690#--|r| <= half ulp of R.
5691        fadd.x          %fp1,%fp0               # fp0 = R := A+a
5692#--No need to calculate r if this is the last loop
5693        cmp.b           %d1,&0
5694        bgt.w           SRESTORE
5695
5696#--Need to calculate r
5697        fsub.x          %fp0,%fp3               # fp3 = A-R
5698        fadd.x          %fp3,%fp1               # fp1 = r := (A-R)+a
5699        bra.w           SLOOP
5700
5701SRESTORE:
5702        fmov.l          %fp2,INT(%a6)
5703        mov.l           (%sp)+,%d2              # restore d2
5704        fmovm.x         (%sp)+,&0x3c            # restore {fp2-fp5}
5705
5706        mov.l           ADJN(%a6),%d1
5707        cmp.l           %d1,&4
5708
5709        blt.w           SINCONT
5710        bra.w           SCCONT
5711
5712#########################################################################
5713# stan():  computes the tangent of a normalized input                   #
5714# stand(): computes the tangent of a denormalized input                 #
5715#                                                                       #
5716# INPUT *************************************************************** #
5717#       a0 = pointer to extended precision input                        #
5718#       d0 = round precision,mode                                       #
5719#                                                                       #
5720# OUTPUT ************************************************************** #
5721#       fp0 = tan(X)                                                    #
5722#                                                                       #
5723# ACCURACY and MONOTONICITY ******************************************* #
5724#       The returned result is within 3 ulp in 64 significant bit, i.e. #
5725#       within 0.5001 ulp to 53 bits if the result is subsequently      #
5726#       rounded to double precision. The result is provably monotonic   #
5727#       in double precision.                                            #
5728#                                                                       #
5729# ALGORITHM *********************************************************** #
5730#                                                                       #
5731#       1. If |X| >= 15Pi or |X| < 2**(-40), go to 6.                   #
5732#                                                                       #
5733#       2. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let        #
5734#               k = N mod 2, so in particular, k = 0 or 1.              #
5735#                                                                       #
5736#       3. If k is odd, go to 5.                                        #
5737#                                                                       #
5738#       4. (k is even) Tan(X) = tan(r) and tan(r) is approximated by a  #
5739#               rational function U/V where                             #
5740#               U = r + r*s*(P1 + s*(P2 + s*P3)), and                   #
5741#               V = 1 + s*(Q1 + s*(Q2 + s*(Q3 + s*Q4))),  s = r*r.      #
5742#               Exit.                                                   #
5743#                                                                       #
5744#       4. (k is odd) Tan(X) = -cot(r). Since tan(r) is approximated by #
5745#               a rational function U/V where                           #
5746#               U = r + r*s*(P1 + s*(P2 + s*P3)), and                   #
5747#               V = 1 + s*(Q1 + s*(Q2 + s*(Q3 + s*Q4))), s = r*r,       #
5748#               -Cot(r) = -V/U. Exit.                                   #
5749#                                                                       #
5750#       6. If |X| > 1, go to 8.                                         #
5751#                                                                       #
5752#       7. (|X|<2**(-40)) Tan(X) = X. Exit.                             #
5753#                                                                       #
5754#       8. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi, go back   #
5755#               to 2.                                                   #
5756#                                                                       #
5757#########################################################################
5758
5759TANQ4:
5760        long            0x3EA0B759,0xF50F8688
5761TANP3:
5762        long            0xBEF2BAA5,0xA8924F04
5763
5764TANQ3:
5765        long            0xBF346F59,0xB39BA65F,0x00000000,0x00000000
5766
5767TANP2:
5768        long            0x3FF60000,0xE073D3FC,0x199C4A00,0x00000000
5769
5770TANQ2:
5771        long            0x3FF90000,0xD23CD684,0x15D95FA1,0x00000000
5772
5773TANP1:
5774        long            0xBFFC0000,0x8895A6C5,0xFB423BCA,0x00000000
5775
5776TANQ1:
5777        long            0xBFFD0000,0xEEF57E0D,0xA84BC8CE,0x00000000
5778
5779INVTWOPI:
5780        long            0x3FFC0000,0xA2F9836E,0x4E44152A,0x00000000
5781
5782TWOPI1:
5783        long            0x40010000,0xC90FDAA2,0x00000000,0x00000000
5784TWOPI2:
5785        long            0x3FDF0000,0x85A308D4,0x00000000,0x00000000
5786
5787#--N*PI/2, -32 <= N <= 32, IN A LEADING TERM IN EXT. AND TRAILING
5788#--TERM IN SGL. NOTE THAT PI IS 64-BIT LONG, THUS N*PI/2 IS AT
5789#--MOST 69 BITS LONG.
5790#       global          PITBL
5791PITBL:
5792        long            0xC0040000,0xC90FDAA2,0x2168C235,0x21800000
5793        long            0xC0040000,0xC2C75BCD,0x105D7C23,0xA0D00000
5794        long            0xC0040000,0xBC7EDCF7,0xFF523611,0xA1E80000
5795        long            0xC0040000,0xB6365E22,0xEE46F000,0x21480000
5796        long            0xC0040000,0xAFEDDF4D,0xDD3BA9EE,0xA1200000
5797        long            0xC0040000,0xA9A56078,0xCC3063DD,0x21FC0000
5798        long            0xC0040000,0xA35CE1A3,0xBB251DCB,0x21100000
5799        long            0xC0040000,0x9D1462CE,0xAA19D7B9,0xA1580000
5800        long            0xC0040000,0x96CBE3F9,0x990E91A8,0x21E00000
5801        long            0xC0040000,0x90836524,0x88034B96,0x20B00000
5802        long            0xC0040000,0x8A3AE64F,0x76F80584,0xA1880000
5803        long            0xC0040000,0x83F2677A,0x65ECBF73,0x21C40000
5804        long            0xC0030000,0xFB53D14A,0xA9C2F2C2,0x20000000
5805        long            0xC0030000,0xEEC2D3A0,0x87AC669F,0x21380000
5806        long            0xC0030000,0xE231D5F6,0x6595DA7B,0xA1300000
5807        long            0xC0030000,0xD5A0D84C,0x437F4E58,0x9FC00000
5808        long            0xC0030000,0xC90FDAA2,0x2168C235,0x21000000
5809        long            0xC0030000,0xBC7EDCF7,0xFF523611,0xA1680000
5810        long            0xC0030000,0xAFEDDF4D,0xDD3BA9EE,0xA0A00000
5811        long            0xC0030000,0xA35CE1A3,0xBB251DCB,0x20900000
5812        long            0xC0030000,0x96CBE3F9,0x990E91A8,0x21600000
5813        long            0xC0030000,0x8A3AE64F,0x76F80584,0xA1080000
5814        long            0xC0020000,0xFB53D14A,0xA9C2F2C2,0x1F800000
5815        long            0xC0020000,0xE231D5F6,0x6595DA7B,0xA0B00000
5816        long            0xC0020000,0xC90FDAA2,0x2168C235,0x20800000
5817        long            0xC0020000,0xAFEDDF4D,0xDD3BA9EE,0xA0200000
5818        long            0xC0020000,0x96CBE3F9,0x990E91A8,0x20E00000
5819        long            0xC0010000,0xFB53D14A,0xA9C2F2C2,0x1F000000
5820        long            0xC0010000,0xC90FDAA2,0x2168C235,0x20000000
5821        long            0xC0010000,0x96CBE3F9,0x990E91A8,0x20600000
5822        long            0xC0000000,0xC90FDAA2,0x2168C235,0x1F800000
5823        long            0xBFFF0000,0xC90FDAA2,0x2168C235,0x1F000000
5824        long            0x00000000,0x00000000,0x00000000,0x00000000
5825        long            0x3FFF0000,0xC90FDAA2,0x2168C235,0x9F000000
5826        long            0x40000000,0xC90FDAA2,0x2168C235,0x9F800000
5827        long            0x40010000,0x96CBE3F9,0x990E91A8,0xA0600000
5828        long            0x40010000,0xC90FDAA2,0x2168C235,0xA0000000
5829        long            0x40010000,0xFB53D14A,0xA9C2F2C2,0x9F000000
5830        long            0x40020000,0x96CBE3F9,0x990E91A8,0xA0E00000
5831        long            0x40020000,0xAFEDDF4D,0xDD3BA9EE,0x20200000
5832        long            0x40020000,0xC90FDAA2,0x2168C235,0xA0800000
5833        long            0x40020000,0xE231D5F6,0x6595DA7B,0x20B00000
5834        long            0x40020000,0xFB53D14A,0xA9C2F2C2,0x9F800000
5835        long            0x40030000,0x8A3AE64F,0x76F80584,0x21080000
5836        long            0x40030000,0x96CBE3F9,0x990E91A8,0xA1600000
5837        long            0x40030000,0xA35CE1A3,0xBB251DCB,0xA0900000
5838        long            0x40030000,0xAFEDDF4D,0xDD3BA9EE,0x20A00000
5839        long            0x40030000,0xBC7EDCF7,0xFF523611,0x21680000
5840        long            0x40030000,0xC90FDAA2,0x2168C235,0xA1000000
5841        long            0x40030000,0xD5A0D84C,0x437F4E58,0x1FC00000
5842        long            0x40030000,0xE231D5F6,0x6595DA7B,0x21300000
5843        long            0x40030000,0xEEC2D3A0,0x87AC669F,0xA1380000
5844        long            0x40030000,0xFB53D14A,0xA9C2F2C2,0xA0000000
5845        long            0x40040000,0x83F2677A,0x65ECBF73,0xA1C40000
5846        long            0x40040000,0x8A3AE64F,0x76F80584,0x21880000
5847        long            0x40040000,0x90836524,0x88034B96,0xA0B00000
5848        long            0x40040000,0x96CBE3F9,0x990E91A8,0xA1E00000
5849        long            0x40040000,0x9D1462CE,0xAA19D7B9,0x21580000
5850        long            0x40040000,0xA35CE1A3,0xBB251DCB,0xA1100000
5851        long            0x40040000,0xA9A56078,0xCC3063DD,0xA1FC0000
5852        long            0x40040000,0xAFEDDF4D,0xDD3BA9EE,0x21200000
5853        long            0x40040000,0xB6365E22,0xEE46F000,0xA1480000
5854        long            0x40040000,0xBC7EDCF7,0xFF523611,0x21E80000
5855        long            0x40040000,0xC2C75BCD,0x105D7C23,0x20D00000
5856        long            0x40040000,0xC90FDAA2,0x2168C235,0xA1800000
5857
5858        set             INARG,FP_SCR0
5859
5860        set             TWOTO63,L_SCR1
5861        set             INT,L_SCR1
5862        set             ENDFLAG,L_SCR2
5863
5864        global          stan
5865stan:
5866        fmov.x          (%a0),%fp0              # LOAD INPUT
5867
5868        mov.l           (%a0),%d1
5869        mov.w           4(%a0),%d1
5870        and.l           &0x7FFFFFFF,%d1
5871
5872        cmp.l           %d1,&0x3FD78000         # |X| >= 2**(-40)?
5873        bge.b           TANOK1
5874        bra.w           TANSM
5875TANOK1:
5876        cmp.l           %d1,&0x4004BC7E         # |X| < 15 PI?
5877        blt.b           TANMAIN
5878        bra.w           REDUCEX
5879
5880TANMAIN:
5881#--THIS IS THE USUAL CASE, |X| <= 15 PI.
5882#--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP.
5883        fmov.x          %fp0,%fp1
5884        fmul.d          TWOBYPI(%pc),%fp1       # X*2/PI
5885
5886        lea.l           PITBL+0x200(%pc),%a1    # TABLE OF N*PI/2, N = -32,...,32
5887
5888        fmov.l          %fp1,%d1                # CONVERT TO INTEGER
5889
5890        asl.l           &4,%d1
5891        add.l           %d1,%a1                 # ADDRESS N*PIBY2 IN Y1, Y2
5892
5893        fsub.x          (%a1)+,%fp0             # X-Y1
5894
5895        fsub.s          (%a1),%fp0              # FP0 IS R = (X-Y1)-Y2
5896
5897        ror.l           &5,%d1
5898        and.l           &0x80000000,%d1         # D0 WAS ODD IFF D0 < 0
5899
5900TANCONT:
5901        fmovm.x         &0x0c,-(%sp)            # save fp2,fp3
5902
5903        cmp.l           %d1,&0
5904        blt.w           NODD
5905
5906        fmov.x          %fp0,%fp1
5907        fmul.x          %fp1,%fp1               # S = R*R
5908
5909        fmov.d          TANQ4(%pc),%fp3
5910        fmov.d          TANP3(%pc),%fp2
5911
5912        fmul.x          %fp1,%fp3               # SQ4
5913        fmul.x          %fp1,%fp2               # SP3
5914
5915        fadd.d          TANQ3(%pc),%fp3         # Q3+SQ4
5916        fadd.x          TANP2(%pc),%fp2         # P2+SP3
5917
5918        fmul.x          %fp1,%fp3               # S(Q3+SQ4)
5919        fmul.x          %fp1,%fp2               # S(P2+SP3)
5920
5921        fadd.x          TANQ2(%pc),%fp3         # Q2+S(Q3+SQ4)
5922        fadd.x          TANP1(%pc),%fp2         # P1+S(P2+SP3)
5923
5924        fmul.x          %fp1,%fp3               # S(Q2+S(Q3+SQ4))
5925        fmul.x          %fp1,%fp2               # S(P1+S(P2+SP3))
5926
5927        fadd.x          TANQ1(%pc),%fp3         # Q1+S(Q2+S(Q3+SQ4))
5928        fmul.x          %fp0,%fp2               # RS(P1+S(P2+SP3))
5929
5930        fmul.x          %fp3,%fp1               # S(Q1+S(Q2+S(Q3+SQ4)))
5931
5932        fadd.x          %fp2,%fp0               # R+RS(P1+S(P2+SP3))
5933
5934        fadd.s          &0x3F800000,%fp1        # 1+S(Q1+...)
5935
5936        fmovm.x         (%sp)+,&0x30            # restore fp2,fp3
5937
5938        fmov.l          %d0,%fpcr               # restore users round mode,prec
5939        fdiv.x          %fp1,%fp0               # last inst - possible exception set
5940        bra             t_inx2
5941
5942NODD:
5943        fmov.x          %fp0,%fp1
5944        fmul.x          %fp0,%fp0               # S = R*R
5945
5946        fmov.d          TANQ4(%pc),%fp3
5947        fmov.d          TANP3(%pc),%fp2
5948
5949        fmul.x          %fp0,%fp3               # SQ4
5950        fmul.x          %fp0,%fp2               # SP3
5951
5952        fadd.d          TANQ3(%pc),%fp3         # Q3+SQ4
5953        fadd.x          TANP2(%pc),%fp2         # P2+SP3
5954
5955        fmul.x          %fp0,%fp3               # S(Q3+SQ4)
5956        fmul.x          %fp0,%fp2               # S(P2+SP3)
5957
5958        fadd.x          TANQ2(%pc),%fp3         # Q2+S(Q3+SQ4)
5959        fadd.x          TANP1(%pc),%fp2         # P1+S(P2+SP3)
5960
5961        fmul.x          %fp0,%fp3               # S(Q2+S(Q3+SQ4))
5962        fmul.x          %fp0,%fp2               # S(P1+S(P2+SP3))
5963
5964        fadd.x          TANQ1(%pc),%fp3         # Q1+S(Q2+S(Q3+SQ4))
5965        fmul.x          %fp1,%fp2               # RS(P1+S(P2+SP3))
5966
5967        fmul.x          %fp3,%fp0               # S(Q1+S(Q2+S(Q3+SQ4)))
5968
5969        fadd.x          %fp2,%fp1               # R+RS(P1+S(P2+SP3))
5970        fadd.s          &0x3F800000,%fp0        # 1+S(Q1+...)
5971
5972        fmovm.x         (%sp)+,&0x30            # restore fp2,fp3
5973
5974        fmov.x          %fp1,-(%sp)
5975        eor.l           &0x80000000,(%sp)
5976
5977        fmov.l          %d0,%fpcr               # restore users round mode,prec
5978        fdiv.x          (%sp)+,%fp0             # last inst - possible exception set
5979        bra             t_inx2
5980
5981TANBORS:
5982#--IF |X| > 15PI, WE USE THE GENERAL ARGUMENT REDUCTION.
5983#--IF |X| < 2**(-40), RETURN X OR 1.
5984        cmp.l           %d1,&0x3FFF8000
5985        bgt.b           REDUCEX
5986
5987TANSM:
5988        fmov.x          %fp0,-(%sp)
5989        fmov.l          %d0,%fpcr               # restore users round mode,prec
5990        mov.b           &FMOV_OP,%d1            # last inst is MOVE
5991        fmov.x          (%sp)+,%fp0             # last inst - posibble exception set
5992        bra             t_catch
5993
5994        global          stand
5995#--TAN(X) = X FOR DENORMALIZED X
5996stand:
5997        bra             t_extdnrm
5998
5999#--WHEN REDUCEX IS USED, THE CODE WILL INEVITABLY BE SLOW.
6000#--THIS REDUCTION METHOD, HOWEVER, IS MUCH FASTER THAN USING
6001#--THE REMAINDER INSTRUCTION WHICH IS NOW IN SOFTWARE.
6002REDUCEX:
6003        fmovm.x         &0x3c,-(%sp)            # save {fp2-fp5}
6004        mov.l           %d2,-(%sp)              # save d2
6005        fmov.s          &0x00000000,%fp1        # fp1 = 0
6006
6007#--If compact form of abs(arg) in d0=$7ffeffff, argument is so large that
6008#--there is a danger of unwanted overflow in first LOOP iteration.  In this
6009#--case, reduce argument by one remainder step to make subsequent reduction
6010#--safe.
6011        cmp.l           %d1,&0x7ffeffff         # is arg dangerously large?
6012        bne.b           LOOP                    # no
6013
6014# yes; create 2**16383*PI/2
6015        mov.w           &0x7ffe,FP_SCR0_EX(%a6)
6016        mov.l           &0xc90fdaa2,FP_SCR0_HI(%a6)
6017        clr.l           FP_SCR0_LO(%a6)
6018
6019# create low half of 2**16383*PI/2 at FP_SCR1
6020        mov.w           &0x7fdc,FP_SCR1_EX(%a6)
6021        mov.l           &0x85a308d3,FP_SCR1_HI(%a6)
6022        clr.l           FP_SCR1_LO(%a6)
6023
6024        ftest.x         %fp0                    # test sign of argument
6025        fblt.w          red_neg
6026
6027        or.b            &0x80,FP_SCR0_EX(%a6)   # positive arg
6028        or.b            &0x80,FP_SCR1_EX(%a6)
6029red_neg:
6030        fadd.x          FP_SCR0(%a6),%fp0       # high part of reduction is exact
6031        fmov.x          %fp0,%fp1               # save high result in fp1
6032        fadd.x          FP_SCR1(%a6),%fp0       # low part of reduction
6033        fsub.x          %fp0,%fp1               # determine low component of result
6034        fadd.x          FP_SCR1(%a6),%fp1       # fp0/fp1 are reduced argument.
6035
6036#--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4.
6037#--integer quotient will be stored in N
6038#--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1)
6039LOOP:
6040        fmov.x          %fp0,INARG(%a6)         # +-2**K * F, 1 <= F < 2
6041        mov.w           INARG(%a6),%d1
6042        mov.l           %d1,%a1                 # save a copy of D0
6043        and.l           &0x00007FFF,%d1
6044        sub.l           &0x00003FFF,%d1         # d0 = K
6045        cmp.l           %d1,&28
6046        ble.b           LASTLOOP
6047CONTLOOP:
6048        sub.l           &27,%d1                 # d0 = L := K-27
6049        mov.b           &0,ENDFLAG(%a6)
6050        bra.b           WORK
6051LASTLOOP:
6052        clr.l           %d1                     # d0 = L := 0
6053        mov.b           &1,ENDFLAG(%a6)
6054
6055WORK:
6056#--FIND THE REMAINDER OF (R,r) W.R.T.   2**L * (PI/2). L IS SO CHOSEN
6057#--THAT INT( X * (2/PI) / 2**(L) ) < 2**29.
6058
6059#--CREATE 2**(-L) * (2/PI), SIGN(INARG)*2**(63),
6060#--2**L * (PIby2_1), 2**L * (PIby2_2)
6061
6062        mov.l           &0x00003FFE,%d2         # BIASED EXP OF 2/PI
6063        sub.l           %d1,%d2                 # BIASED EXP OF 2**(-L)*(2/PI)
6064
6065        mov.l           &0xA2F9836E,FP_SCR0_HI(%a6)
6066        mov.l           &0x4E44152A,FP_SCR0_LO(%a6)
6067        mov.w           %d2,FP_SCR0_EX(%a6)     # FP_SCR0 = 2**(-L)*(2/PI)
6068
6069        fmov.x          %fp0,%fp2
6070        fmul.x          FP_SCR0(%a6),%fp2       # fp2 = X * 2**(-L)*(2/PI)
6071
6072#--WE MUST NOW FIND INT(FP2). SINCE WE NEED THIS VALUE IN
6073#--FLOATING POINT FORMAT, THE TWO FMOVE'S       FMOVE.L FP <--> N
6074#--WILL BE TOO INEFFICIENT. THE WAY AROUND IT IS THAT
6075#--(SIGN(INARG)*2**63   +       FP2) - SIGN(INARG)*2**63 WILL GIVE
6076#--US THE DESIRED VALUE IN FLOATING POINT.
6077        mov.l           %a1,%d2
6078        swap            %d2
6079        and.l           &0x80000000,%d2
6080        or.l            &0x5F000000,%d2         # d2 = SIGN(INARG)*2**63 IN SGL
6081        mov.l           %d2,TWOTO63(%a6)
6082        fadd.s          TWOTO63(%a6),%fp2       # THE FRACTIONAL PART OF FP1 IS ROUNDED
6083        fsub.s          TWOTO63(%a6),%fp2       # fp2 = N
6084#       fintrz.x        %fp2,%fp2
6085
6086#--CREATING 2**(L)*Piby2_1 and 2**(L)*Piby2_2
6087        mov.l           %d1,%d2                 # d2 = L
6088
6089        add.l           &0x00003FFF,%d2         # BIASED EXP OF 2**L * (PI/2)
6090        mov.w           %d2,FP_SCR0_EX(%a6)
6091        mov.l           &0xC90FDAA2,FP_SCR0_HI(%a6)
6092        clr.l           FP_SCR0_LO(%a6)         # FP_SCR0 = 2**(L) * Piby2_1
6093
6094        add.l           &0x00003FDD,%d1
6095        mov.w           %d1,FP_SCR1_EX(%a6)
6096        mov.l           &0x85A308D3,FP_SCR1_HI(%a6)
6097        clr.l           FP_SCR1_LO(%a6)         # FP_SCR1 = 2**(L) * Piby2_2
6098
6099        mov.b           ENDFLAG(%a6),%d1
6100
6101#--We are now ready to perform (R+r) - N*P1 - N*P2, P1 = 2**(L) * Piby2_1 and
6102#--P2 = 2**(L) * Piby2_2
6103        fmov.x          %fp2,%fp4               # fp4 = N
6104        fmul.x          FP_SCR0(%a6),%fp4       # fp4 = W = N*P1
6105        fmov.x          %fp2,%fp5               # fp5 = N
6106        fmul.x          FP_SCR1(%a6),%fp5       # fp5 = w = N*P2
6107        fmov.x          %fp4,%fp3               # fp3 = W = N*P1
6108
6109#--we want P+p = W+w  but  |p| <= half ulp of P
6110#--Then, we need to compute  A := R-P   and  a := r-p
6111        fadd.x          %fp5,%fp3               # fp3 = P
6112        fsub.x          %fp3,%fp4               # fp4 = W-P
6113
6114        fsub.x          %fp3,%fp0               # fp0 = A := R - P
6115        fadd.x          %fp5,%fp4               # fp4 = p = (W-P)+w
6116
6117        fmov.x          %fp0,%fp3               # fp3 = A
6118        fsub.x          %fp4,%fp1               # fp1 = a := r - p
6119
6120#--Now we need to normalize (A,a) to  "new (R,r)" where R+r = A+a but
6121#--|r| <= half ulp of R.
6122        fadd.x          %fp1,%fp0               # fp0 = R := A+a
6123#--No need to calculate r if this is the last loop
6124        cmp.b           %d1,&0
6125        bgt.w           RESTORE
6126
6127#--Need to calculate r
6128        fsub.x          %fp0,%fp3               # fp3 = A-R
6129        fadd.x          %fp3,%fp1               # fp1 = r := (A-R)+a
6130        bra.w           LOOP
6131
6132RESTORE:
6133        fmov.l          %fp2,INT(%a6)
6134        mov.l           (%sp)+,%d2              # restore d2
6135        fmovm.x         (%sp)+,&0x3c            # restore {fp2-fp5}
6136
6137        mov.l           INT(%a6),%d1
6138        ror.l           &1,%d1
6139
6140        bra.w           TANCONT
6141
6142#########################################################################
6143# satan():  computes the arctangent of a normalized number              #
6144# satand(): computes the arctangent of a denormalized number            #
6145#                                                                       #
6146# INPUT *************************************************************** #
6147#       a0 = pointer to extended precision input                        #
6148#       d0 = round precision,mode                                       #
6149#                                                                       #
6150# OUTPUT ************************************************************** #
6151#       fp0 = arctan(X)                                                 #
6152#                                                                       #
6153# ACCURACY and MONOTONICITY ******************************************* #
6154#       The returned result is within 2 ulps in 64 significant bit,     #
6155#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
6156#       rounded to double precision. The result is provably monotonic   #
6157#       in double precision.                                            #
6158#                                                                       #
6159# ALGORITHM *********************************************************** #
6160#       Step 1. If |X| >= 16 or |X| < 1/16, go to Step 5.               #
6161#                                                                       #
6162#       Step 2. Let X = sgn * 2**k * 1.xxxxxxxx...x.                    #
6163#               Note that k = -4, -3,..., or 3.                         #
6164#               Define F = sgn * 2**k * 1.xxxx1, i.e. the first 5       #
6165#               significant bits of X with a bit-1 attached at the 6-th #
6166#               bit position. Define u to be u = (X-F) / (1 + X*F).     #
6167#                                                                       #
6168#       Step 3. Approximate arctan(u) by a polynomial poly.             #
6169#                                                                       #
6170#       Step 4. Return arctan(F) + poly, arctan(F) is fetched from a    #
6171#               table of values calculated beforehand. Exit.            #
6172#                                                                       #
6173#       Step 5. If |X| >= 16, go to Step 7.                             #
6174#                                                                       #
6175#       Step 6. Approximate arctan(X) by an odd polynomial in X. Exit.  #
6176#                                                                       #
6177#       Step 7. Define X' = -1/X. Approximate arctan(X') by an odd      #
6178#               polynomial in X'.                                       #
6179#               Arctan(X) = sign(X)*Pi/2 + arctan(X'). Exit.            #
6180#                                                                       #
6181#########################################################################
6182
6183ATANA3: long            0xBFF6687E,0x314987D8
6184ATANA2: long            0x4002AC69,0x34A26DB3
6185ATANA1: long            0xBFC2476F,0x4E1DA28E
6186
6187ATANB6: long            0x3FB34444,0x7F876989
6188ATANB5: long            0xBFB744EE,0x7FAF45DB
6189ATANB4: long            0x3FBC71C6,0x46940220
6190ATANB3: long            0xBFC24924,0x921872F9
6191ATANB2: long            0x3FC99999,0x99998FA9
6192ATANB1: long            0xBFD55555,0x55555555
6193
6194ATANC5: long            0xBFB70BF3,0x98539E6A
6195ATANC4: long            0x3FBC7187,0x962D1D7D
6196ATANC3: long            0xBFC24924,0x827107B8
6197ATANC2: long            0x3FC99999,0x9996263E
6198ATANC1: long            0xBFD55555,0x55555536
6199
6200PPIBY2: long            0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000
6201NPIBY2: long            0xBFFF0000,0xC90FDAA2,0x2168C235,0x00000000
6202
6203PTINY:  long            0x00010000,0x80000000,0x00000000,0x00000000
6204NTINY:  long            0x80010000,0x80000000,0x00000000,0x00000000
6205
6206ATANTBL:
6207        long            0x3FFB0000,0x83D152C5,0x060B7A51,0x00000000
6208        long            0x3FFB0000,0x8BC85445,0x65498B8B,0x00000000
6209        long            0x3FFB0000,0x93BE4060,0x17626B0D,0x00000000
6210        long            0x3FFB0000,0x9BB3078D,0x35AEC202,0x00000000
6211        long            0x3FFB0000,0xA3A69A52,0x5DDCE7DE,0x00000000
6212        long            0x3FFB0000,0xAB98E943,0x62765619,0x00000000
6213        long            0x3FFB0000,0xB389E502,0xF9C59862,0x00000000
6214        long            0x3FFB0000,0xBB797E43,0x6B09E6FB,0x00000000
6215        long            0x3FFB0000,0xC367A5C7,0x39E5F446,0x00000000
6216        long            0x3FFB0000,0xCB544C61,0xCFF7D5C6,0x00000000
6217        long            0x3FFB0000,0xD33F62F8,0x2488533E,0x00000000
6218        long            0x3FFB0000,0xDB28DA81,0x62404C77,0x00000000
6219        long            0x3FFB0000,0xE310A407,0x8AD34F18,0x00000000
6220        long            0x3FFB0000,0xEAF6B0A8,0x188EE1EB,0x00000000
6221        long            0x3FFB0000,0xF2DAF194,0x9DBE79D5,0x00000000
6222        long            0x3FFB0000,0xFABD5813,0x61D47E3E,0x00000000
6223        long            0x3FFC0000,0x8346AC21,0x0959ECC4,0x00000000
6224        long            0x3FFC0000,0x8B232A08,0x304282D8,0x00000000
6225        long            0x3FFC0000,0x92FB70B8,0xD29AE2F9,0x00000000
6226        long            0x3FFC0000,0x9ACF476F,0x5CCD1CB4,0x00000000
6227        long            0x3FFC0000,0xA29E7630,0x4954F23F,0x00000000
6228        long            0x3FFC0000,0xAA68C5D0,0x8AB85230,0x00000000
6229        long            0x3FFC0000,0xB22DFFFD,0x9D539F83,0x00000000
6230        long            0x3FFC0000,0xB9EDEF45,0x3E900EA5,0x00000000
6231        long            0x3FFC0000,0xC1A85F1C,0xC75E3EA5,0x00000000
6232        long            0x3FFC0000,0xC95D1BE8,0x28138DE6,0x00000000
6233        long            0x3FFC0000,0xD10BF300,0x840D2DE4,0x00000000
6234        long            0x3FFC0000,0xD8B4B2BA,0x6BC05E7A,0x00000000
6235        long            0x3FFC0000,0xE0572A6B,0xB42335F6,0x00000000
6236        long            0x3FFC0000,0xE7F32A70,0xEA9CAA8F,0x00000000
6237        long            0x3FFC0000,0xEF888432,0x64ECEFAA,0x00000000
6238        long            0x3FFC0000,0xF7170A28,0xECC06666,0x00000000
6239        long            0x3FFD0000,0x812FD288,0x332DAD32,0x00000000
6240        long            0x3FFD0000,0x88A8D1B1,0x218E4D64,0x00000000
6241        long            0x3FFD0000,0x9012AB3F,0x23E4AEE8,0x00000000
6242        long            0x3FFD0000,0x976CC3D4,0x11E7F1B9,0x00000000
6243        long            0x3FFD0000,0x9EB68949,0x3889A227,0x00000000
6244        long            0x3FFD0000,0xA5EF72C3,0x4487361B,0x00000000
6245        long            0x3FFD0000,0xAD1700BA,0xF07A7227,0x00000000
6246        long            0x3FFD0000,0xB42CBCFA,0xFD37EFB7,0x00000000
6247        long            0x3FFD0000,0xBB303A94,0x0BA80F89,0x00000000
6248        long            0x3FFD0000,0xC22115C6,0xFCAEBBAF,0x00000000
6249        long            0x3FFD0000,0xC8FEF3E6,0x86331221,0x00000000
6250        long            0x3FFD0000,0xCFC98330,0xB4000C70,0x00000000
6251        long            0x3FFD0000,0xD6807AA1,0x102C5BF9,0x00000000
6252        long            0x3FFD0000,0xDD2399BC,0x31252AA3,0x00000000
6253        long            0x3FFD0000,0xE3B2A855,0x6B8FC517,0x00000000
6254        long            0x3FFD0000,0xEA2D764F,0x64315989,0x00000000
6255        long            0x3FFD0000,0xF3BF5BF8,0xBAD1A21D,0x00000000
6256        long            0x3FFE0000,0x801CE39E,0x0D205C9A,0x00000000
6257        long            0x3FFE0000,0x8630A2DA,0xDA1ED066,0x00000000
6258        long            0x3FFE0000,0x8C1AD445,0xF3E09B8C,0x00000000
6259        long            0x3FFE0000,0x91DB8F16,0x64F350E2,0x00000000
6260        long            0x3FFE0000,0x97731420,0x365E538C,0x00000000
6261        long            0x3FFE0000,0x9CE1C8E6,0xA0B8CDBA,0x00000000
6262        long            0x3FFE0000,0xA22832DB,0xCADAAE09,0x00000000
6263        long            0x3FFE0000,0xA746F2DD,0xB7602294,0x00000000
6264        long            0x3FFE0000,0xAC3EC0FB,0x997DD6A2,0x00000000
6265        long            0x3FFE0000,0xB110688A,0xEBDC6F6A,0x00000000
6266        long            0x3FFE0000,0xB5BCC490,0x59ECC4B0,0x00000000
6267        long            0x3FFE0000,0xBA44BC7D,0xD470782F,0x00000000
6268        long            0x3FFE0000,0xBEA94144,0xFD049AAC,0x00000000
6269        long            0x3FFE0000,0xC2EB4ABB,0x661628B6,0x00000000
6270        long            0x3FFE0000,0xC70BD54C,0xE602EE14,0x00000000
6271        long            0x3FFE0000,0xCD000549,0xADEC7159,0x00000000
6272        long            0x3FFE0000,0xD48457D2,0xD8EA4EA3,0x00000000
6273        long            0x3FFE0000,0xDB948DA7,0x12DECE3B,0x00000000
6274        long            0x3FFE0000,0xE23855F9,0x69E8096A,0x00000000
6275        long            0x3FFE0000,0xE8771129,0xC4353259,0x00000000
6276        long            0x3FFE0000,0xEE57C16E,0x0D379C0D,0x00000000
6277        long            0x3FFE0000,0xF3E10211,0xA87C3779,0x00000000
6278        long            0x3FFE0000,0xF919039D,0x758B8D41,0x00000000
6279        long            0x3FFE0000,0xFE058B8F,0x64935FB3,0x00000000
6280        long            0x3FFF0000,0x8155FB49,0x7B685D04,0x00000000
6281        long            0x3FFF0000,0x83889E35,0x49D108E1,0x00000000
6282        long            0x3FFF0000,0x859CFA76,0x511D724B,0x00000000
6283        long            0x3FFF0000,0x87952ECF,0xFF8131E7,0x00000000
6284        long            0x3FFF0000,0x89732FD1,0x9557641B,0x00000000
6285        long            0x3FFF0000,0x8B38CAD1,0x01932A35,0x00000000
6286        long            0x3FFF0000,0x8CE7A8D8,0x301EE6B5,0x00000000
6287        long            0x3FFF0000,0x8F46A39E,0x2EAE5281,0x00000000
6288        long            0x3FFF0000,0x922DA7D7,0x91888487,0x00000000
6289        long            0x3FFF0000,0x94D19FCB,0xDEDF5241,0x00000000
6290        long            0x3FFF0000,0x973AB944,0x19D2A08B,0x00000000
6291        long            0x3FFF0000,0x996FF00E,0x08E10B96,0x00000000
6292        long            0x3FFF0000,0x9B773F95,0x12321DA7,0x00000000
6293        long            0x3FFF0000,0x9D55CC32,0x0F935624,0x00000000
6294        long            0x3FFF0000,0x9F100575,0x006CC571,0x00000000
6295        long            0x3FFF0000,0xA0A9C290,0xD97CC06C,0x00000000
6296        long            0x3FFF0000,0xA22659EB,0xEBC0630A,0x00000000
6297        long            0x3FFF0000,0xA388B4AF,0xF6EF0EC9,0x00000000
6298        long            0x3FFF0000,0xA4D35F10,0x61D292C4,0x00000000
6299        long            0x3FFF0000,0xA60895DC,0xFBE3187E,0x00000000
6300        long            0x3FFF0000,0xA72A51DC,0x7367BEAC,0x00000000
6301        long            0x3FFF0000,0xA83A5153,0x0956168F,0x00000000
6302        long            0x3FFF0000,0xA93A2007,0x7539546E,0x00000000
6303        long            0x3FFF0000,0xAA9E7245,0x023B2605,0x00000000
6304        long            0x3FFF0000,0xAC4C84BA,0x6FE4D58F,0x00000000
6305        long            0x3FFF0000,0xADCE4A4A,0x606B9712,0x00000000
6306        long            0x3FFF0000,0xAF2A2DCD,0x8D263C9C,0x00000000
6307        long            0x3FFF0000,0xB0656F81,0xF22265C7,0x00000000
6308        long            0x3FFF0000,0xB1846515,0x0F71496A,0x00000000
6309        long            0x3FFF0000,0xB28AAA15,0x6F9ADA35,0x00000000
6310        long            0x3FFF0000,0xB37B44FF,0x3766B895,0x00000000
6311        long            0x3FFF0000,0xB458C3DC,0xE9630433,0x00000000
6312        long            0x3FFF0000,0xB525529D,0x562246BD,0x00000000
6313        long            0x3FFF0000,0xB5E2CCA9,0x5F9D88CC,0x00000000
6314        long            0x3FFF0000,0xB692CADA,0x7ACA1ADA,0x00000000
6315        long            0x3FFF0000,0xB736AEA7,0xA6925838,0x00000000
6316        long            0x3FFF0000,0xB7CFAB28,0x7E9F7B36,0x00000000
6317        long            0x3FFF0000,0xB85ECC66,0xCB219835,0x00000000
6318        long            0x3FFF0000,0xB8E4FD5A,0x20A593DA,0x00000000
6319        long            0x3FFF0000,0xB99F41F6,0x4AFF9BB5,0x00000000
6320        long            0x3FFF0000,0xBA7F1E17,0x842BBE7B,0x00000000
6321        long            0x3FFF0000,0xBB471285,0x7637E17D,0x00000000
6322        long            0x3FFF0000,0xBBFABE8A,0x4788DF6F,0x00000000
6323        long            0x3FFF0000,0xBC9D0FAD,0x2B689D79,0x00000000
6324        long            0x3FFF0000,0xBD306A39,0x471ECD86,0x00000000
6325        long            0x3FFF0000,0xBDB6C731,0x856AF18A,0x00000000
6326        long            0x3FFF0000,0xBE31CAC5,0x02E80D70,0x00000000
6327        long            0x3FFF0000,0xBEA2D55C,0xE33194E2,0x00000000
6328        long            0x3FFF0000,0xBF0B10B7,0xC03128F0,0x00000000
6329        long            0x3FFF0000,0xBF6B7A18,0xDACB778D,0x00000000
6330        long            0x3FFF0000,0xBFC4EA46,0x63FA18F6,0x00000000
6331        long            0x3FFF0000,0xC0181BDE,0x8B89A454,0x00000000
6332        long            0x3FFF0000,0xC065B066,0xCFBF6439,0x00000000
6333        long            0x3FFF0000,0xC0AE345F,0x56340AE6,0x00000000
6334        long            0x3FFF0000,0xC0F22291,0x9CB9E6A7,0x00000000
6335
6336        set             X,FP_SCR0
6337        set             XDCARE,X+2
6338        set             XFRAC,X+4
6339        set             XFRACLO,X+8
6340
6341        set             ATANF,FP_SCR1
6342        set             ATANFHI,ATANF+4
6343        set             ATANFLO,ATANF+8
6344
6345        global          satan
6346#--ENTRY POINT FOR ATAN(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S
6347satan:
6348        fmov.x          (%a0),%fp0              # LOAD INPUT
6349
6350        mov.l           (%a0),%d1
6351        mov.w           4(%a0),%d1
6352        fmov.x          %fp0,X(%a6)
6353        and.l           &0x7FFFFFFF,%d1
6354
6355        cmp.l           %d1,&0x3FFB8000         # |X| >= 1/16?
6356        bge.b           ATANOK1
6357        bra.w           ATANSM
6358
6359ATANOK1:
6360        cmp.l           %d1,&0x4002FFFF         # |X| < 16 ?
6361        ble.b           ATANMAIN
6362        bra.w           ATANBIG
6363
6364#--THE MOST LIKELY CASE, |X| IN [1/16, 16). WE USE TABLE TECHNIQUE
6365#--THE IDEA IS ATAN(X) = ATAN(F) + ATAN( [X-F] / [1+XF] ).
6366#--SO IF F IS CHOSEN TO BE CLOSE TO X AND ATAN(F) IS STORED IN
6367#--A TABLE, ALL WE NEED IS TO APPROXIMATE ATAN(U) WHERE
6368#--U = (X-F)/(1+XF) IS SMALL (REMEMBER F IS CLOSE TO X). IT IS
6369#--TRUE THAT A DIVIDE IS NOW NEEDED, BUT THE APPROXIMATION FOR
6370#--ATAN(U) IS A VERY SHORT POLYNOMIAL AND THE INDEXING TO
6371#--FETCH F AND SAVING OF REGISTERS CAN BE ALL HIDED UNDER THE
6372#--DIVIDE. IN THE END THIS METHOD IS MUCH FASTER THAN A TRADITIONAL
6373#--ONE. NOTE ALSO THAT THE TRADITIONAL SCHEME THAT APPROXIMATE
6374#--ATAN(X) DIRECTLY WILL NEED TO USE A RATIONAL APPROXIMATION
6375#--(DIVISION NEEDED) ANYWAY BECAUSE A POLYNOMIAL APPROXIMATION
6376#--WILL INVOLVE A VERY LONG POLYNOMIAL.
6377
6378#--NOW WE SEE X AS +-2^K * 1.BBBBBBB....B <- 1. + 63 BITS
6379#--WE CHOSE F TO BE +-2^K * 1.BBBB1
6380#--THAT IS IT MATCHES THE EXPONENT AND FIRST 5 BITS OF X, THE
6381#--SIXTH BITS IS SET TO BE 1. SINCE K = -4, -3, ..., 3, THERE
6382#--ARE ONLY 8 TIMES 16 = 2^7 = 128 |F|'S. SINCE ATAN(-|F|) IS
6383#-- -ATAN(|F|), WE NEED TO STORE ONLY ATAN(|F|).
6384
6385ATANMAIN:
6386
6387        and.l           &0xF8000000,XFRAC(%a6)  # FIRST 5 BITS
6388        or.l            &0x04000000,XFRAC(%a6)  # SET 6-TH BIT TO 1
6389        mov.l           &0x00000000,XFRACLO(%a6) # LOCATION OF X IS NOW F
6390
6391        fmov.x          %fp0,%fp1               # FP1 IS X
6392        fmul.x          X(%a6),%fp1             # FP1 IS X*F, NOTE THAT X*F > 0
6393        fsub.x          X(%a6),%fp0             # FP0 IS X-F
6394        fadd.s          &0x3F800000,%fp1        # FP1 IS 1 + X*F
6395        fdiv.x          %fp1,%fp0               # FP0 IS U = (X-F)/(1+X*F)
6396
6397#--WHILE THE DIVISION IS TAKING ITS TIME, WE FETCH ATAN(|F|)
6398#--CREATE ATAN(F) AND STORE IT IN ATANF, AND
6399#--SAVE REGISTERS FP2.
6400
6401        mov.l           %d2,-(%sp)              # SAVE d2 TEMPORARILY
6402        mov.l           %d1,%d2                 # THE EXP AND 16 BITS OF X
6403        and.l           &0x00007800,%d1         # 4 VARYING BITS OF F'S FRACTION
6404        and.l           &0x7FFF0000,%d2         # EXPONENT OF F
6405        sub.l           &0x3FFB0000,%d2         # K+4
6406        asr.l           &1,%d2
6407        add.l           %d2,%d1                 # THE 7 BITS IDENTIFYING F
6408        asr.l           &7,%d1                  # INDEX INTO TBL OF ATAN(|F|)
6409        lea             ATANTBL(%pc),%a1
6410        add.l           %d1,%a1                 # ADDRESS OF ATAN(|F|)
6411        mov.l           (%a1)+,ATANF(%a6)
6412        mov.l           (%a1)+,ATANFHI(%a6)
6413        mov.l           (%a1)+,ATANFLO(%a6)     # ATANF IS NOW ATAN(|F|)
6414        mov.l           X(%a6),%d1              # LOAD SIGN AND EXPO. AGAIN
6415        and.l           &0x80000000,%d1         # SIGN(F)
6416        or.l            %d1,ATANF(%a6)          # ATANF IS NOW SIGN(F)*ATAN(|F|)
6417        mov.l           (%sp)+,%d2              # RESTORE d2
6418
6419#--THAT'S ALL I HAVE TO DO FOR NOW,
6420#--BUT ALAS, THE DIVIDE IS STILL CRANKING!
6421
6422#--U IN FP0, WE ARE NOW READY TO COMPUTE ATAN(U) AS
6423#--U + A1*U*V*(A2 + V*(A3 + V)), V = U*U
6424#--THE POLYNOMIAL MAY LOOK STRANGE, BUT IS NEVERTHELESS CORRECT.
6425#--THE NATURAL FORM IS U + U*V*(A1 + V*(A2 + V*A3))
6426#--WHAT WE HAVE HERE IS MERELY  A1 = A3, A2 = A1/A3, A3 = A2/A3.
6427#--THE REASON FOR THIS REARRANGEMENT IS TO MAKE THE INDEPENDENT
6428#--PARTS A1*U*V AND (A2 + ... STUFF) MORE LOAD-BALANCED
6429
6430        fmovm.x         &0x04,-(%sp)            # save fp2
6431
6432        fmov.x          %fp0,%fp1
6433        fmul.x          %fp1,%fp1
6434        fmov.d          ATANA3(%pc),%fp2
6435        fadd.x          %fp1,%fp2               # A3+V
6436        fmul.x          %fp1,%fp2               # V*(A3+V)
6437        fmul.x          %fp0,%fp1               # U*V
6438        fadd.d          ATANA2(%pc),%fp2        # A2+V*(A3+V)
6439        fmul.d          ATANA1(%pc),%fp1        # A1*U*V
6440        fmul.x          %fp2,%fp1               # A1*U*V*(A2+V*(A3+V))
6441        fadd.x          %fp1,%fp0               # ATAN(U), FP1 RELEASED
6442
6443        fmovm.x         (%sp)+,&0x20            # restore fp2
6444
6445        fmov.l          %d0,%fpcr               # restore users rnd mode,prec
6446        fadd.x          ATANF(%a6),%fp0         # ATAN(X)
6447        bra             t_inx2
6448
6449ATANBORS:
6450#--|X| IS IN d0 IN COMPACT FORM. FP1, d0 SAVED.
6451#--FP0 IS X AND |X| <= 1/16 OR |X| >= 16.
6452        cmp.l           %d1,&0x3FFF8000
6453        bgt.w           ATANBIG                 # I.E. |X| >= 16
6454
6455ATANSM:
6456#--|X| <= 1/16
6457#--IF |X| < 2^(-40), RETURN X AS ANSWER. OTHERWISE, APPROXIMATE
6458#--ATAN(X) BY X + X*Y*(B1+Y*(B2+Y*(B3+Y*(B4+Y*(B5+Y*B6)))))
6459#--WHICH IS X + X*Y*( [B1+Z*(B3+Z*B5)] + [Y*(B2+Z*(B4+Z*B6)] )
6460#--WHERE Y = X*X, AND Z = Y*Y.
6461
6462        cmp.l           %d1,&0x3FD78000
6463        blt.w           ATANTINY
6464
6465#--COMPUTE POLYNOMIAL
6466        fmovm.x         &0x0c,-(%sp)            # save fp2/fp3
6467
6468        fmul.x          %fp0,%fp0               # FPO IS Y = X*X
6469
6470        fmov.x          %fp0,%fp1
6471        fmul.x          %fp1,%fp1               # FP1 IS Z = Y*Y
6472
6473        fmov.d          ATANB6(%pc),%fp2
6474        fmov.d          ATANB5(%pc),%fp3
6475
6476        fmul.x          %fp1,%fp2               # Z*B6
6477        fmul.x          %fp1,%fp3               # Z*B5
6478
6479        fadd.d          ATANB4(%pc),%fp2        # B4+Z*B6
6480        fadd.d          ATANB3(%pc),%fp3        # B3+Z*B5
6481
6482        fmul.x          %fp1,%fp2               # Z*(B4+Z*B6)
6483        fmul.x          %fp3,%fp1               # Z*(B3+Z*B5)
6484
6485        fadd.d          ATANB2(%pc),%fp2        # B2+Z*(B4+Z*B6)
6486        fadd.d          ATANB1(%pc),%fp1        # B1+Z*(B3+Z*B5)
6487
6488        fmul.x          %fp0,%fp2               # Y*(B2+Z*(B4+Z*B6))
6489        fmul.x          X(%a6),%fp0             # X*Y
6490
6491        fadd.x          %fp2,%fp1               # [B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]
6492
6493        fmul.x          %fp1,%fp0               # X*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))])
6494
6495        fmovm.x         (%sp)+,&0x30            # restore fp2/fp3
6496
6497        fmov.l          %d0,%fpcr               # restore users rnd mode,prec
6498        fadd.x          X(%a6),%fp0
6499        bra             t_inx2
6500
6501ATANTINY:
6502#--|X| < 2^(-40), ATAN(X) = X
6503
6504        fmov.l          %d0,%fpcr               # restore users rnd mode,prec
6505        mov.b           &FMOV_OP,%d1            # last inst is MOVE
6506        fmov.x          X(%a6),%fp0             # last inst - possible exception set
6507
6508        bra             t_catch
6509
6510ATANBIG:
6511#--IF |X| > 2^(100), RETURN     SIGN(X)*(PI/2 - TINY). OTHERWISE,
6512#--RETURN SIGN(X)*PI/2 + ATAN(-1/X).
6513        cmp.l           %d1,&0x40638000
6514        bgt.w           ATANHUGE
6515
6516#--APPROXIMATE ATAN(-1/X) BY
6517#--X'+X'*Y*(C1+Y*(C2+Y*(C3+Y*(C4+Y*C5)))), X' = -1/X, Y = X'*X'
6518#--THIS CAN BE RE-WRITTEN AS
6519#--X'+X'*Y*( [C1+Z*(C3+Z*C5)] + [Y*(C2+Z*C4)] ), Z = Y*Y.
6520
6521        fmovm.x         &0x0c,-(%sp)            # save fp2/fp3
6522
6523        fmov.s          &0xBF800000,%fp1        # LOAD -1
6524        fdiv.x          %fp0,%fp1               # FP1 IS -1/X
6525
6526#--DIVIDE IS STILL CRANKING
6527
6528        fmov.x          %fp1,%fp0               # FP0 IS X'
6529        fmul.x          %fp0,%fp0               # FP0 IS Y = X'*X'
6530        fmov.x          %fp1,X(%a6)             # X IS REALLY X'
6531
6532        fmov.x          %fp0,%fp1
6533        fmul.x          %fp1,%fp1               # FP1 IS Z = Y*Y
6534
6535        fmov.d          ATANC5(%pc),%fp3
6536        fmov.d          ATANC4(%pc),%fp2
6537
6538        fmul.x          %fp1,%fp3               # Z*C5
6539        fmul.x          %fp1,%fp2               # Z*B4
6540
6541        fadd.d          ATANC3(%pc),%fp3        # C3+Z*C5
6542        fadd.d          ATANC2(%pc),%fp2        # C2+Z*C4
6543
6544        fmul.x          %fp3,%fp1               # Z*(C3+Z*C5), FP3 RELEASED
6545        fmul.x          %fp0,%fp2               # Y*(C2+Z*C4)
6546
6547        fadd.d          ATANC1(%pc),%fp1        # C1+Z*(C3+Z*C5)
6548        fmul.x          X(%a6),%fp0             # X'*Y
6549
6550        fadd.x          %fp2,%fp1               # [Y*(C2+Z*C4)]+[C1+Z*(C3+Z*C5)]
6551
6552        fmul.x          %fp1,%fp0               # X'*Y*([B1+Z*(B3+Z*B5)]
6553#                                       ...     +[Y*(B2+Z*(B4+Z*B6))])
6554        fadd.x          X(%a6),%fp0
6555
6556        fmovm.x         (%sp)+,&0x30            # restore fp2/fp3
6557
6558        fmov.l          %d0,%fpcr               # restore users rnd mode,prec
6559        tst.b           (%a0)
6560        bpl.b           pos_big
6561
6562neg_big:
6563        fadd.x          NPIBY2(%pc),%fp0
6564        bra             t_minx2
6565
6566pos_big:
6567        fadd.x          PPIBY2(%pc),%fp0
6568        bra             t_pinx2
6569
6570ATANHUGE:
6571#--RETURN SIGN(X)*(PIBY2 - TINY) = SIGN(X)*PIBY2 - SIGN(X)*TINY
6572        tst.b           (%a0)
6573        bpl.b           pos_huge
6574
6575neg_huge:
6576        fmov.x          NPIBY2(%pc),%fp0
6577        fmov.l          %d0,%fpcr
6578        fadd.x          PTINY(%pc),%fp0
6579        bra             t_minx2
6580
6581pos_huge:
6582        fmov.x          PPIBY2(%pc),%fp0
6583        fmov.l          %d0,%fpcr
6584        fadd.x          NTINY(%pc),%fp0
6585        bra             t_pinx2
6586
6587        global          satand
6588#--ENTRY POINT FOR ATAN(X) FOR DENORMALIZED ARGUMENT
6589satand:
6590        bra             t_extdnrm
6591
6592#########################################################################
6593# sasin():  computes the inverse sine of a normalized input             #
6594# sasind(): computes the inverse sine of a denormalized input           #
6595#                                                                       #
6596# INPUT *************************************************************** #
6597#       a0 = pointer to extended precision input                        #
6598#       d0 = round precision,mode                                       #
6599#                                                                       #
6600# OUTPUT ************************************************************** #
6601#       fp0 = arcsin(X)                                                 #
6602#                                                                       #
6603# ACCURACY and MONOTONICITY ******************************************* #
6604#       The returned result is within 3 ulps in 64 significant bit,     #
6605#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
6606#       rounded to double precision. The result is provably monotonic   #
6607#       in double precision.                                            #
6608#                                                                       #
6609# ALGORITHM *********************************************************** #
6610#                                                                       #
6611#       ASIN                                                            #
6612#       1. If |X| >= 1, go to 3.                                        #
6613#                                                                       #
6614#       2. (|X| < 1) Calculate asin(X) by                               #
6615#               z := sqrt( [1-X][1+X] )                                 #
6616#               asin(X) = atan( x / z ).                                #
6617#               Exit.                                                   #
6618#                                                                       #
6619#       3. If |X| > 1, go to 5.                                         #
6620#                                                                       #
6621#       4. (|X| = 1) sgn := sign(X), return asin(X) := sgn * Pi/2. Exit.#
6622#                                                                       #
6623#       5. (|X| > 1) Generate an invalid operation by 0 * infinity.     #
6624#               Exit.                                                   #
6625#                                                                       #
6626#########################################################################
6627
6628        global          sasin
6629sasin:
6630        fmov.x          (%a0),%fp0              # LOAD INPUT
6631
6632        mov.l           (%a0),%d1
6633        mov.w           4(%a0),%d1
6634        and.l           &0x7FFFFFFF,%d1
6635        cmp.l           %d1,&0x3FFF8000
6636        bge.b           ASINBIG
6637
6638# This catch is added here for the '060 QSP. Originally, the call to
6639# satan() would handle this case by causing the exception which would
6640# not be caught until gen_except(). Now, with the exceptions being
6641# detected inside of satan(), the exception would have been handled there
6642# instead of inside sasin() as expected.
6643        cmp.l           %d1,&0x3FD78000
6644        blt.w           ASINTINY
6645
6646#--THIS IS THE USUAL CASE, |X| < 1
6647#--ASIN(X) = ATAN( X / SQRT( (1-X)(1+X) ) )
6648
6649ASINMAIN:
6650        fmov.s          &0x3F800000,%fp1
6651        fsub.x          %fp0,%fp1               # 1-X
6652        fmovm.x         &0x4,-(%sp)             #  {fp2}
6653        fmov.s          &0x3F800000,%fp2
6654        fadd.x          %fp0,%fp2               # 1+X
6655        fmul.x          %fp2,%fp1               # (1+X)(1-X)
6656        fmovm.x         (%sp)+,&0x20            #  {fp2}
6657        fsqrt.x         %fp1                    # SQRT([1-X][1+X])
6658        fdiv.x          %fp1,%fp0               # X/SQRT([1-X][1+X])
6659        fmovm.x         &0x01,-(%sp)            # save X/SQRT(...)
6660        lea             (%sp),%a0               # pass ptr to X/SQRT(...)
6661        bsr             satan
6662        add.l           &0xc,%sp                # clear X/SQRT(...) from stack
6663        bra             t_inx2
6664
6665ASINBIG:
6666        fabs.x          %fp0                    # |X|
6667        fcmp.s          %fp0,&0x3F800000
6668        fbgt            t_operr                 # cause an operr exception
6669
6670#--|X| = 1, ASIN(X) = +- PI/2.
6671ASINONE:
6672        fmov.x          PIBY2(%pc),%fp0
6673        mov.l           (%a0),%d1
6674        and.l           &0x80000000,%d1         # SIGN BIT OF X
6675        or.l            &0x3F800000,%d1         # +-1 IN SGL FORMAT
6676        mov.l           %d1,-(%sp)              # push SIGN(X) IN SGL-FMT
6677        fmov.l          %d0,%fpcr
6678        fmul.s          (%sp)+,%fp0
6679        bra             t_inx2
6680
6681#--|X| < 2^(-40), ATAN(X) = X
6682ASINTINY:
6683        fmov.l          %d0,%fpcr               # restore users rnd mode,prec
6684        mov.b           &FMOV_OP,%d1            # last inst is MOVE
6685        fmov.x          (%a0),%fp0              # last inst - possible exception
6686        bra             t_catch
6687
6688        global          sasind
6689#--ASIN(X) = X FOR DENORMALIZED X
6690sasind:
6691        bra             t_extdnrm
6692
6693#########################################################################
6694# sacos():  computes the inverse cosine of a normalized input           #
6695# sacosd(): computes the inverse cosine of a denormalized input         #
6696#                                                                       #
6697# INPUT *************************************************************** #
6698#       a0 = pointer to extended precision input                        #
6699#       d0 = round precision,mode                                       #
6700#                                                                       #
6701# OUTPUT ************************************************************** #
6702#       fp0 = arccos(X)                                                 #
6703#                                                                       #
6704# ACCURACY and MONOTONICITY ******************************************* #
6705#       The returned result is within 3 ulps in 64 significant bit,     #
6706#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
6707#       rounded to double precision. The result is provably monotonic   #
6708#       in double precision.                                            #
6709#                                                                       #
6710# ALGORITHM *********************************************************** #
6711#                                                                       #
6712#       ACOS                                                            #
6713#       1. If |X| >= 1, go to 3.                                        #
6714#                                                                       #
6715#       2. (|X| < 1) Calculate acos(X) by                               #
6716#               z := (1-X) / (1+X)                                      #
6717#               acos(X) = 2 * atan( sqrt(z) ).                          #
6718#               Exit.                                                   #
6719#                                                                       #
6720#       3. If |X| > 1, go to 5.                                         #
6721#                                                                       #
6722#       4. (|X| = 1) If X > 0, return 0. Otherwise, return Pi. Exit.    #
6723#                                                                       #
6724#       5. (|X| > 1) Generate an invalid operation by 0 * infinity.     #
6725#               Exit.                                                   #
6726#                                                                       #
6727#########################################################################
6728
6729        global          sacos
6730sacos:
6731        fmov.x          (%a0),%fp0              # LOAD INPUT
6732
6733        mov.l           (%a0),%d1               # pack exp w/ upper 16 fraction
6734        mov.w           4(%a0),%d1
6735        and.l           &0x7FFFFFFF,%d1
6736        cmp.l           %d1,&0x3FFF8000
6737        bge.b           ACOSBIG
6738
6739#--THIS IS THE USUAL CASE, |X| < 1
6740#--ACOS(X) = 2 * ATAN(  SQRT( (1-X)/(1+X) ) )
6741
6742ACOSMAIN:
6743        fmov.s          &0x3F800000,%fp1
6744        fadd.x          %fp0,%fp1               # 1+X
6745        fneg.x          %fp0                    # -X
6746        fadd.s          &0x3F800000,%fp0        # 1-X
6747        fdiv.x          %fp1,%fp0               # (1-X)/(1+X)
6748        fsqrt.x         %fp0                    # SQRT((1-X)/(1+X))
6749        mov.l           %d0,-(%sp)              # save original users fpcr
6750        clr.l           %d0
6751        fmovm.x         &0x01,-(%sp)            # save SQRT(...) to stack
6752        lea             (%sp),%a0               # pass ptr to sqrt
6753        bsr             satan                   # ATAN(SQRT([1-X]/[1+X]))
6754        add.l           &0xc,%sp                # clear SQRT(...) from stack
6755
6756        fmov.l          (%sp)+,%fpcr            # restore users round prec,mode
6757        fadd.x          %fp0,%fp0               # 2 * ATAN( STUFF )
6758        bra             t_pinx2
6759
6760ACOSBIG:
6761        fabs.x          %fp0
6762        fcmp.s          %fp0,&0x3F800000
6763        fbgt            t_operr                 # cause an operr exception
6764
6765#--|X| = 1, ACOS(X) = 0 OR PI
6766        tst.b           (%a0)                   # is X positive or negative?
6767        bpl.b           ACOSP1
6768
6769#--X = -1
6770#Returns PI and inexact exception
6771ACOSM1:
6772        fmov.x          PI(%pc),%fp0            # load PI
6773        fmov.l          %d0,%fpcr               # load round mode,prec
6774        fadd.s          &0x00800000,%fp0        # add a small value
6775        bra             t_pinx2
6776
6777ACOSP1:
6778        bra             ld_pzero                # answer is positive zero
6779
6780        global          sacosd
6781#--ACOS(X) = PI/2 FOR DENORMALIZED X
6782sacosd:
6783        fmov.l          %d0,%fpcr               # load user's rnd mode/prec
6784        fmov.x          PIBY2(%pc),%fp0
6785        bra             t_pinx2
6786
6787#########################################################################
6788# setox():    computes the exponential for a normalized input           #
6789# setoxd():   computes the exponential for a denormalized input         #
6790# setoxm1():  computes the exponential minus 1 for a normalized input   #
6791# setoxm1d(): computes the exponential minus 1 for a denormalized input #
6792#                                                                       #
6793# INPUT *************************************************************** #
6794#       a0 = pointer to extended precision input                        #
6795#       d0 = round precision,mode                                       #
6796#                                                                       #
6797# OUTPUT ************************************************************** #
6798#       fp0 = exp(X) or exp(X)-1                                        #
6799#                                                                       #
6800# ACCURACY and MONOTONICITY ******************************************* #
6801#       The returned result is within 0.85 ulps in 64 significant bit,  #
6802#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
6803#       rounded to double precision. The result is provably monotonic   #
6804#       in double precision.                                            #
6805#                                                                       #
6806# ALGORITHM and IMPLEMENTATION **************************************** #
6807#                                                                       #
6808#       setoxd                                                          #
6809#       ------                                                          #
6810#       Step 1. Set ans := 1.0                                          #
6811#                                                                       #
6812#       Step 2. Return  ans := ans + sign(X)*2^(-126). Exit.            #
6813#       Notes:  This will always generate one exception -- inexact.     #
6814#                                                                       #
6815#                                                                       #
6816#       setox                                                           #
6817#       -----                                                           #
6818#                                                                       #
6819#       Step 1. Filter out extreme cases of input argument.             #
6820#               1.1     If |X| >= 2^(-65), go to Step 1.3.              #
6821#               1.2     Go to Step 7.                                   #
6822#               1.3     If |X| < 16380 log(2), go to Step 2.            #
6823#               1.4     Go to Step 8.                                   #
6824#       Notes:  The usual case should take the branches 1.1 -> 1.3 -> 2.#
6825#               To avoid the use of floating-point comparisons, a       #
6826#               compact representation of |X| is used. This format is a #
6827#               32-bit integer, the upper (more significant) 16 bits    #
6828#               are the sign and biased exponent field of |X|; the      #
6829#               lower 16 bits are the 16 most significant fraction      #
6830#               (including the explicit bit) bits of |X|. Consequently, #
6831#               the comparisons in Steps 1.1 and 1.3 can be performed   #
6832#               by integer comparison. Note also that the constant      #
6833#               16380 log(2) used in Step 1.3 is also in the compact    #
6834#               form. Thus taking the branch to Step 2 guarantees       #
6835#               |X| < 16380 log(2). There is no harm to have a small    #
6836#               number of cases where |X| is less than, but close to,   #
6837#               16380 log(2) and the branch to Step 9 is taken.         #
6838#                                                                       #
6839#       Step 2. Calculate N = round-to-nearest-int( X * 64/log2 ).      #
6840#               2.1     Set AdjFlag := 0 (indicates the branch 1.3 -> 2 #
6841#                       was taken)                                      #
6842#               2.2     N := round-to-nearest-integer( X * 64/log2 ).   #
6843#               2.3     Calculate       J = N mod 64; so J = 0,1,2,..., #
6844#                       or 63.                                          #
6845#               2.4     Calculate       M = (N - J)/64; so N = 64M + J. #
6846#               2.5     Calculate the address of the stored value of    #
6847#                       2^(J/64).                                       #
6848#               2.6     Create the value Scale = 2^M.                   #
6849#       Notes:  The calculation in 2.2 is really performed by           #
6850#                       Z := X * constant                               #
6851#                       N := round-to-nearest-integer(Z)                #
6852#               where                                                   #
6853#                       constant := single-precision( 64/log 2 ).       #
6854#                                                                       #
6855#               Using a single-precision constant avoids memory         #
6856#               access. Another effect of using a single-precision      #
6857#               "constant" is that the calculated value Z is            #
6858#                                                                       #
6859#                       Z = X*(64/log2)*(1+eps), |eps| <= 2^(-24).      #
6860#                                                                       #
6861#               This error has to be considered later in Steps 3 and 4. #
6862#                                                                       #
6863#       Step 3. Calculate X - N*log2/64.                                #
6864#               3.1     R := X + N*L1,                                  #
6865#                               where L1 := single-precision(-log2/64). #
6866#               3.2     R := R + N*L2,                                  #
6867#                               L2 := extended-precision(-log2/64 - L1).#
6868#       Notes:  a) The way L1 and L2 are chosen ensures L1+L2           #
6869#               approximate the value -log2/64 to 88 bits of accuracy.  #
6870#               b) N*L1 is exact because N is no longer than 22 bits    #
6871#               and L1 is no longer than 24 bits.                       #
6872#               c) The calculation X+N*L1 is also exact due to          #
6873#               cancellation. Thus, R is practically X+N(L1+L2) to full #
6874#               64 bits.                                                #
6875#               d) It is important to estimate how large can |R| be     #
6876#               after Step 3.2.                                         #
6877#                                                                       #
6878#               N = rnd-to-int( X*64/log2 (1+eps) ), |eps|<=2^(-24)     #
6879#               X*64/log2 (1+eps)       =       N + f,  |f| <= 0.5      #
6880#               X*64/log2 - N   =       f - eps*X 64/log2               #
6881#               X - N*log2/64   =       f*log2/64 - eps*X               #
6882#                                                                       #
6883#                                                                       #
6884#               Now |X| <= 16446 log2, thus                             #
6885#                                                                       #
6886#                       |X - N*log2/64| <= (0.5 + 16446/2^(18))*log2/64 #
6887#                                       <= 0.57 log2/64.                #
6888#                This bound will be used in Step 4.                     #
6889#                                                                       #
6890#       Step 4. Approximate exp(R)-1 by a polynomial                    #
6891#               p = R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5))))      #
6892#       Notes:  a) In order to reduce memory access, the coefficients   #
6893#               are made as "short" as possible: A1 (which is 1/2), A4  #
6894#               and A5 are single precision; A2 and A3 are double       #
6895#               precision.                                              #
6896#               b) Even with the restrictions above,                    #
6897#                  |p - (exp(R)-1)| < 2^(-68.8) for all |R| <= 0.0062.  #
6898#               Note that 0.0062 is slightly bigger than 0.57 log2/64.  #
6899#               c) To fully utilize the pipeline, p is separated into   #
6900#               two independent pieces of roughly equal complexities    #
6901#                       p = [ R + R*S*(A2 + S*A4) ]     +               #
6902#                               [ S*(A1 + S*(A3 + S*A5)) ]              #
6903#               where S = R*R.                                          #
6904#                                                                       #
6905#       Step 5. Compute 2^(J/64)*exp(R) = 2^(J/64)*(1+p) by             #
6906#                               ans := T + ( T*p + t)                   #
6907#               where T and t are the stored values for 2^(J/64).       #
6908#       Notes:  2^(J/64) is stored as T and t where T+t approximates    #
6909#               2^(J/64) to roughly 85 bits; T is in extended precision #
6910#               and t is in single precision. Note also that T is       #
6911#               rounded to 62 bits so that the last two bits of T are   #
6912#               zero. The reason for such a special form is that T-1,   #
6913#               T-2, and T-8 will all be exact --- a property that will #
6914#               give much more accurate computation of the function     #
6915#               EXPM1.                                                  #
6916#                                                                       #
6917#       Step 6. Reconstruction of exp(X)                                #
6918#                       exp(X) = 2^M * 2^(J/64) * exp(R).               #
6919#               6.1     If AdjFlag = 0, go to 6.3                       #
6920#               6.2     ans := ans * AdjScale                           #
6921#               6.3     Restore the user FPCR                           #
6922#               6.4     Return ans := ans * Scale. Exit.                #
6923#       Notes:  If AdjFlag = 0, we have X = Mlog2 + Jlog2/64 + R,       #
6924#               |M| <= 16380, and Scale = 2^M. Moreover, exp(X) will    #
6925#               neither overflow nor underflow. If AdjFlag = 1, that    #
6926#               means that                                              #
6927#                       X = (M1+M)log2 + Jlog2/64 + R, |M1+M| >= 16380. #
6928#               Hence, exp(X) may overflow or underflow or neither.     #
6929#               When that is the case, AdjScale = 2^(M1) where M1 is    #
6930#               approximately M. Thus 6.2 will never cause              #
6931#               over/underflow. Possible exception in 6.4 is overflow   #
6932#               or underflow. The inexact exception is not generated in #
6933#               6.4. Although one can argue that the inexact flag       #
6934#               should always be raised, to simulate that exception     #
6935#               cost to much than the flag is worth in practical uses.  #
6936#                                                                       #
6937#       Step 7. Return 1 + X.                                           #
6938#               7.1     ans := X                                        #
6939#               7.2     Restore user FPCR.                              #
6940#               7.3     Return ans := 1 + ans. Exit                     #
6941#       Notes:  For non-zero X, the inexact exception will always be    #
6942#               raised by 7.3. That is the only exception raised by 7.3.#
6943#               Note also that we use the FMOVEM instruction to move X  #
6944#               in Step 7.1 to avoid unnecessary trapping. (Although    #
6945#               the FMOVEM may not seem relevant since X is normalized, #
6946#               the precaution will be useful in the library version of #
6947#               this code where the separate entry for denormalized     #
6948#               inputs will be done away with.)                         #
6949#                                                                       #
6950#       Step 8. Handle exp(X) where |X| >= 16380log2.                   #
6951#               8.1     If |X| > 16480 log2, go to Step 9.              #
6952#               (mimic 2.2 - 2.6)                                       #
6953#               8.2     N := round-to-integer( X * 64/log2 )            #
6954#               8.3     Calculate J = N mod 64, J = 0,1,...,63          #
6955#               8.4     K := (N-J)/64, M1 := truncate(K/2), M = K-M1,   #
6956#                       AdjFlag := 1.                                   #
6957#               8.5     Calculate the address of the stored value       #
6958#                       2^(J/64).                                       #
6959#               8.6     Create the values Scale = 2^M, AdjScale = 2^M1. #
6960#               8.7     Go to Step 3.                                   #
6961#       Notes:  Refer to notes for 2.2 - 2.6.                           #
6962#                                                                       #
6963#       Step 9. Handle exp(X), |X| > 16480 log2.                        #
6964#               9.1     If X < 0, go to 9.3                             #
6965#               9.2     ans := Huge, go to 9.4                          #
6966#               9.3     ans := Tiny.                                    #
6967#               9.4     Restore user FPCR.                              #
6968#               9.5     Return ans := ans * ans. Exit.                  #
6969#       Notes:  Exp(X) will surely overflow or underflow, depending on  #
6970#               X's sign. "Huge" and "Tiny" are respectively large/tiny #
6971#               extended-precision numbers whose square over/underflow  #
6972#               with an inexact result. Thus, 9.5 always raises the     #
6973#               inexact together with either overflow or underflow.     #
6974#                                                                       #
6975#       setoxm1d                                                        #
6976#       --------                                                        #
6977#                                                                       #
6978#       Step 1. Set ans := 0                                            #
6979#                                                                       #
6980#       Step 2. Return  ans := X + ans. Exit.                           #
6981#       Notes:  This will return X with the appropriate rounding        #
6982#                precision prescribed by the user FPCR.                 #
6983#                                                                       #
6984#       setoxm1                                                         #
6985#       -------                                                         #
6986#                                                                       #
6987#       Step 1. Check |X|                                               #
6988#               1.1     If |X| >= 1/4, go to Step 1.3.                  #
6989#               1.2     Go to Step 7.                                   #
6990#               1.3     If |X| < 70 log(2), go to Step 2.               #
6991#               1.4     Go to Step 10.                                  #
6992#       Notes:  The usual case should take the branches 1.1 -> 1.3 -> 2.#
6993#               However, it is conceivable |X| can be small very often  #
6994#               because EXPM1 is intended to evaluate exp(X)-1          #
6995#               accurately when |X| is small. For further details on    #
6996#               the comparisons, see the notes on Step 1 of setox.      #
6997#                                                                       #
6998#       Step 2. Calculate N = round-to-nearest-int( X * 64/log2 ).      #
6999#               2.1     N := round-to-nearest-integer( X * 64/log2 ).   #
7000#               2.2     Calculate       J = N mod 64; so J = 0,1,2,..., #
7001#                       or 63.                                          #
7002#               2.3     Calculate       M = (N - J)/64; so N = 64M + J. #
7003#               2.4     Calculate the address of the stored value of    #
7004#                       2^(J/64).                                       #
7005#               2.5     Create the values Sc = 2^M and                  #
7006#                       OnebySc := -2^(-M).                             #
7007#       Notes:  See the notes on Step 2 of setox.                       #
7008#                                                                       #
7009#       Step 3. Calculate X - N*log2/64.                                #
7010#               3.1     R := X + N*L1,                                  #
7011#                               where L1 := single-precision(-log2/64). #
7012#               3.2     R := R + N*L2,                                  #
7013#                               L2 := extended-precision(-log2/64 - L1).#
7014#       Notes:  Applying the analysis of Step 3 of setox in this case   #
7015#               shows that |R| <= 0.0055 (note that |X| <= 70 log2 in   #
7016#               this case).                                             #
7017#                                                                       #
7018#       Step 4. Approximate exp(R)-1 by a polynomial                    #
7019#                       p = R+R*R*(A1+R*(A2+R*(A3+R*(A4+R*(A5+R*A6))))) #
7020#       Notes:  a) In order to reduce memory access, the coefficients   #
7021#               are made as "short" as possible: A1 (which is 1/2), A5  #
7022#               and A6 are single precision; A2, A3 and A4 are double   #
7023#               precision.                                              #
7024#               b) Even with the restriction above,                     #
7025#                       |p - (exp(R)-1)| <      |R| * 2^(-72.7)         #
7026#               for all |R| <= 0.0055.                                  #
7027#               c) To fully utilize the pipeline, p is separated into   #
7028#               two independent pieces of roughly equal complexity      #
7029#                       p = [ R*S*(A2 + S*(A4 + S*A6)) ]        +       #
7030#                               [ R + S*(A1 + S*(A3 + S*A5)) ]          #
7031#               where S = R*R.                                          #
7032#                                                                       #
7033#       Step 5. Compute 2^(J/64)*p by                                   #
7034#                               p := T*p                                #
7035#               where T and t are the stored values for 2^(J/64).       #
7036#       Notes:  2^(J/64) is stored as T and t where T+t approximates    #
7037#               2^(J/64) to roughly 85 bits; T is in extended precision #
7038#               and t is in single precision. Note also that T is       #
7039#               rounded to 62 bits so that the last two bits of T are   #
7040#               zero. The reason for such a special form is that T-1,   #
7041#               T-2, and T-8 will all be exact --- a property that will #
7042#               be exploited in Step 6 below. The total relative error  #
7043#               in p is no bigger than 2^(-67.7) compared to the final  #
7044#               result.                                                 #
7045#                                                                       #
7046#       Step 6. Reconstruction of exp(X)-1                              #
7047#                       exp(X)-1 = 2^M * ( 2^(J/64) + p - 2^(-M) ).     #
7048#               6.1     If M <= 63, go to Step 6.3.                     #
7049#               6.2     ans := T + (p + (t + OnebySc)). Go to 6.6       #
7050#               6.3     If M >= -3, go to 6.5.                          #
7051#               6.4     ans := (T + (p + t)) + OnebySc. Go to 6.6       #
7052#               6.5     ans := (T + OnebySc) + (p + t).                 #
7053#               6.6     Restore user FPCR.                              #
7054#               6.7     Return ans := Sc * ans. Exit.                   #
7055#       Notes:  The various arrangements of the expressions give        #
7056#               accurate evaluations.                                   #
7057#                                                                       #
7058#       Step 7. exp(X)-1 for |X| < 1/4.                                 #
7059#               7.1     If |X| >= 2^(-65), go to Step 9.                #
7060#               7.2     Go to Step 8.                                   #
7061#                                                                       #
7062#       Step 8. Calculate exp(X)-1, |X| < 2^(-65).                      #
7063#               8.1     If |X| < 2^(-16312), goto 8.3                   #
7064#               8.2     Restore FPCR; return ans := X - 2^(-16382).     #
7065#                       Exit.                                           #
7066#               8.3     X := X * 2^(140).                               #
7067#               8.4     Restore FPCR; ans := ans - 2^(-16382).          #
7068#                Return ans := ans*2^(140). Exit                        #
7069#       Notes:  The idea is to return "X - tiny" under the user         #
7070#               precision and rounding modes. To avoid unnecessary      #
7071#               inefficiency, we stay away from denormalized numbers    #
7072#               the best we can. For |X| >= 2^(-16312), the             #
7073#               straightforward 8.2 generates the inexact exception as  #
7074#               the case warrants.                                      #
7075#                                                                       #
7076#       Step 9. Calculate exp(X)-1, |X| < 1/4, by a polynomial          #
7077#                       p = X + X*X*(B1 + X*(B2 + ... + X*B12))         #
7078#       Notes:  a) In order to reduce memory access, the coefficients   #
7079#               are made as "short" as possible: B1 (which is 1/2), B9  #
7080#               to B12 are single precision; B3 to B8 are double        #
7081#               precision; and B2 is double extended.                   #
7082#               b) Even with the restriction above,                     #
7083#                       |p - (exp(X)-1)| < |X| 2^(-70.6)                #
7084#               for all |X| <= 0.251.                                   #
7085#               Note that 0.251 is slightly bigger than 1/4.            #
7086#               c) To fully preserve accuracy, the polynomial is        #
7087#               computed as                                             #
7088#                       X + ( S*B1 +    Q ) where S = X*X and           #
7089#                       Q       =       X*S*(B2 + X*(B3 + ... + X*B12)) #
7090#               d) To fully utilize the pipeline, Q is separated into   #
7091#               two independent pieces of roughly equal complexity      #
7092#                       Q = [ X*S*(B2 + S*(B4 + ... + S*B12)) ] +       #
7093#                               [ S*S*(B3 + S*(B5 + ... + S*B11)) ]     #
7094#                                                                       #
7095#       Step 10. Calculate exp(X)-1 for |X| >= 70 log 2.                #
7096#               10.1 If X >= 70log2 , exp(X) - 1 = exp(X) for all       #
7097#               practical purposes. Therefore, go to Step 1 of setox.   #
7098#               10.2 If X <= -70log2, exp(X) - 1 = -1 for all practical #
7099#               purposes.                                               #
7100#               ans := -1                                               #
7101#               Restore user FPCR                                       #
7102#               Return ans := ans + 2^(-126). Exit.                     #
7103#       Notes:  10.2 will always create an inexact and return -1 + tiny #
7104#               in the user rounding precision and mode.                #
7105#                                                                       #
7106#########################################################################
7107
7108L2:     long            0x3FDC0000,0x82E30865,0x4361C4C6,0x00000000
7109
7110EEXPA3: long            0x3FA55555,0x55554CC1
7111EEXPA2: long            0x3FC55555,0x55554A54
7112
7113EM1A4:  long            0x3F811111,0x11174385
7114EM1A3:  long            0x3FA55555,0x55554F5A
7115
7116EM1A2:  long            0x3FC55555,0x55555555,0x00000000,0x00000000
7117
7118EM1B8:  long            0x3EC71DE3,0xA5774682
7119EM1B7:  long            0x3EFA01A0,0x19D7CB68
7120
7121EM1B6:  long            0x3F2A01A0,0x1A019DF3
7122EM1B5:  long            0x3F56C16C,0x16C170E2
7123
7124EM1B4:  long            0x3F811111,0x11111111
7125EM1B3:  long            0x3FA55555,0x55555555
7126
7127EM1B2:  long            0x3FFC0000,0xAAAAAAAA,0xAAAAAAAB
7128        long            0x00000000
7129
7130TWO140: long            0x48B00000,0x00000000
7131TWON140:
7132        long            0x37300000,0x00000000
7133
7134EEXPTBL:
7135        long            0x3FFF0000,0x80000000,0x00000000,0x00000000
7136        long            0x3FFF0000,0x8164D1F3,0xBC030774,0x9F841A9B
7137        long            0x3FFF0000,0x82CD8698,0xAC2BA1D8,0x9FC1D5B9
7138        long            0x3FFF0000,0x843A28C3,0xACDE4048,0xA0728369
7139        long            0x3FFF0000,0x85AAC367,0xCC487B14,0x1FC5C95C
7140        long            0x3FFF0000,0x871F6196,0x9E8D1010,0x1EE85C9F
7141        long            0x3FFF0000,0x88980E80,0x92DA8528,0x9FA20729
7142        long            0x3FFF0000,0x8A14D575,0x496EFD9C,0xA07BF9AF
7143        long            0x3FFF0000,0x8B95C1E3,0xEA8BD6E8,0xA0020DCF
7144        long            0x3FFF0000,0x8D1ADF5B,0x7E5BA9E4,0x205A63DA
7145        long            0x3FFF0000,0x8EA4398B,0x45CD53C0,0x1EB70051
7146        long            0x3FFF0000,0x9031DC43,0x1466B1DC,0x1F6EB029
7147        long            0x3FFF0000,0x91C3D373,0xAB11C338,0xA0781494
7148        long            0x3FFF0000,0x935A2B2F,0x13E6E92C,0x9EB319B0
7149        long            0x3FFF0000,0x94F4EFA8,0xFEF70960,0x2017457D
7150        long            0x3FFF0000,0x96942D37,0x20185A00,0x1F11D537
7151        long            0x3FFF0000,0x9837F051,0x8DB8A970,0x9FB952DD
7152        long            0x3FFF0000,0x99E04593,0x20B7FA64,0x1FE43087
7153        long            0x3FFF0000,0x9B8D39B9,0xD54E5538,0x1FA2A818
7154        long            0x3FFF0000,0x9D3ED9A7,0x2CFFB750,0x1FDE494D
7155        long            0x3FFF0000,0x9EF53260,0x91A111AC,0x20504890
7156        long            0x3FFF0000,0xA0B0510F,0xB9714FC4,0xA073691C
7157        long            0x3FFF0000,0xA2704303,0x0C496818,0x1F9B7A05
7158        long            0x3FFF0000,0xA43515AE,0x09E680A0,0xA0797126
7159        long            0x3FFF0000,0xA5FED6A9,0xB15138EC,0xA071A140
7160        long            0x3FFF0000,0xA7CD93B4,0xE9653568,0x204F62DA
7161        long            0x3FFF0000,0xA9A15AB4,0xEA7C0EF8,0x1F283C4A
7162        long            0x3FFF0000,0xAB7A39B5,0xA93ED338,0x9F9A7FDC
7163        long            0x3FFF0000,0xAD583EEA,0x42A14AC8,0xA05B3FAC
7164        long            0x3FFF0000,0xAF3B78AD,0x690A4374,0x1FDF2610
7165        long            0x3FFF0000,0xB123F581,0xD2AC2590,0x9F705F90
7166        long            0x3FFF0000,0xB311C412,0xA9112488,0x201F678A
7167        long            0x3FFF0000,0xB504F333,0xF9DE6484,0x1F32FB13
7168        long            0x3FFF0000,0xB6FD91E3,0x28D17790,0x20038B30
7169        long            0x3FFF0000,0xB8FBAF47,0x62FB9EE8,0x200DC3CC
7170        long            0x3FFF0000,0xBAFF5AB2,0x133E45FC,0x9F8B2AE6
7171        long            0x3FFF0000,0xBD08A39F,0x580C36C0,0xA02BBF70
7172        long            0x3FFF0000,0xBF1799B6,0x7A731084,0xA00BF518
7173        long            0x3FFF0000,0xC12C4CCA,0x66709458,0xA041DD41
7174        long            0x3FFF0000,0xC346CCDA,0x24976408,0x9FDF137B
7175        long            0x3FFF0000,0xC5672A11,0x5506DADC,0x201F1568
7176        long            0x3FFF0000,0xC78D74C8,0xABB9B15C,0x1FC13A2E
7177        long            0x3FFF0000,0xC9B9BD86,0x6E2F27A4,0xA03F8F03
7178        long            0x3FFF0000,0xCBEC14FE,0xF2727C5C,0x1FF4907D
7179        long            0x3FFF0000,0xCE248C15,0x1F8480E4,0x9E6E53E4
7180        long            0x3FFF0000,0xD06333DA,0xEF2B2594,0x1FD6D45C
7181        long            0x3FFF0000,0xD2A81D91,0xF12AE45C,0xA076EDB9
7182        long            0x3FFF0000,0xD4F35AAB,0xCFEDFA20,0x9FA6DE21
7183        long            0x3FFF0000,0xD744FCCA,0xD69D6AF4,0x1EE69A2F
7184        long            0x3FFF0000,0xD99D15C2,0x78AFD7B4,0x207F439F
7185        long            0x3FFF0000,0xDBFBB797,0xDAF23754,0x201EC207
7186        long            0x3FFF0000,0xDE60F482,0x5E0E9124,0x9E8BE175
7187        long            0x3FFF0000,0xE0CCDEEC,0x2A94E110,0x20032C4B
7188        long            0x3FFF0000,0xE33F8972,0xBE8A5A50,0x2004DFF5
7189        long            0x3FFF0000,0xE5B906E7,0x7C8348A8,0x1E72F47A
7190        long            0x3FFF0000,0xE8396A50,0x3C4BDC68,0x1F722F22
7191        long            0x3FFF0000,0xEAC0C6E7,0xDD243930,0xA017E945
7192        long            0x3FFF0000,0xED4F301E,0xD9942B84,0x1F401A5B
7193        long            0x3FFF0000,0xEFE4B99B,0xDCDAF5CC,0x9FB9A9E3
7194        long            0x3FFF0000,0xF281773C,0x59FFB138,0x20744C05
7195        long            0x3FFF0000,0xF5257D15,0x2486CC2C,0x1F773A19
7196        long            0x3FFF0000,0xF7D0DF73,0x0AD13BB8,0x1FFE90D5
7197        long            0x3FFF0000,0xFA83B2DB,0x722A033C,0xA041ED22
7198        long            0x3FFF0000,0xFD3E0C0C,0xF486C174,0x1F853F3A
7199
7200        set             ADJFLAG,L_SCR2
7201        set             SCALE,FP_SCR0
7202        set             ADJSCALE,FP_SCR1
7203        set             SC,FP_SCR0
7204        set             ONEBYSC,FP_SCR1
7205
7206        global          setox
7207setox:
7208#--entry point for EXP(X), here X is finite, non-zero, and not NaN's
7209
7210#--Step 1.
7211        mov.l           (%a0),%d1               # load part of input X
7212        and.l           &0x7FFF0000,%d1         # biased expo. of X
7213        cmp.l           %d1,&0x3FBE0000         # 2^(-65)
7214        bge.b           EXPC1                   # normal case
7215        bra             EXPSM
7216
7217EXPC1:
7218#--The case |X| >= 2^(-65)
7219        mov.w           4(%a0),%d1              # expo. and partial sig. of |X|
7220        cmp.l           %d1,&0x400CB167         # 16380 log2 trunc. 16 bits
7221        blt.b           EXPMAIN                 # normal case
7222        bra             EEXPBIG
7223
7224EXPMAIN:
7225#--Step 2.
7226#--This is the normal branch:   2^(-65) <= |X| < 16380 log2.
7227        fmov.x          (%a0),%fp0              # load input from (a0)
7228
7229        fmov.x          %fp0,%fp1
7230        fmul.s          &0x42B8AA3B,%fp0        # 64/log2 * X
7231        fmovm.x         &0xc,-(%sp)             # save fp2 {%fp2/%fp3}
7232        mov.l           &0,ADJFLAG(%a6)
7233        fmov.l          %fp0,%d1                # N = int( X * 64/log2 )
7234        lea             EEXPTBL(%pc),%a1
7235        fmov.l          %d1,%fp0                # convert to floating-format
7236
7237        mov.l           %d1,L_SCR1(%a6)         # save N temporarily
7238        and.l           &0x3F,%d1               # D0 is J = N mod 64
7239        lsl.l           &4,%d1
7240        add.l           %d1,%a1                 # address of 2^(J/64)
7241        mov.l           L_SCR1(%a6),%d1
7242        asr.l           &6,%d1                  # D0 is M
7243        add.w           &0x3FFF,%d1             # biased expo. of 2^(M)
7244        mov.w           L2(%pc),L_SCR1(%a6)     # prefetch L2, no need in CB
7245
7246EXPCONT1:
7247#--Step 3.
7248#--fp1,fp2 saved on the stack. fp0 is N, fp1 is X,
7249#--a0 points to 2^(J/64), D0 is biased expo. of 2^(M)
7250        fmov.x          %fp0,%fp2
7251        fmul.s          &0xBC317218,%fp0        # N * L1, L1 = lead(-log2/64)
7252        fmul.x          L2(%pc),%fp2            # N * L2, L1+L2 = -log2/64
7253        fadd.x          %fp1,%fp0               # X + N*L1
7254        fadd.x          %fp2,%fp0               # fp0 is R, reduced arg.
7255
7256#--Step 4.
7257#--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL
7258#-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5))))
7259#--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R
7260#--[R+R*S*(A2+S*A4)] + [S*(A1+S*(A3+S*A5))]
7261
7262        fmov.x          %fp0,%fp1
7263        fmul.x          %fp1,%fp1               # fp1 IS S = R*R
7264
7265        fmov.s          &0x3AB60B70,%fp2        # fp2 IS A5
7266
7267        fmul.x          %fp1,%fp2               # fp2 IS S*A5
7268        fmov.x          %fp1,%fp3
7269        fmul.s          &0x3C088895,%fp3        # fp3 IS S*A4
7270
7271        fadd.d          EEXPA3(%pc),%fp2        # fp2 IS A3+S*A5
7272        fadd.d          EEXPA2(%pc),%fp3        # fp3 IS A2+S*A4
7273
7274        fmul.x          %fp1,%fp2               # fp2 IS S*(A3+S*A5)
7275        mov.w           %d1,SCALE(%a6)          # SCALE is 2^(M) in extended
7276        mov.l           &0x80000000,SCALE+4(%a6)
7277        clr.l           SCALE+8(%a6)
7278
7279        fmul.x          %fp1,%fp3               # fp3 IS S*(A2+S*A4)
7280
7281        fadd.s          &0x3F000000,%fp2        # fp2 IS A1+S*(A3+S*A5)
7282        fmul.x          %fp0,%fp3               # fp3 IS R*S*(A2+S*A4)
7283
7284        fmul.x          %fp1,%fp2               # fp2 IS S*(A1+S*(A3+S*A5))
7285        fadd.x          %fp3,%fp0               # fp0 IS R+R*S*(A2+S*A4),
7286
7287        fmov.x          (%a1)+,%fp1             # fp1 is lead. pt. of 2^(J/64)
7288        fadd.x          %fp2,%fp0               # fp0 is EXP(R) - 1
7289
7290#--Step 5
7291#--final reconstruction process
7292#--EXP(X) = 2^M * ( 2^(J/64) + 2^(J/64)*(EXP(R)-1) )
7293
7294        fmul.x          %fp1,%fp0               # 2^(J/64)*(Exp(R)-1)
7295        fmovm.x         (%sp)+,&0x30            # fp2 restored {%fp2/%fp3}
7296        fadd.s          (%a1),%fp0              # accurate 2^(J/64)
7297
7298        fadd.x          %fp1,%fp0               # 2^(J/64) + 2^(J/64)*...
7299        mov.l           ADJFLAG(%a6),%d1
7300
7301#--Step 6
7302        tst.l           %d1
7303        beq.b           NORMAL
7304ADJUST:
7305        fmul.x          ADJSCALE(%a6),%fp0
7306NORMAL:
7307        fmov.l          %d0,%fpcr               # restore user FPCR
7308        mov.b           &FMUL_OP,%d1            # last inst is MUL
7309        fmul.x          SCALE(%a6),%fp0         # multiply 2^(M)
7310        bra             t_catch
7311
7312EXPSM:
7313#--Step 7
7314        fmovm.x         (%a0),&0x80             # load X
7315        fmov.l          %d0,%fpcr
7316        fadd.s          &0x3F800000,%fp0        # 1+X in user mode
7317        bra             t_pinx2
7318
7319EEXPBIG:
7320#--Step 8
7321        cmp.l           %d1,&0x400CB27C         # 16480 log2
7322        bgt.b           EXP2BIG
7323#--Steps 8.2 -- 8.6
7324        fmov.x          (%a0),%fp0              # load input from (a0)
7325
7326        fmov.x          %fp0,%fp1
7327        fmul.s          &0x42B8AA3B,%fp0        # 64/log2 * X
7328        fmovm.x         &0xc,-(%sp)             # save fp2 {%fp2/%fp3}
7329        mov.l           &1,ADJFLAG(%a6)
7330        fmov.l          %fp0,%d1                # N = int( X * 64/log2 )
7331        lea             EEXPTBL(%pc),%a1
7332        fmov.l          %d1,%fp0                # convert to floating-format
7333        mov.l           %d1,L_SCR1(%a6)         # save N temporarily
7334        and.l           &0x3F,%d1               # D0 is J = N mod 64
7335        lsl.l           &4,%d1
7336        add.l           %d1,%a1                 # address of 2^(J/64)
7337        mov.l           L_SCR1(%a6),%d1
7338        asr.l           &6,%d1                  # D0 is K
7339        mov.l           %d1,L_SCR1(%a6)         # save K temporarily
7340        asr.l           &1,%d1                  # D0 is M1
7341        sub.l           %d1,L_SCR1(%a6)         # a1 is M
7342        add.w           &0x3FFF,%d1             # biased expo. of 2^(M1)
7343        mov.w           %d1,ADJSCALE(%a6)       # ADJSCALE := 2^(M1)
7344        mov.l           &0x80000000,ADJSCALE+4(%a6)
7345        clr.l           ADJSCALE+8(%a6)
7346        mov.l           L_SCR1(%a6),%d1         # D0 is M
7347        add.w           &0x3FFF,%d1             # biased expo. of 2^(M)
7348        bra.w           EXPCONT1                # go back to Step 3
7349
7350EXP2BIG:
7351#--Step 9
7352        tst.b           (%a0)                   # is X positive or negative?
7353        bmi             t_unfl2
7354        bra             t_ovfl2
7355
7356        global          setoxd
7357setoxd:
7358#--entry point for EXP(X), X is denormalized
7359        mov.l           (%a0),-(%sp)
7360        andi.l          &0x80000000,(%sp)
7361        ori.l           &0x00800000,(%sp)       # sign(X)*2^(-126)
7362
7363        fmov.s          &0x3F800000,%fp0
7364
7365        fmov.l          %d0,%fpcr
7366        fadd.s          (%sp)+,%fp0
7367        bra             t_pinx2
7368
7369        global          setoxm1
7370setoxm1:
7371#--entry point for EXPM1(X), here X is finite, non-zero, non-NaN
7372
7373#--Step 1.
7374#--Step 1.1
7375        mov.l           (%a0),%d1               # load part of input X
7376        and.l           &0x7FFF0000,%d1         # biased expo. of X
7377        cmp.l           %d1,&0x3FFD0000         # 1/4
7378        bge.b           EM1CON1                 # |X| >= 1/4
7379        bra             EM1SM
7380
7381EM1CON1:
7382#--Step 1.3
7383#--The case |X| >= 1/4
7384        mov.w           4(%a0),%d1              # expo. and partial sig. of |X|
7385        cmp.l           %d1,&0x4004C215         # 70log2 rounded up to 16 bits
7386        ble.b           EM1MAIN                 # 1/4 <= |X| <= 70log2
7387        bra             EM1BIG
7388
7389EM1MAIN:
7390#--Step 2.
7391#--This is the case:    1/4 <= |X| <= 70 log2.
7392        fmov.x          (%a0),%fp0              # load input from (a0)
7393
7394        fmov.x          %fp0,%fp1
7395        fmul.s          &0x42B8AA3B,%fp0        # 64/log2 * X
7396        fmovm.x         &0xc,-(%sp)             # save fp2 {%fp2/%fp3}
7397        fmov.l          %fp0,%d1                # N = int( X * 64/log2 )
7398        lea             EEXPTBL(%pc),%a1
7399        fmov.l          %d1,%fp0                # convert to floating-format
7400
7401        mov.l           %d1,L_SCR1(%a6)         # save N temporarily
7402        and.l           &0x3F,%d1               # D0 is J = N mod 64
7403        lsl.l           &4,%d1
7404        add.l           %d1,%a1                 # address of 2^(J/64)
7405        mov.l           L_SCR1(%a6),%d1
7406        asr.l           &6,%d1                  # D0 is M
7407        mov.l           %d1,L_SCR1(%a6)         # save a copy of M
7408
7409#--Step 3.
7410#--fp1,fp2 saved on the stack. fp0 is N, fp1 is X,
7411#--a0 points to 2^(J/64), D0 and a1 both contain M
7412        fmov.x          %fp0,%fp2
7413        fmul.s          &0xBC317218,%fp0        # N * L1, L1 = lead(-log2/64)
7414        fmul.x          L2(%pc),%fp2            # N * L2, L1+L2 = -log2/64
7415        fadd.x          %fp1,%fp0               # X + N*L1
7416        fadd.x          %fp2,%fp0               # fp0 is R, reduced arg.
7417        add.w           &0x3FFF,%d1             # D0 is biased expo. of 2^M
7418
7419#--Step 4.
7420#--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL
7421#-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*(A5 + R*A6)))))
7422#--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R
7423#--[R*S*(A2+S*(A4+S*A6))] + [R+S*(A1+S*(A3+S*A5))]
7424
7425        fmov.x          %fp0,%fp1
7426        fmul.x          %fp1,%fp1               # fp1 IS S = R*R
7427
7428        fmov.s          &0x3950097B,%fp2        # fp2 IS a6
7429
7430        fmul.x          %fp1,%fp2               # fp2 IS S*A6
7431        fmov.x          %fp1,%fp3
7432        fmul.s          &0x3AB60B6A,%fp3        # fp3 IS S*A5
7433
7434        fadd.d          EM1A4(%pc),%fp2         # fp2 IS A4+S*A6
7435        fadd.d          EM1A3(%pc),%fp3         # fp3 IS A3+S*A5
7436        mov.w           %d1,SC(%a6)             # SC is 2^(M) in extended
7437        mov.l           &0x80000000,SC+4(%a6)
7438        clr.l           SC+8(%a6)
7439
7440        fmul.x          %fp1,%fp2               # fp2 IS S*(A4+S*A6)
7441        mov.l           L_SCR1(%a6),%d1         # D0 is M
7442        neg.w           %d1                     # D0 is -M
7443        fmul.x          %fp1,%fp3               # fp3 IS S*(A3+S*A5)
7444        add.w           &0x3FFF,%d1             # biased expo. of 2^(-M)
7445        fadd.d          EM1A2(%pc),%fp2         # fp2 IS A2+S*(A4+S*A6)
7446        fadd.s          &0x3F000000,%fp3        # fp3 IS A1+S*(A3+S*A5)
7447
7448        fmul.x          %fp1,%fp2               # fp2 IS S*(A2+S*(A4+S*A6))
7449        or.w            &0x8000,%d1             # signed/expo. of -2^(-M)
7450        mov.w           %d1,ONEBYSC(%a6)        # OnebySc is -2^(-M)
7451        mov.l           &0x80000000,ONEBYSC+4(%a6)
7452        clr.l           ONEBYSC+8(%a6)
7453        fmul.x          %fp3,%fp1               # fp1 IS S*(A1+S*(A3+S*A5))
7454
7455        fmul.x          %fp0,%fp2               # fp2 IS R*S*(A2+S*(A4+S*A6))
7456        fadd.x          %fp1,%fp0               # fp0 IS R+S*(A1+S*(A3+S*A5))
7457
7458        fadd.x          %fp2,%fp0               # fp0 IS EXP(R)-1
7459
7460        fmovm.x         (%sp)+,&0x30            # fp2 restored {%fp2/%fp3}
7461
7462#--Step 5
7463#--Compute 2^(J/64)*p
7464
7465        fmul.x          (%a1),%fp0              # 2^(J/64)*(Exp(R)-1)
7466
7467#--Step 6
7468#--Step 6.1
7469        mov.l           L_SCR1(%a6),%d1         # retrieve M
7470        cmp.l           %d1,&63
7471        ble.b           MLE63
7472#--Step 6.2     M >= 64
7473        fmov.s          12(%a1),%fp1            # fp1 is t
7474        fadd.x          ONEBYSC(%a6),%fp1       # fp1 is t+OnebySc
7475        fadd.x          %fp1,%fp0               # p+(t+OnebySc), fp1 released
7476        fadd.x          (%a1),%fp0              # T+(p+(t+OnebySc))
7477        bra             EM1SCALE
7478MLE63:
7479#--Step 6.3     M <= 63
7480        cmp.l           %d1,&-3
7481        bge.b           MGEN3
7482MLTN3:
7483#--Step 6.4     M <= -4
7484        fadd.s          12(%a1),%fp0            # p+t
7485        fadd.x          (%a1),%fp0              # T+(p+t)
7486        fadd.x          ONEBYSC(%a6),%fp0       # OnebySc + (T+(p+t))
7487        bra             EM1SCALE
7488MGEN3:
7489#--Step 6.5     -3 <= M <= 63
7490        fmov.x          (%a1)+,%fp1             # fp1 is T
7491        fadd.s          (%a1),%fp0              # fp0 is p+t
7492        fadd.x          ONEBYSC(%a6),%fp1       # fp1 is T+OnebySc
7493        fadd.x          %fp1,%fp0               # (T+OnebySc)+(p+t)
7494
7495EM1SCALE:
7496#--Step 6.6
7497        fmov.l          %d0,%fpcr
7498        fmul.x          SC(%a6),%fp0
7499        bra             t_inx2
7500
7501EM1SM:
7502#--Step 7       |X| < 1/4.
7503        cmp.l           %d1,&0x3FBE0000         # 2^(-65)
7504        bge.b           EM1POLY
7505
7506EM1TINY:
7507#--Step 8       |X| < 2^(-65)
7508        cmp.l           %d1,&0x00330000         # 2^(-16312)
7509        blt.b           EM12TINY
7510#--Step 8.2
7511        mov.l           &0x80010000,SC(%a6)     # SC is -2^(-16382)
7512        mov.l           &0x80000000,SC+4(%a6)
7513        clr.l           SC+8(%a6)
7514        fmov.x          (%a0),%fp0
7515        fmov.l          %d0,%fpcr
7516        mov.b           &FADD_OP,%d1            # last inst is ADD
7517        fadd.x          SC(%a6),%fp0
7518        bra             t_catch
7519
7520EM12TINY:
7521#--Step 8.3
7522        fmov.x          (%a0),%fp0
7523        fmul.d          TWO140(%pc),%fp0
7524        mov.l           &0x80010000,SC(%a6)
7525        mov.l           &0x80000000,SC+4(%a6)
7526        clr.l           SC+8(%a6)
7527        fadd.x          SC(%a6),%fp0
7528        fmov.l          %d0,%fpcr
7529        mov.b           &FMUL_OP,%d1            # last inst is MUL
7530        fmul.d          TWON140(%pc),%fp0
7531        bra             t_catch
7532
7533EM1POLY:
7534#--Step 9       exp(X)-1 by a simple polynomial
7535        fmov.x          (%a0),%fp0              # fp0 is X
7536        fmul.x          %fp0,%fp0               # fp0 is S := X*X
7537        fmovm.x         &0xc,-(%sp)             # save fp2 {%fp2/%fp3}
7538        fmov.s          &0x2F30CAA8,%fp1        # fp1 is B12
7539        fmul.x          %fp0,%fp1               # fp1 is S*B12
7540        fmov.s          &0x310F8290,%fp2        # fp2 is B11
7541        fadd.s          &0x32D73220,%fp1        # fp1 is B10+S*B12
7542
7543        fmul.x          %fp0,%fp2               # fp2 is S*B11
7544        fmul.x          %fp0,%fp1               # fp1 is S*(B10 + ...
7545
7546        fadd.s          &0x3493F281,%fp2        # fp2 is B9+S*...
7547        fadd.d          EM1B8(%pc),%fp1         # fp1 is B8+S*...
7548
7549        fmul.x          %fp0,%fp2               # fp2 is S*(B9+...
7550        fmul.x          %fp0,%fp1               # fp1 is S*(B8+...
7551
7552        fadd.d          EM1B7(%pc),%fp2         # fp2 is B7+S*...
7553        fadd.d          EM1B6(%pc),%fp1         # fp1 is B6+S*...
7554
7555        fmul.x          %fp0,%fp2               # fp2 is S*(B7+...
7556        fmul.x          %fp0,%fp1               # fp1 is S*(B6+...
7557
7558        fadd.d          EM1B5(%pc),%fp2         # fp2 is B5+S*...
7559        fadd.d          EM1B4(%pc),%fp1         # fp1 is B4+S*...
7560
7561        fmul.x          %fp0,%fp2               # fp2 is S*(B5+...
7562        fmul.x          %fp0,%fp1               # fp1 is S*(B4+...
7563
7564        fadd.d          EM1B3(%pc),%fp2         # fp2 is B3+S*...
7565        fadd.x          EM1B2(%pc),%fp1         # fp1 is B2+S*...
7566
7567        fmul.x          %fp0,%fp2               # fp2 is S*(B3+...
7568        fmul.x          %fp0,%fp1               # fp1 is S*(B2+...
7569
7570        fmul.x          %fp0,%fp2               # fp2 is S*S*(B3+...)
7571        fmul.x          (%a0),%fp1              # fp1 is X*S*(B2...
7572
7573        fmul.s          &0x3F000000,%fp0        # fp0 is S*B1
7574        fadd.x          %fp2,%fp1               # fp1 is Q
7575
7576        fmovm.x         (%sp)+,&0x30            # fp2 restored {%fp2/%fp3}
7577
7578        fadd.x          %fp1,%fp0               # fp0 is S*B1+Q
7579
7580        fmov.l          %d0,%fpcr
7581        fadd.x          (%a0),%fp0
7582        bra             t_inx2
7583
7584EM1BIG:
7585#--Step 10      |X| > 70 log2
7586        mov.l           (%a0),%d1
7587        cmp.l           %d1,&0
7588        bgt.w           EXPC1
7589#--Step 10.2
7590        fmov.s          &0xBF800000,%fp0        # fp0 is -1
7591        fmov.l          %d0,%fpcr
7592        fadd.s          &0x00800000,%fp0        # -1 + 2^(-126)
7593        bra             t_minx2
7594
7595        global          setoxm1d
7596setoxm1d:
7597#--entry point for EXPM1(X), here X is denormalized
7598#--Step 0.
7599        bra             t_extdnrm
7600
7601#########################################################################
7602# sgetexp():  returns the exponent portion of the input argument.       #
7603#             The exponent bias is removed and the exponent value is    #
7604#             returned as an extended precision number in fp0.          #
7605# sgetexpd(): handles denormalized numbers.                             #
7606#                                                                       #
7607# sgetman():  extracts the mantissa of the input argument. The          #
7608#             mantissa is converted to an extended precision number w/  #
7609#             an exponent of $3fff and is returned in fp0. The range of #
7610#             the result is [1.0 - 2.0).                                #
7611# sgetmand(): handles denormalized numbers.                             #
7612#                                                                       #
7613# INPUT *************************************************************** #
7614#       a0  = pointer to extended precision input                       #
7615#                                                                       #
7616# OUTPUT ************************************************************** #
7617#       fp0 = exponent(X) or mantissa(X)                                #
7618#                                                                       #
7619#########################################################################
7620
7621        global          sgetexp
7622sgetexp:
7623        mov.w           SRC_EX(%a0),%d0         # get the exponent
7624        bclr            &0xf,%d0                # clear the sign bit
7625        subi.w          &0x3fff,%d0             # subtract off the bias
7626        fmov.w          %d0,%fp0                # return exp in fp0
7627        blt.b           sgetexpn                # it's negative
7628        rts
7629
7630sgetexpn:
7631        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
7632        rts
7633
7634        global          sgetexpd
7635sgetexpd:
7636        bsr.l           norm                    # normalize
7637        neg.w           %d0                     # new exp = -(shft amt)
7638        subi.w          &0x3fff,%d0             # subtract off the bias
7639        fmov.w          %d0,%fp0                # return exp in fp0
7640        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
7641        rts
7642
7643        global          sgetman
7644sgetman:
7645        mov.w           SRC_EX(%a0),%d0         # get the exp
7646        ori.w           &0x7fff,%d0             # clear old exp
7647        bclr            &0xe,%d0                # make it the new exp +-3fff
7648
7649# here, we build the result in a tmp location so as not to disturb the input
7650        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6) # copy to tmp loc
7651        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6) # copy to tmp loc
7652        mov.w           %d0,FP_SCR0_EX(%a6)     # insert new exponent
7653        fmov.x          FP_SCR0(%a6),%fp0       # put new value back in fp0
7654        bmi.b           sgetmann                # it's negative
7655        rts
7656
7657sgetmann:
7658        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
7659        rts
7660
7661#
7662# For denormalized numbers, shift the mantissa until the j-bit = 1,
7663# then load the exponent with +/1 $3fff.
7664#
7665        global          sgetmand
7666sgetmand:
7667        bsr.l           norm                    # normalize exponent
7668        bra.b           sgetman
7669
7670#########################################################################
7671# scosh():  computes the hyperbolic cosine of a normalized input        #
7672# scoshd(): computes the hyperbolic cosine of a denormalized input      #
7673#                                                                       #
7674# INPUT *************************************************************** #
7675#       a0 = pointer to extended precision input                        #
7676#       d0 = round precision,mode                                       #
7677#                                                                       #
7678# OUTPUT ************************************************************** #
7679#       fp0 = cosh(X)                                                   #
7680#                                                                       #
7681# ACCURACY and MONOTONICITY ******************************************* #
7682#       The returned result is within 3 ulps in 64 significant bit,     #
7683#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
7684#       rounded to double precision. The result is provably monotonic   #
7685#       in double precision.                                            #
7686#                                                                       #
7687# ALGORITHM *********************************************************** #
7688#                                                                       #
7689#       COSH                                                            #
7690#       1. If |X| > 16380 log2, go to 3.                                #
7691#                                                                       #
7692#       2. (|X| <= 16380 log2) Cosh(X) is obtained by the formulae      #
7693#               y = |X|, z = exp(Y), and                                #
7694#               cosh(X) = (1/2)*( z + 1/z ).                            #
7695#               Exit.                                                   #
7696#                                                                       #
7697#       3. (|X| > 16380 log2). If |X| > 16480 log2, go to 5.            #
7698#                                                                       #
7699#       4. (16380 log2 < |X| <= 16480 log2)                             #
7700#               cosh(X) = sign(X) * exp(|X|)/2.                         #
7701#               However, invoking exp(|X|) may cause premature          #
7702#               overflow. Thus, we calculate sinh(X) as follows:        #
7703#               Y       := |X|                                          #
7704#               Fact    :=      2**(16380)                              #
7705#               Y'      := Y - 16381 log2                               #
7706#               cosh(X) := Fact * exp(Y').                              #
7707#               Exit.                                                   #
7708#                                                                       #
7709#       5. (|X| > 16480 log2) sinh(X) must overflow. Return             #
7710#               Huge*Huge to generate overflow and an infinity with     #
7711#               the appropriate sign. Huge is the largest finite number #
7712#               in extended format. Exit.                               #
7713#                                                                       #
7714#########################################################################
7715
7716TWO16380:
7717        long            0x7FFB0000,0x80000000,0x00000000,0x00000000
7718
7719        global          scosh
7720scosh:
7721        fmov.x          (%a0),%fp0              # LOAD INPUT
7722
7723        mov.l           (%a0),%d1
7724        mov.w           4(%a0),%d1
7725        and.l           &0x7FFFFFFF,%d1
7726        cmp.l           %d1,&0x400CB167
7727        bgt.b           COSHBIG
7728
7729#--THIS IS THE USUAL CASE, |X| < 16380 LOG2
7730#--COSH(X) = (1/2) * ( EXP(X) + 1/EXP(X) )
7731
7732        fabs.x          %fp0                    # |X|
7733
7734        mov.l           %d0,-(%sp)
7735        clr.l           %d0
7736        fmovm.x         &0x01,-(%sp)            # save |X| to stack
7737        lea             (%sp),%a0               # pass ptr to |X|
7738        bsr             setox                   # FP0 IS EXP(|X|)
7739        add.l           &0xc,%sp                # erase |X| from stack
7740        fmul.s          &0x3F000000,%fp0        # (1/2)EXP(|X|)
7741        mov.l           (%sp)+,%d0
7742
7743        fmov.s          &0x3E800000,%fp1        # (1/4)
7744        fdiv.x          %fp0,%fp1               # 1/(2 EXP(|X|))
7745
7746        fmov.l          %d0,%fpcr
7747        mov.b           &FADD_OP,%d1            # last inst is ADD
7748        fadd.x          %fp1,%fp0
7749        bra             t_catch
7750
7751COSHBIG:
7752        cmp.l           %d1,&0x400CB2B3
7753        bgt.b           COSHHUGE
7754
7755        fabs.x          %fp0
7756        fsub.d          T1(%pc),%fp0            # (|X|-16381LOG2_LEAD)
7757        fsub.d          T2(%pc),%fp0            # |X| - 16381 LOG2, ACCURATE
7758
7759        mov.l           %d0,-(%sp)
7760        clr.l           %d0
7761        fmovm.x         &0x01,-(%sp)            # save fp0 to stack
7762        lea             (%sp),%a0               # pass ptr to fp0
7763        bsr             setox
7764        add.l           &0xc,%sp                # clear fp0 from stack
7765        mov.l           (%sp)+,%d0
7766
7767        fmov.l          %d0,%fpcr
7768        mov.b           &FMUL_OP,%d1            # last inst is MUL
7769        fmul.x          TWO16380(%pc),%fp0
7770        bra             t_catch
7771
7772COSHHUGE:
7773        bra             t_ovfl2
7774
7775        global          scoshd
7776#--COSH(X) = 1 FOR DENORMALIZED X
7777scoshd:
7778        fmov.s          &0x3F800000,%fp0
7779
7780        fmov.l          %d0,%fpcr
7781        fadd.s          &0x00800000,%fp0
7782        bra             t_pinx2
7783
7784#########################################################################
7785# ssinh():  computes the hyperbolic sine of a normalized input          #
7786# ssinhd(): computes the hyperbolic sine of a denormalized input        #
7787#                                                                       #
7788# INPUT *************************************************************** #
7789#       a0 = pointer to extended precision input                        #
7790#       d0 = round precision,mode                                       #
7791#                                                                       #
7792# OUTPUT ************************************************************** #
7793#       fp0 = sinh(X)                                                   #
7794#                                                                       #
7795# ACCURACY and MONOTONICITY ******************************************* #
7796#       The returned result is within 3 ulps in 64 significant bit,     #
7797#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
7798#       rounded to double precision. The result is provably monotonic   #
7799#       in double precision.                                            #
7800#                                                                       #
7801# ALGORITHM *********************************************************** #
7802#                                                                       #
7803#       SINH                                                            #
7804#       1. If |X| > 16380 log2, go to 3.                                #
7805#                                                                       #
7806#       2. (|X| <= 16380 log2) Sinh(X) is obtained by the formula       #
7807#               y = |X|, sgn = sign(X), and z = expm1(Y),               #
7808#               sinh(X) = sgn*(1/2)*( z + z/(1+z) ).                    #
7809#          Exit.                                                        #
7810#                                                                       #
7811#       3. If |X| > 16480 log2, go to 5.                                #
7812#                                                                       #
7813#       4. (16380 log2 < |X| <= 16480 log2)                             #
7814#               sinh(X) = sign(X) * exp(|X|)/2.                         #
7815#          However, invoking exp(|X|) may cause premature overflow.     #
7816#          Thus, we calculate sinh(X) as follows:                       #
7817#             Y       := |X|                                            #
7818#             sgn     := sign(X)                                        #
7819#             sgnFact := sgn * 2**(16380)                               #
7820#             Y'      := Y - 16381 log2                                 #
7821#             sinh(X) := sgnFact * exp(Y').                             #
7822#          Exit.                                                        #
7823#                                                                       #
7824#       5. (|X| > 16480 log2) sinh(X) must overflow. Return             #
7825#          sign(X)*Huge*Huge to generate overflow and an infinity with  #
7826#          the appropriate sign. Huge is the largest finite number in   #
7827#          extended format. Exit.                                       #
7828#                                                                       #
7829#########################################################################
7830
7831        global          ssinh
7832ssinh:
7833        fmov.x          (%a0),%fp0              # LOAD INPUT
7834
7835        mov.l           (%a0),%d1
7836        mov.w           4(%a0),%d1
7837        mov.l           %d1,%a1                 # save (compacted) operand
7838        and.l           &0x7FFFFFFF,%d1
7839        cmp.l           %d1,&0x400CB167
7840        bgt.b           SINHBIG
7841
7842#--THIS IS THE USUAL CASE, |X| < 16380 LOG2
7843#--Y = |X|, Z = EXPM1(Y), SINH(X) = SIGN(X)*(1/2)*( Z + Z/(1+Z) )
7844
7845        fabs.x          %fp0                    # Y = |X|
7846
7847        movm.l          &0x8040,-(%sp)          # {a1/d0}
7848        fmovm.x         &0x01,-(%sp)            # save Y on stack
7849        lea             (%sp),%a0               # pass ptr to Y
7850        clr.l           %d0
7851        bsr             setoxm1                 # FP0 IS Z = EXPM1(Y)
7852        add.l           &0xc,%sp                # clear Y from stack
7853        fmov.l          &0,%fpcr
7854        movm.l          (%sp)+,&0x0201          # {a1/d0}
7855
7856        fmov.x          %fp0,%fp1
7857        fadd.s          &0x3F800000,%fp1        # 1+Z
7858        fmov.x          %fp0,-(%sp)
7859        fdiv.x          %fp1,%fp0               # Z/(1+Z)
7860        mov.l           %a1,%d1
7861        and.l           &0x80000000,%d1
7862        or.l            &0x3F000000,%d1
7863        fadd.x          (%sp)+,%fp0
7864        mov.l           %d1,-(%sp)
7865
7866        fmov.l          %d0,%fpcr
7867        mov.b           &FMUL_OP,%d1            # last inst is MUL
7868        fmul.s          (%sp)+,%fp0             # last fp inst - possible exceptions set
7869        bra             t_catch
7870
7871SINHBIG:
7872        cmp.l           %d1,&0x400CB2B3
7873        bgt             t_ovfl
7874        fabs.x          %fp0
7875        fsub.d          T1(%pc),%fp0            # (|X|-16381LOG2_LEAD)
7876        mov.l           &0,-(%sp)
7877        mov.l           &0x80000000,-(%sp)
7878        mov.l           %a1,%d1
7879        and.l           &0x80000000,%d1
7880        or.l            &0x7FFB0000,%d1
7881        mov.l           %d1,-(%sp)              # EXTENDED FMT
7882        fsub.d          T2(%pc),%fp0            # |X| - 16381 LOG2, ACCURATE
7883
7884        mov.l           %d0,-(%sp)
7885        clr.l           %d0
7886        fmovm.x         &0x01,-(%sp)            # save fp0 on stack
7887        lea             (%sp),%a0               # pass ptr to fp0
7888        bsr             setox
7889        add.l           &0xc,%sp                # clear fp0 from stack
7890
7891        mov.l           (%sp)+,%d0
7892        fmov.l          %d0,%fpcr
7893        mov.b           &FMUL_OP,%d1            # last inst is MUL
7894        fmul.x          (%sp)+,%fp0             # possible exception
7895        bra             t_catch
7896
7897        global          ssinhd
7898#--SINH(X) = X FOR DENORMALIZED X
7899ssinhd:
7900        bra             t_extdnrm
7901
7902#########################################################################
7903# stanh():  computes the hyperbolic tangent of a normalized input       #
7904# stanhd(): computes the hyperbolic tangent of a denormalized input     #
7905#                                                                       #
7906# INPUT *************************************************************** #
7907#       a0 = pointer to extended precision input                        #
7908#       d0 = round precision,mode                                       #
7909#                                                                       #
7910# OUTPUT ************************************************************** #
7911#       fp0 = tanh(X)                                                   #
7912#                                                                       #
7913# ACCURACY and MONOTONICITY ******************************************* #
7914#       The returned result is within 3 ulps in 64 significant bit,     #
7915#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
7916#       rounded to double precision. The result is provably monotonic   #
7917#       in double precision.                                            #
7918#                                                                       #
7919# ALGORITHM *********************************************************** #
7920#                                                                       #
7921#       TANH                                                            #
7922#       1. If |X| >= (5/2) log2 or |X| <= 2**(-40), go to 3.            #
7923#                                                                       #
7924#       2. (2**(-40) < |X| < (5/2) log2) Calculate tanh(X) by           #
7925#               sgn := sign(X), y := 2|X|, z := expm1(Y), and           #
7926#               tanh(X) = sgn*( z/(2+z) ).                              #
7927#               Exit.                                                   #
7928#                                                                       #
7929#       3. (|X| <= 2**(-40) or |X| >= (5/2) log2). If |X| < 1,          #
7930#               go to 7.                                                #
7931#                                                                       #
7932#       4. (|X| >= (5/2) log2) If |X| >= 50 log2, go to 6.              #
7933#                                                                       #
7934#       5. ((5/2) log2 <= |X| < 50 log2) Calculate tanh(X) by           #
7935#               sgn := sign(X), y := 2|X|, z := exp(Y),                 #
7936#               tanh(X) = sgn - [ sgn*2/(1+z) ].                        #
7937#               Exit.                                                   #
7938#                                                                       #
7939#       6. (|X| >= 50 log2) Tanh(X) = +-1 (round to nearest). Thus, we  #
7940#               calculate Tanh(X) by                                    #
7941#               sgn := sign(X), Tiny := 2**(-126),                      #
7942#               tanh(X) := sgn - sgn*Tiny.                              #
7943#               Exit.                                                   #
7944#                                                                       #
7945#       7. (|X| < 2**(-40)). Tanh(X) = X.       Exit.                   #
7946#                                                                       #
7947#########################################################################
7948
7949        set             X,FP_SCR0
7950        set             XFRAC,X+4
7951
7952        set             SGN,L_SCR3
7953
7954        set             V,FP_SCR0
7955
7956        global          stanh
7957stanh:
7958        fmov.x          (%a0),%fp0              # LOAD INPUT
7959
7960        fmov.x          %fp0,X(%a6)
7961        mov.l           (%a0),%d1
7962        mov.w           4(%a0),%d1
7963        mov.l           %d1,X(%a6)
7964        and.l           &0x7FFFFFFF,%d1
7965        cmp.l           %d1, &0x3fd78000        # is |X| < 2^(-40)?
7966        blt.w           TANHBORS                # yes
7967        cmp.l           %d1, &0x3fffddce        # is |X| > (5/2)LOG2?
7968        bgt.w           TANHBORS                # yes
7969
7970#--THIS IS THE USUAL CASE
7971#--Y = 2|X|, Z = EXPM1(Y), TANH(X) = SIGN(X) * Z / (Z+2).
7972
7973        mov.l           X(%a6),%d1
7974        mov.l           %d1,SGN(%a6)
7975        and.l           &0x7FFF0000,%d1
7976        add.l           &0x00010000,%d1         # EXPONENT OF 2|X|
7977        mov.l           %d1,X(%a6)
7978        and.l           &0x80000000,SGN(%a6)
7979        fmov.x          X(%a6),%fp0             # FP0 IS Y = 2|X|
7980
7981        mov.l           %d0,-(%sp)
7982        clr.l           %d0
7983        fmovm.x         &0x1,-(%sp)             # save Y on stack
7984        lea             (%sp),%a0               # pass ptr to Y
7985        bsr             setoxm1                 # FP0 IS Z = EXPM1(Y)
7986        add.l           &0xc,%sp                # clear Y from stack
7987        mov.l           (%sp)+,%d0
7988
7989        fmov.x          %fp0,%fp1
7990        fadd.s          &0x40000000,%fp1        # Z+2
7991        mov.l           SGN(%a6),%d1
7992        fmov.x          %fp1,V(%a6)
7993        eor.l           %d1,V(%a6)
7994
7995        fmov.l          %d0,%fpcr               # restore users round prec,mode
7996        fdiv.x          V(%a6),%fp0
7997        bra             t_inx2
7998
7999TANHBORS:
8000        cmp.l           %d1,&0x3FFF8000
8001        blt.w           TANHSM
8002
8003        cmp.l           %d1,&0x40048AA1
8004        bgt.w           TANHHUGE
8005
8006#-- (5/2) LOG2 < |X| < 50 LOG2,
8007#--TANH(X) = 1 - (2/[EXP(2X)+1]). LET Y = 2|X|, SGN = SIGN(X),
8008#--TANH(X) = SGN -      SGN*2/[EXP(Y)+1].
8009
8010        mov.l           X(%a6),%d1
8011        mov.l           %d1,SGN(%a6)
8012        and.l           &0x7FFF0000,%d1
8013        add.l           &0x00010000,%d1         # EXPO OF 2|X|
8014        mov.l           %d1,X(%a6)              # Y = 2|X|
8015        and.l           &0x80000000,SGN(%a6)
8016        mov.l           SGN(%a6),%d1
8017        fmov.x          X(%a6),%fp0             # Y = 2|X|
8018
8019        mov.l           %d0,-(%sp)
8020        clr.l           %d0
8021        fmovm.x         &0x01,-(%sp)            # save Y on stack
8022        lea             (%sp),%a0               # pass ptr to Y
8023        bsr             setox                   # FP0 IS EXP(Y)
8024        add.l           &0xc,%sp                # clear Y from stack
8025        mov.l           (%sp)+,%d0
8026        mov.l           SGN(%a6),%d1
8027        fadd.s          &0x3F800000,%fp0        # EXP(Y)+1
8028
8029        eor.l           &0xC0000000,%d1         # -SIGN(X)*2
8030        fmov.s          %d1,%fp1                # -SIGN(X)*2 IN SGL FMT
8031        fdiv.x          %fp0,%fp1               # -SIGN(X)2 / [EXP(Y)+1 ]
8032
8033        mov.l           SGN(%a6),%d1
8034        or.l            &0x3F800000,%d1         # SGN
8035        fmov.s          %d1,%fp0                # SGN IN SGL FMT
8036
8037        fmov.l          %d0,%fpcr               # restore users round prec,mode
8038        mov.b           &FADD_OP,%d1            # last inst is ADD
8039        fadd.x          %fp1,%fp0
8040        bra             t_inx2
8041
8042TANHSM:
8043        fmov.l          %d0,%fpcr               # restore users round prec,mode
8044        mov.b           &FMOV_OP,%d1            # last inst is MOVE
8045        fmov.x          X(%a6),%fp0             # last inst - possible exception set
8046        bra             t_catch
8047
8048#---RETURN SGN(X) - SGN(X)EPS
8049TANHHUGE:
8050        mov.l           X(%a6),%d1
8051        and.l           &0x80000000,%d1
8052        or.l            &0x3F800000,%d1
8053        fmov.s          %d1,%fp0
8054        and.l           &0x80000000,%d1
8055        eor.l           &0x80800000,%d1         # -SIGN(X)*EPS
8056
8057        fmov.l          %d0,%fpcr               # restore users round prec,mode
8058        fadd.s          %d1,%fp0
8059        bra             t_inx2
8060
8061        global          stanhd
8062#--TANH(X) = X FOR DENORMALIZED X
8063stanhd:
8064        bra             t_extdnrm
8065
8066#########################################################################
8067# slogn():    computes the natural logarithm of a normalized input      #
8068# slognd():   computes the natural logarithm of a denormalized input    #
8069# slognp1():  computes the log(1+X) of a normalized input               #
8070# slognp1d(): computes the log(1+X) of a denormalized input             #
8071#                                                                       #
8072# INPUT *************************************************************** #
8073#       a0 = pointer to extended precision input                        #
8074#       d0 = round precision,mode                                       #
8075#                                                                       #
8076# OUTPUT ************************************************************** #
8077#       fp0 = log(X) or log(1+X)                                        #
8078#                                                                       #
8079# ACCURACY and MONOTONICITY ******************************************* #
8080#       The returned result is within 2 ulps in 64 significant bit,     #
8081#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
8082#       rounded to double precision. The result is provably monotonic   #
8083#       in double precision.                                            #
8084#                                                                       #
8085# ALGORITHM *********************************************************** #
8086#       LOGN:                                                           #
8087#       Step 1. If |X-1| < 1/16, approximate log(X) by an odd           #
8088#               polynomial in u, where u = 2(X-1)/(X+1). Otherwise,     #
8089#               move on to Step 2.                                      #
8090#                                                                       #
8091#       Step 2. X = 2**k * Y where 1 <= Y < 2. Define F to be the first #
8092#               seven significant bits of Y plus 2**(-7), i.e.          #
8093#               F = 1.xxxxxx1 in base 2 where the six "x" match those   #
8094#               of Y. Note that |Y-F| <= 2**(-7).                       #
8095#                                                                       #
8096#       Step 3. Define u = (Y-F)/F. Approximate log(1+u) by a           #
8097#               polynomial in u, log(1+u) = poly.                       #
8098#                                                                       #
8099#       Step 4. Reconstruct                                             #
8100#               log(X) = log( 2**k * Y ) = k*log(2) + log(F) + log(1+u) #
8101#               by k*log(2) + (log(F) + poly). The values of log(F) are #
8102#               calculated beforehand and stored in the program.        #
8103#                                                                       #
8104#       lognp1:                                                         #
8105#       Step 1: If |X| < 1/16, approximate log(1+X) by an odd           #
8106#               polynomial in u where u = 2X/(2+X). Otherwise, move on  #
8107#               to Step 2.                                              #
8108#                                                                       #
8109#       Step 2: Let 1+X = 2**k * Y, where 1 <= Y < 2. Define F as done  #
8110#               in Step 2 of the algorithm for LOGN and compute         #
8111#               log(1+X) as k*log(2) + log(F) + poly where poly         #
8112#               approximates log(1+u), u = (Y-F)/F.                     #
8113#                                                                       #
8114#       Implementation Notes:                                           #
8115#       Note 1. There are 64 different possible values for F, thus 64   #
8116#               log(F)'s need to be tabulated. Moreover, the values of  #
8117#               1/F are also tabulated so that the division in (Y-F)/F  #
8118#               can be performed by a multiplication.                   #
8119#                                                                       #
8120#       Note 2. In Step 2 of lognp1, in order to preserved accuracy,    #
8121#               the value Y-F has to be calculated carefully when       #
8122#               1/2 <= X < 3/2.                                         #
8123#                                                                       #
8124#       Note 3. To fully exploit the pipeline, polynomials are usually  #
8125#               separated into two parts evaluated independently before #
8126#               being added up.                                         #
8127#                                                                       #
8128#########################################################################
8129LOGOF2:
8130        long            0x3FFE0000,0xB17217F7,0xD1CF79AC,0x00000000
8131
8132one:
8133        long            0x3F800000
8134zero:
8135        long            0x00000000
8136infty:
8137        long            0x7F800000
8138negone:
8139        long            0xBF800000
8140
8141LOGA6:
8142        long            0x3FC2499A,0xB5E4040B
8143LOGA5:
8144        long            0xBFC555B5,0x848CB7DB
8145
8146LOGA4:
8147        long            0x3FC99999,0x987D8730
8148LOGA3:
8149        long            0xBFCFFFFF,0xFF6F7E97
8150
8151LOGA2:
8152        long            0x3FD55555,0x555555A4
8153LOGA1:
8154        long            0xBFE00000,0x00000008
8155
8156LOGB5:
8157        long            0x3F175496,0xADD7DAD6
8158LOGB4:
8159        long            0x3F3C71C2,0xFE80C7E0
8160
8161LOGB3:
8162        long            0x3F624924,0x928BCCFF
8163LOGB2:
8164        long            0x3F899999,0x999995EC
8165
8166LOGB1:
8167        long            0x3FB55555,0x55555555
8168TWO:
8169        long            0x40000000,0x00000000
8170
8171LTHOLD:
8172        long            0x3f990000,0x80000000,0x00000000,0x00000000
8173
8174LOGTBL:
8175        long            0x3FFE0000,0xFE03F80F,0xE03F80FE,0x00000000
8176        long            0x3FF70000,0xFF015358,0x833C47E2,0x00000000
8177        long            0x3FFE0000,0xFA232CF2,0x52138AC0,0x00000000
8178        long            0x3FF90000,0xBDC8D83E,0xAD88D549,0x00000000
8179        long            0x3FFE0000,0xF6603D98,0x0F6603DA,0x00000000
8180        long            0x3FFA0000,0x9CF43DCF,0xF5EAFD48,0x00000000
8181        long            0x3FFE0000,0xF2B9D648,0x0F2B9D65,0x00000000
8182        long            0x3FFA0000,0xDA16EB88,0xCB8DF614,0x00000000
8183        long            0x3FFE0000,0xEF2EB71F,0xC4345238,0x00000000
8184        long            0x3FFB0000,0x8B29B775,0x1BD70743,0x00000000
8185        long            0x3FFE0000,0xEBBDB2A5,0xC1619C8C,0x00000000
8186        long            0x3FFB0000,0xA8D839F8,0x30C1FB49,0x00000000
8187        long            0x3FFE0000,0xE865AC7B,0x7603A197,0x00000000
8188        long            0x3FFB0000,0xC61A2EB1,0x8CD907AD,0x00000000
8189        long            0x3FFE0000,0xE525982A,0xF70C880E,0x00000000
8190        long            0x3FFB0000,0xE2F2A47A,0xDE3A18AF,0x00000000
8191        long            0x3FFE0000,0xE1FC780E,0x1FC780E2,0x00000000
8192        long            0x3FFB0000,0xFF64898E,0xDF55D551,0x00000000
8193        long            0x3FFE0000,0xDEE95C4C,0xA037BA57,0x00000000
8194        long            0x3FFC0000,0x8DB956A9,0x7B3D0148,0x00000000
8195        long            0x3FFE0000,0xDBEB61EE,0xD19C5958,0x00000000
8196        long            0x3FFC0000,0x9B8FE100,0xF47BA1DE,0x00000000
8197        long            0x3FFE0000,0xD901B203,0x6406C80E,0x00000000
8198        long            0x3FFC0000,0xA9372F1D,0x0DA1BD17,0x00000000
8199        long            0x3FFE0000,0xD62B80D6,0x2B80D62C,0x00000000
8200        long            0x3FFC0000,0xB6B07F38,0xCE90E46B,0x00000000
8201        long            0x3FFE0000,0xD3680D36,0x80D3680D,0x00000000
8202        long            0x3FFC0000,0xC3FD0329,0x06488481,0x00000000
8203        long            0x3FFE0000,0xD0B69FCB,0xD2580D0B,0x00000000
8204        long            0x3FFC0000,0xD11DE0FF,0x15AB18CA,0x00000000
8205        long            0x3FFE0000,0xCE168A77,0x25080CE1,0x00000000
8206        long            0x3FFC0000,0xDE1433A1,0x6C66B150,0x00000000
8207        long            0x3FFE0000,0xCB8727C0,0x65C393E0,0x00000000
8208        long            0x3FFC0000,0xEAE10B5A,0x7DDC8ADD,0x00000000
8209        long            0x3FFE0000,0xC907DA4E,0x871146AD,0x00000000
8210        long            0x3FFC0000,0xF7856E5E,0xE2C9B291,0x00000000
8211        long            0x3FFE0000,0xC6980C69,0x80C6980C,0x00000000
8212        long            0x3FFD0000,0x82012CA5,0xA68206D7,0x00000000
8213        long            0x3FFE0000,0xC4372F85,0x5D824CA6,0x00000000
8214        long            0x3FFD0000,0x882C5FCD,0x7256A8C5,0x00000000
8215        long            0x3FFE0000,0xC1E4BBD5,0x95F6E947,0x00000000
8216        long            0x3FFD0000,0x8E44C60B,0x4CCFD7DE,0x00000000
8217        long            0x3FFE0000,0xBFA02FE8,0x0BFA02FF,0x00000000
8218        long            0x3FFD0000,0x944AD09E,0xF4351AF6,0x00000000
8219        long            0x3FFE0000,0xBD691047,0x07661AA3,0x00000000
8220        long            0x3FFD0000,0x9A3EECD4,0xC3EAA6B2,0x00000000
8221        long            0x3FFE0000,0xBB3EE721,0xA54D880C,0x00000000
8222        long            0x3FFD0000,0xA0218434,0x353F1DE8,0x00000000
8223        long            0x3FFE0000,0xB92143FA,0x36F5E02E,0x00000000
8224        long            0x3FFD0000,0xA5F2FCAB,0xBBC506DA,0x00000000
8225        long            0x3FFE0000,0xB70FBB5A,0x19BE3659,0x00000000
8226        long            0x3FFD0000,0xABB3B8BA,0x2AD362A5,0x00000000
8227        long            0x3FFE0000,0xB509E68A,0x9B94821F,0x00000000
8228        long            0x3FFD0000,0xB1641795,0xCE3CA97B,0x00000000
8229        long            0x3FFE0000,0xB30F6352,0x8917C80B,0x00000000
8230        long            0x3FFD0000,0xB7047551,0x5D0F1C61,0x00000000
8231        long            0x3FFE0000,0xB11FD3B8,0x0B11FD3C,0x00000000
8232        long            0x3FFD0000,0xBC952AFE,0xEA3D13E1,0x00000000
8233        long            0x3FFE0000,0xAF3ADDC6,0x80AF3ADE,0x00000000
8234        long            0x3FFD0000,0xC2168ED0,0xF458BA4A,0x00000000
8235        long            0x3FFE0000,0xAD602B58,0x0AD602B6,0x00000000
8236        long            0x3FFD0000,0xC788F439,0xB3163BF1,0x00000000
8237        long            0x3FFE0000,0xAB8F69E2,0x8359CD11,0x00000000
8238        long            0x3FFD0000,0xCCECAC08,0xBF04565D,0x00000000
8239        long            0x3FFE0000,0xA9C84A47,0xA07F5638,0x00000000
8240        long            0x3FFD0000,0xD2420487,0x2DD85160,0x00000000
8241        long            0x3FFE0000,0xA80A80A8,0x0A80A80B,0x00000000
8242        long            0x3FFD0000,0xD7894992,0x3BC3588A,0x00000000
8243        long            0x3FFE0000,0xA655C439,0x2D7B73A8,0x00000000
8244        long            0x3FFD0000,0xDCC2C4B4,0x9887DACC,0x00000000
8245        long            0x3FFE0000,0xA4A9CF1D,0x96833751,0x00000000
8246        long            0x3FFD0000,0xE1EEBD3E,0x6D6A6B9E,0x00000000
8247        long            0x3FFE0000,0xA3065E3F,0xAE7CD0E0,0x00000000
8248        long            0x3FFD0000,0xE70D785C,0x2F9F5BDC,0x00000000
8249        long            0x3FFE0000,0xA16B312E,0xA8FC377D,0x00000000
8250        long            0x3FFD0000,0xEC1F392C,0x5179F283,0x00000000
8251        long            0x3FFE0000,0x9FD809FD,0x809FD80A,0x00000000
8252        long            0x3FFD0000,0xF12440D3,0xE36130E6,0x00000000
8253        long            0x3FFE0000,0x9E4CAD23,0xDD5F3A20,0x00000000
8254        long            0x3FFD0000,0xF61CCE92,0x346600BB,0x00000000
8255        long            0x3FFE0000,0x9CC8E160,0xC3FB19B9,0x00000000
8256        long            0x3FFD0000,0xFB091FD3,0x8145630A,0x00000000
8257        long            0x3FFE0000,0x9B4C6F9E,0xF03A3CAA,0x00000000
8258        long            0x3FFD0000,0xFFE97042,0xBFA4C2AD,0x00000000
8259        long            0x3FFE0000,0x99D722DA,0xBDE58F06,0x00000000
8260        long            0x3FFE0000,0x825EFCED,0x49369330,0x00000000
8261        long            0x3FFE0000,0x9868C809,0x868C8098,0x00000000
8262        long            0x3FFE0000,0x84C37A7A,0xB9A905C9,0x00000000
8263        long            0x3FFE0000,0x97012E02,0x5C04B809,0x00000000
8264        long            0x3FFE0000,0x87224C2E,0x8E645FB7,0x00000000
8265        long            0x3FFE0000,0x95A02568,0x095A0257,0x00000000
8266        long            0x3FFE0000,0x897B8CAC,0x9F7DE298,0x00000000
8267        long            0x3FFE0000,0x94458094,0x45809446,0x00000000
8268        long            0x3FFE0000,0x8BCF55DE,0xC4CD05FE,0x00000000
8269        long            0x3FFE0000,0x92F11384,0x0497889C,0x00000000
8270        long            0x3FFE0000,0x8E1DC0FB,0x89E125E5,0x00000000
8271        long            0x3FFE0000,0x91A2B3C4,0xD5E6F809,0x00000000
8272        long            0x3FFE0000,0x9066E68C,0x955B6C9B,0x00000000
8273        long            0x3FFE0000,0x905A3863,0x3E06C43B,0x00000000
8274        long            0x3FFE0000,0x92AADE74,0xC7BE59E0,0x00000000
8275        long            0x3FFE0000,0x8F1779D9,0xFDC3A219,0x00000000
8276        long            0x3FFE0000,0x94E9BFF6,0x15845643,0x00000000
8277        long            0x3FFE0000,0x8DDA5202,0x37694809,0x00000000
8278        long            0x3FFE0000,0x9723A1B7,0x20134203,0x00000000
8279        long            0x3FFE0000,0x8CA29C04,0x6514E023,0x00000000
8280        long            0x3FFE0000,0x995899C8,0x90EB8990,0x00000000
8281        long            0x3FFE0000,0x8B70344A,0x139BC75A,0x00000000
8282        long            0x3FFE0000,0x9B88BDAA,0x3A3DAE2F,0x00000000
8283        long            0x3FFE0000,0x8A42F870,0x5669DB46,0x00000000
8284        long            0x3FFE0000,0x9DB4224F,0xFFE1157C,0x00000000
8285        long            0x3FFE0000,0x891AC73A,0xE9819B50,0x00000000
8286        long            0x3FFE0000,0x9FDADC26,0x8B7A12DA,0x00000000
8287        long            0x3FFE0000,0x87F78087,0xF78087F8,0x00000000
8288        long            0x3FFE0000,0xA1FCFF17,0xCE733BD4,0x00000000
8289        long            0x3FFE0000,0x86D90544,0x7A34ACC6,0x00000000
8290        long            0x3FFE0000,0xA41A9E8F,0x5446FB9F,0x00000000
8291        long            0x3FFE0000,0x85BF3761,0x2CEE3C9B,0x00000000
8292        long            0x3FFE0000,0xA633CD7E,0x6771CD8B,0x00000000
8293        long            0x3FFE0000,0x84A9F9C8,0x084A9F9D,0x00000000
8294        long            0x3FFE0000,0xA8489E60,0x0B435A5E,0x00000000
8295        long            0x3FFE0000,0x83993052,0x3FBE3368,0x00000000
8296        long            0x3FFE0000,0xAA59233C,0xCCA4BD49,0x00000000
8297        long            0x3FFE0000,0x828CBFBE,0xB9A020A3,0x00000000
8298        long            0x3FFE0000,0xAC656DAE,0x6BCC4985,0x00000000
8299        long            0x3FFE0000,0x81848DA8,0xFAF0D277,0x00000000
8300        long            0x3FFE0000,0xAE6D8EE3,0x60BB2468,0x00000000
8301        long            0x3FFE0000,0x80808080,0x80808081,0x00000000
8302        long            0x3FFE0000,0xB07197A2,0x3C46C654,0x00000000
8303
8304        set             ADJK,L_SCR1
8305
8306        set             X,FP_SCR0
8307        set             XDCARE,X+2
8308        set             XFRAC,X+4
8309
8310        set             F,FP_SCR1
8311        set             FFRAC,F+4
8312
8313        set             KLOG2,FP_SCR0
8314
8315        set             SAVEU,FP_SCR0
8316
8317        global          slogn
8318#--ENTRY POINT FOR LOG(X) FOR X FINITE, NON-ZERO, NOT NAN'S
8319slogn:
8320        fmov.x          (%a0),%fp0              # LOAD INPUT
8321        mov.l           &0x00000000,ADJK(%a6)
8322
8323LOGBGN:
8324#--FPCR SAVED AND CLEARED, INPUT IS 2^(ADJK)*FP0, FP0 CONTAINS
8325#--A FINITE, NON-ZERO, NORMALIZED NUMBER.
8326
8327        mov.l           (%a0),%d1
8328        mov.w           4(%a0),%d1
8329
8330        mov.l           (%a0),X(%a6)
8331        mov.l           4(%a0),X+4(%a6)
8332        mov.l           8(%a0),X+8(%a6)
8333
8334        cmp.l           %d1,&0                  # CHECK IF X IS NEGATIVE
8335        blt.w           LOGNEG                  # LOG OF NEGATIVE ARGUMENT IS INVALID
8336# X IS POSITIVE, CHECK IF X IS NEAR 1
8337        cmp.l           %d1,&0x3ffef07d         # IS X < 15/16?
8338        blt.b           LOGMAIN                 # YES
8339        cmp.l           %d1,&0x3fff8841         # IS X > 17/16?
8340        ble.w           LOGNEAR1                # NO
8341
8342LOGMAIN:
8343#--THIS SHOULD BE THE USUAL CASE, X NOT VERY CLOSE TO 1
8344
8345#--X = 2^(K) * Y, 1 <= Y < 2. THUS, Y = 1.XXXXXXXX....XX IN BINARY.
8346#--WE DEFINE F = 1.XXXXXX1, I.E. FIRST 7 BITS OF Y AND ATTACH A 1.
8347#--THE IDEA IS THAT LOG(X) = K*LOG2 + LOG(Y)
8348#--                      = K*LOG2 + LOG(F) + LOG(1 + (Y-F)/F).
8349#--NOTE THAT U = (Y-F)/F IS VERY SMALL AND THUS APPROXIMATING
8350#--LOG(1+U) CAN BE VERY EFFICIENT.
8351#--ALSO NOTE THAT THE VALUE 1/F IS STORED IN A TABLE SO THAT NO
8352#--DIVISION IS NEEDED TO CALCULATE (Y-F)/F.
8353
8354#--GET K, Y, F, AND ADDRESS OF 1/F.
8355        asr.l           &8,%d1
8356        asr.l           &8,%d1                  # SHIFTED 16 BITS, BIASED EXPO. OF X
8357        sub.l           &0x3FFF,%d1             # THIS IS K
8358        add.l           ADJK(%a6),%d1           # ADJUST K, ORIGINAL INPUT MAY BE  DENORM.
8359        lea             LOGTBL(%pc),%a0         # BASE ADDRESS OF 1/F AND LOG(F)
8360        fmov.l          %d1,%fp1                # CONVERT K TO FLOATING-POINT FORMAT
8361
8362#--WHILE THE CONVERSION IS GOING ON, WE GET F AND ADDRESS OF 1/F
8363        mov.l           &0x3FFF0000,X(%a6)      # X IS NOW Y, I.E. 2^(-K)*X
8364        mov.l           XFRAC(%a6),FFRAC(%a6)
8365        and.l           &0xFE000000,FFRAC(%a6)  # FIRST 7 BITS OF Y
8366        or.l            &0x01000000,FFRAC(%a6)  # GET F: ATTACH A 1 AT THE EIGHTH BIT
8367        mov.l           FFRAC(%a6),%d1  # READY TO GET ADDRESS OF 1/F
8368        and.l           &0x7E000000,%d1
8369        asr.l           &8,%d1
8370        asr.l           &8,%d1
8371        asr.l           &4,%d1                  # SHIFTED 20, D0 IS THE DISPLACEMENT
8372        add.l           %d1,%a0                 # A0 IS THE ADDRESS FOR 1/F
8373
8374        fmov.x          X(%a6),%fp0
8375        mov.l           &0x3fff0000,F(%a6)
8376        clr.l           F+8(%a6)
8377        fsub.x          F(%a6),%fp0             # Y-F
8378        fmovm.x         &0xc,-(%sp)             # SAVE FP2-3 WHILE FP0 IS NOT READY
8379#--SUMMARY: FP0 IS Y-F, A0 IS ADDRESS OF 1/F, FP1 IS K
8380#--REGISTERS SAVED: FPCR, FP1, FP2
8381
8382LP1CONT1:
8383#--AN RE-ENTRY POINT FOR LOGNP1
8384        fmul.x          (%a0),%fp0              # FP0 IS U = (Y-F)/F
8385        fmul.x          LOGOF2(%pc),%fp1        # GET K*LOG2 WHILE FP0 IS NOT READY
8386        fmov.x          %fp0,%fp2
8387        fmul.x          %fp2,%fp2               # FP2 IS V=U*U
8388        fmov.x          %fp1,KLOG2(%a6)         # PUT K*LOG2 IN MEMEORY, FREE FP1
8389
8390#--LOG(1+U) IS APPROXIMATED BY
8391#--U + V*(A1+U*(A2+U*(A3+U*(A4+U*(A5+U*A6))))) WHICH IS
8392#--[U + V*(A1+V*(A3+V*A5))]  +  [U*V*(A2+V*(A4+V*A6))]
8393
8394        fmov.x          %fp2,%fp3
8395        fmov.x          %fp2,%fp1
8396
8397        fmul.d          LOGA6(%pc),%fp1         # V*A6
8398        fmul.d          LOGA5(%pc),%fp2         # V*A5
8399
8400        fadd.d          LOGA4(%pc),%fp1         # A4+V*A6
8401        fadd.d          LOGA3(%pc),%fp2         # A3+V*A5
8402
8403        fmul.x          %fp3,%fp1               # V*(A4+V*A6)
8404        fmul.x          %fp3,%fp2               # V*(A3+V*A5)
8405
8406        fadd.d          LOGA2(%pc),%fp1         # A2+V*(A4+V*A6)
8407        fadd.d          LOGA1(%pc),%fp2         # A1+V*(A3+V*A5)
8408
8409        fmul.x          %fp3,%fp1               # V*(A2+V*(A4+V*A6))
8410        add.l           &16,%a0                 # ADDRESS OF LOG(F)
8411        fmul.x          %fp3,%fp2               # V*(A1+V*(A3+V*A5))
8412
8413        fmul.x          %fp0,%fp1               # U*V*(A2+V*(A4+V*A6))
8414        fadd.x          %fp2,%fp0               # U+V*(A1+V*(A3+V*A5))
8415
8416        fadd.x          (%a0),%fp1              # LOG(F)+U*V*(A2+V*(A4+V*A6))
8417        fmovm.x         (%sp)+,&0x30            # RESTORE FP2-3
8418        fadd.x          %fp1,%fp0               # FP0 IS LOG(F) + LOG(1+U)
8419
8420        fmov.l          %d0,%fpcr
8421        fadd.x          KLOG2(%a6),%fp0         # FINAL ADD
8422        bra             t_inx2
8423
8424
8425LOGNEAR1:
8426
8427# if the input is exactly equal to one, then exit through ld_pzero.
8428# if these 2 lines weren't here, the correct answer would be returned
8429# but the INEX2 bit would be set.
8430        fcmp.b          %fp0,&0x1               # is it equal to one?
8431        fbeq.l          ld_pzero                # yes
8432
8433#--REGISTERS SAVED: FPCR, FP1. FP0 CONTAINS THE INPUT.
8434        fmov.x          %fp0,%fp1
8435        fsub.s          one(%pc),%fp1           # FP1 IS X-1
8436        fadd.s          one(%pc),%fp0           # FP0 IS X+1
8437        fadd.x          %fp1,%fp1               # FP1 IS 2(X-1)
8438#--LOG(X) = LOG(1+U/2)-LOG(1-U/2) WHICH IS AN ODD POLYNOMIAL
8439#--IN U, U = 2(X-1)/(X+1) = FP1/FP0
8440
8441LP1CONT2:
8442#--THIS IS AN RE-ENTRY POINT FOR LOGNP1
8443        fdiv.x          %fp0,%fp1               # FP1 IS U
8444        fmovm.x         &0xc,-(%sp)             # SAVE FP2-3
8445#--REGISTERS SAVED ARE NOW FPCR,FP1,FP2,FP3
8446#--LET V=U*U, W=V*V, CALCULATE
8447#--U + U*V*(B1 + V*(B2 + V*(B3 + V*(B4 + V*B5)))) BY
8448#--U + U*V*(  [B1 + W*(B3 + W*B5)]  +  [V*(B2 + W*B4)]  )
8449        fmov.x          %fp1,%fp0
8450        fmul.x          %fp0,%fp0               # FP0 IS V
8451        fmov.x          %fp1,SAVEU(%a6)         # STORE U IN MEMORY, FREE FP1
8452        fmov.x          %fp0,%fp1
8453        fmul.x          %fp1,%fp1               # FP1 IS W
8454
8455        fmov.d          LOGB5(%pc),%fp3
8456        fmov.d          LOGB4(%pc),%fp2
8457
8458        fmul.x          %fp1,%fp3               # W*B5
8459        fmul.x          %fp1,%fp2               # W*B4
8460
8461        fadd.d          LOGB3(%pc),%fp3         # B3+W*B5
8462        fadd.d          LOGB2(%pc),%fp2         # B2+W*B4
8463
8464        fmul.x          %fp3,%fp1               # W*(B3+W*B5), FP3 RELEASED
8465
8466        fmul.x          %fp0,%fp2               # V*(B2+W*B4)
8467
8468        fadd.d          LOGB1(%pc),%fp1         # B1+W*(B3+W*B5)
8469        fmul.x          SAVEU(%a6),%fp0         # FP0 IS U*V
8470
8471        fadd.x          %fp2,%fp1               # B1+W*(B3+W*B5) + V*(B2+W*B4), FP2 RELEASED
8472        fmovm.x         (%sp)+,&0x30            # FP2-3 RESTORED
8473
8474        fmul.x          %fp1,%fp0               # U*V*( [B1+W*(B3+W*B5)] + [V*(B2+W*B4)] )
8475
8476        fmov.l          %d0,%fpcr
8477        fadd.x          SAVEU(%a6),%fp0
8478        bra             t_inx2
8479
8480#--REGISTERS SAVED FPCR. LOG(-VE) IS INVALID
8481LOGNEG:
8482        bra             t_operr
8483
8484        global          slognd
8485slognd:
8486#--ENTRY POINT FOR LOG(X) FOR DENORMALIZED INPUT
8487
8488        mov.l           &-100,ADJK(%a6)         # INPUT = 2^(ADJK) * FP0
8489
8490#----normalize the input value by left shifting k bits (k to be determined
8491#----below), adjusting exponent and storing -k to  ADJK
8492#----the value TWOTO100 is no longer needed.
8493#----Note that this code assumes the denormalized input is NON-ZERO.
8494
8495        movm.l          &0x3f00,-(%sp)          # save some registers  {d2-d7}
8496        mov.l           (%a0),%d3               # D3 is exponent of smallest norm. #
8497        mov.l           4(%a0),%d4
8498        mov.l           8(%a0),%d5              # (D4,D5) is (Hi_X,Lo_X)
8499        clr.l           %d2                     # D2 used for holding K
8500
8501        tst.l           %d4
8502        bne.b           Hi_not0
8503
8504Hi_0:
8505        mov.l           %d5,%d4
8506        clr.l           %d5
8507        mov.l           &32,%d2
8508        clr.l           %d6
8509        bfffo           %d4{&0:&32},%d6
8510        lsl.l           %d6,%d4
8511        add.l           %d6,%d2                 # (D3,D4,D5) is normalized
8512
8513        mov.l           %d3,X(%a6)
8514        mov.l           %d4,XFRAC(%a6)
8515        mov.l           %d5,XFRAC+4(%a6)
8516        neg.l           %d2
8517        mov.l           %d2,ADJK(%a6)
8518        fmov.x          X(%a6),%fp0
8519        movm.l          (%sp)+,&0xfc            # restore registers {d2-d7}
8520        lea             X(%a6),%a0
8521        bra.w           LOGBGN                  # begin regular log(X)
8522
8523Hi_not0:
8524        clr.l           %d6
8525        bfffo           %d4{&0:&32},%d6         # find first 1
8526        mov.l           %d6,%d2                 # get k
8527        lsl.l           %d6,%d4
8528        mov.l           %d5,%d7                 # a copy of D5
8529        lsl.l           %d6,%d5
8530        neg.l           %d6
8531        add.l           &32,%d6
8532        lsr.l           %d6,%d7
8533        or.l            %d7,%d4                 # (D3,D4,D5) normalized
8534
8535        mov.l           %d3,X(%a6)
8536        mov.l           %d4,XFRAC(%a6)
8537        mov.l           %d5,XFRAC+4(%a6)
8538        neg.l           %d2
8539        mov.l           %d2,ADJK(%a6)
8540        fmov.x          X(%a6),%fp0
8541        movm.l          (%sp)+,&0xfc            # restore registers {d2-d7}
8542        lea             X(%a6),%a0
8543        bra.w           LOGBGN                  # begin regular log(X)
8544
8545        global          slognp1
8546#--ENTRY POINT FOR LOG(1+X) FOR X FINITE, NON-ZERO, NOT NAN'S
8547slognp1:
8548        fmov.x          (%a0),%fp0              # LOAD INPUT
8549        fabs.x          %fp0                    # test magnitude
8550        fcmp.x          %fp0,LTHOLD(%pc)        # compare with min threshold
8551        fbgt.w          LP1REAL                 # if greater, continue
8552        fmov.l          %d0,%fpcr
8553        mov.b           &FMOV_OP,%d1            # last inst is MOVE
8554        fmov.x          (%a0),%fp0              # return signed argument
8555        bra             t_catch
8556
8557LP1REAL:
8558        fmov.x          (%a0),%fp0              # LOAD INPUT
8559        mov.l           &0x00000000,ADJK(%a6)
8560        fmov.x          %fp0,%fp1               # FP1 IS INPUT Z
8561        fadd.s          one(%pc),%fp0           # X := ROUND(1+Z)
8562        fmov.x          %fp0,X(%a6)
8563        mov.w           XFRAC(%a6),XDCARE(%a6)
8564        mov.l           X(%a6),%d1
8565        cmp.l           %d1,&0
8566        ble.w           LP1NEG0                 # LOG OF ZERO OR -VE
8567        cmp.l           %d1,&0x3ffe8000         # IS BOUNDS [1/2,3/2]?
8568        blt.w           LOGMAIN
8569        cmp.l           %d1,&0x3fffc000
8570        bgt.w           LOGMAIN
8571#--IF 1+Z > 3/2 OR 1+Z < 1/2, THEN X, WHICH IS ROUNDING 1+Z,
8572#--CONTAINS AT LEAST 63 BITS OF INFORMATION OF Z. IN THAT CASE,
8573#--SIMPLY INVOKE LOG(X) FOR LOG(1+Z).
8574
8575LP1NEAR1:
8576#--NEXT SEE IF EXP(-1/16) < X < EXP(1/16)
8577        cmp.l           %d1,&0x3ffef07d
8578        blt.w           LP1CARE
8579        cmp.l           %d1,&0x3fff8841
8580        bgt.w           LP1CARE
8581
8582LP1ONE16:
8583#--EXP(-1/16) < X < EXP(1/16). LOG(1+Z) = LOG(1+U/2) - LOG(1-U/2)
8584#--WHERE U = 2Z/(2+Z) = 2Z/(1+X).
8585        fadd.x          %fp1,%fp1               # FP1 IS 2Z
8586        fadd.s          one(%pc),%fp0           # FP0 IS 1+X
8587#--U = FP1/FP0
8588        bra.w           LP1CONT2
8589
8590LP1CARE:
8591#--HERE WE USE THE USUAL TABLE DRIVEN APPROACH. CARE HAS TO BE
8592#--TAKEN BECAUSE 1+Z CAN HAVE 67 BITS OF INFORMATION AND WE MUST
8593#--PRESERVE ALL THE INFORMATION. BECAUSE 1+Z IS IN [1/2,3/2],
8594#--THERE ARE ONLY TWO CASES.
8595#--CASE 1: 1+Z < 1, THEN K = -1 AND Y-F = (2-F) + 2Z
8596#--CASE 2: 1+Z > 1, THEN K = 0  AND Y-F = (1-F) + Z
8597#--ON RETURNING TO LP1CONT1, WE MUST HAVE K IN FP1, ADDRESS OF
8598#--(1/F) IN A0, Y-F IN FP0, AND FP2 SAVED.
8599
8600        mov.l           XFRAC(%a6),FFRAC(%a6)
8601        and.l           &0xFE000000,FFRAC(%a6)
8602        or.l            &0x01000000,FFRAC(%a6)  # F OBTAINED
8603        cmp.l           %d1,&0x3FFF8000         # SEE IF 1+Z > 1
8604        bge.b           KISZERO
8605
8606KISNEG1:
8607        fmov.s          TWO(%pc),%fp0
8608        mov.l           &0x3fff0000,F(%a6)
8609        clr.l           F+8(%a6)
8610        fsub.x          F(%a6),%fp0             # 2-F
8611        mov.l           FFRAC(%a6),%d1
8612        and.l           &0x7E000000,%d1
8613        asr.l           &8,%d1
8614        asr.l           &8,%d1
8615        asr.l           &4,%d1                  # D0 CONTAINS DISPLACEMENT FOR 1/F
8616        fadd.x          %fp1,%fp1               # GET 2Z
8617        fmovm.x         &0xc,-(%sp)             # SAVE FP2  {%fp2/%fp3}
8618        fadd.x          %fp1,%fp0               # FP0 IS Y-F = (2-F)+2Z
8619        lea             LOGTBL(%pc),%a0         # A0 IS ADDRESS OF 1/F
8620        add.l           %d1,%a0
8621        fmov.s          negone(%pc),%fp1        # FP1 IS K = -1
8622        bra.w           LP1CONT1
8623
8624KISZERO:
8625        fmov.s          one(%pc),%fp0
8626        mov.l           &0x3fff0000,F(%a6)
8627        clr.l           F+8(%a6)
8628        fsub.x          F(%a6),%fp0             # 1-F
8629        mov.l           FFRAC(%a6),%d1
8630        and.l           &0x7E000000,%d1
8631        asr.l           &8,%d1
8632        asr.l           &8,%d1
8633        asr.l           &4,%d1
8634        fadd.x          %fp1,%fp0               # FP0 IS Y-F
8635        fmovm.x         &0xc,-(%sp)             # FP2 SAVED {%fp2/%fp3}
8636        lea             LOGTBL(%pc),%a0
8637        add.l           %d1,%a0                 # A0 IS ADDRESS OF 1/F
8638        fmov.s          zero(%pc),%fp1          # FP1 IS K = 0
8639        bra.w           LP1CONT1
8640
8641LP1NEG0:
8642#--FPCR SAVED. D0 IS X IN COMPACT FORM.
8643        cmp.l           %d1,&0
8644        blt.b           LP1NEG
8645LP1ZERO:
8646        fmov.s          negone(%pc),%fp0
8647
8648        fmov.l          %d0,%fpcr
8649        bra             t_dz
8650
8651LP1NEG:
8652        fmov.s          zero(%pc),%fp0
8653
8654        fmov.l          %d0,%fpcr
8655        bra             t_operr
8656
8657        global          slognp1d
8658#--ENTRY POINT FOR LOG(1+Z) FOR DENORMALIZED INPUT
8659# Simply return the denorm
8660slognp1d:
8661        bra             t_extdnrm
8662
8663#########################################################################
8664# satanh():  computes the inverse hyperbolic tangent of a norm input    #
8665# satanhd(): computes the inverse hyperbolic tangent of a denorm input  #
8666#                                                                       #
8667# INPUT *************************************************************** #
8668#       a0 = pointer to extended precision input                        #
8669#       d0 = round precision,mode                                       #
8670#                                                                       #
8671# OUTPUT ************************************************************** #
8672#       fp0 = arctanh(X)                                                #
8673#                                                                       #
8674# ACCURACY and MONOTONICITY ******************************************* #
8675#       The returned result is within 3 ulps in 64 significant bit,     #
8676#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
8677#       rounded to double precision. The result is provably monotonic   #
8678#       in double precision.                                            #
8679#                                                                       #
8680# ALGORITHM *********************************************************** #
8681#                                                                       #
8682#       ATANH                                                           #
8683#       1. If |X| >= 1, go to 3.                                        #
8684#                                                                       #
8685#       2. (|X| < 1) Calculate atanh(X) by                              #
8686#               sgn := sign(X)                                          #
8687#               y := |X|                                                #
8688#               z := 2y/(1-y)                                           #
8689#               atanh(X) := sgn * (1/2) * logp1(z)                      #
8690#               Exit.                                                   #
8691#                                                                       #
8692#       3. If |X| > 1, go to 5.                                         #
8693#                                                                       #
8694#       4. (|X| = 1) Generate infinity with an appropriate sign and     #
8695#               divide-by-zero by                                       #
8696#               sgn := sign(X)                                          #
8697#               atan(X) := sgn / (+0).                                  #
8698#               Exit.                                                   #
8699#                                                                       #
8700#       5. (|X| > 1) Generate an invalid operation by 0 * infinity.     #
8701#               Exit.                                                   #
8702#                                                                       #
8703#########################################################################
8704
8705        global          satanh
8706satanh:
8707        mov.l           (%a0),%d1
8708        mov.w           4(%a0),%d1
8709        and.l           &0x7FFFFFFF,%d1
8710        cmp.l           %d1,&0x3FFF8000
8711        bge.b           ATANHBIG
8712
8713#--THIS IS THE USUAL CASE, |X| < 1
8714#--Y = |X|, Z = 2Y/(1-Y), ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z).
8715
8716        fabs.x          (%a0),%fp0              # Y = |X|
8717        fmov.x          %fp0,%fp1
8718        fneg.x          %fp1                    # -Y
8719        fadd.x          %fp0,%fp0               # 2Y
8720        fadd.s          &0x3F800000,%fp1        # 1-Y
8721        fdiv.x          %fp1,%fp0               # 2Y/(1-Y)
8722        mov.l           (%a0),%d1
8723        and.l           &0x80000000,%d1
8724        or.l            &0x3F000000,%d1         # SIGN(X)*HALF
8725        mov.l           %d1,-(%sp)
8726
8727        mov.l           %d0,-(%sp)              # save rnd prec,mode
8728        clr.l           %d0                     # pass ext prec,RN
8729        fmovm.x         &0x01,-(%sp)            # save Z on stack
8730        lea             (%sp),%a0               # pass ptr to Z
8731        bsr             slognp1                 # LOG1P(Z)
8732        add.l           &0xc,%sp                # clear Z from stack
8733
8734        mov.l           (%sp)+,%d0              # fetch old prec,mode
8735        fmov.l          %d0,%fpcr               # load it
8736        mov.b           &FMUL_OP,%d1            # last inst is MUL
8737        fmul.s          (%sp)+,%fp0
8738        bra             t_catch
8739
8740ATANHBIG:
8741        fabs.x          (%a0),%fp0              # |X|
8742        fcmp.s          %fp0,&0x3F800000
8743        fbgt            t_operr
8744        bra             t_dz
8745
8746        global          satanhd
8747#--ATANH(X) = X FOR DENORMALIZED X
8748satanhd:
8749        bra             t_extdnrm
8750
8751#########################################################################
8752# slog10():  computes the base-10 logarithm of a normalized input       #
8753# slog10d(): computes the base-10 logarithm of a denormalized input     #
8754# slog2():   computes the base-2 logarithm of a normalized input        #
8755# slog2d():  computes the base-2 logarithm of a denormalized input      #
8756#                                                                       #
8757# INPUT *************************************************************** #
8758#       a0 = pointer to extended precision input                        #
8759#       d0 = round precision,mode                                       #
8760#                                                                       #
8761# OUTPUT ************************************************************** #
8762#       fp0 = log_10(X) or log_2(X)                                     #
8763#                                                                       #
8764# ACCURACY and MONOTONICITY ******************************************* #
8765#       The returned result is within 1.7 ulps in 64 significant bit,   #
8766#       i.e. within 0.5003 ulp to 53 bits if the result is subsequently #
8767#       rounded to double precision. The result is provably monotonic   #
8768#       in double precision.                                            #
8769#                                                                       #
8770# ALGORITHM *********************************************************** #
8771#                                                                       #
8772#       slog10d:                                                        #
8773#                                                                       #
8774#       Step 0. If X < 0, create a NaN and raise the invalid operation  #
8775#               flag. Otherwise, save FPCR in D1; set FpCR to default.  #
8776#       Notes:  Default means round-to-nearest mode, no floating-point  #
8777#               traps, and precision control = double extended.         #
8778#                                                                       #
8779#       Step 1. Call slognd to obtain Y = log(X), the natural log of X. #
8780#       Notes:  Even if X is denormalized, log(X) is always normalized. #
8781#                                                                       #
8782#       Step 2.  Compute log_10(X) = log(X) * (1/log(10)).              #
8783#            2.1 Restore the user FPCR                                  #
8784#            2.2 Return ans := Y * INV_L10.                             #
8785#                                                                       #
8786#       slog10:                                                         #
8787#                                                                       #
8788#       Step 0. If X < 0, create a NaN and raise the invalid operation  #
8789#               flag. Otherwise, save FPCR in D1; set FpCR to default.  #
8790#       Notes:  Default means round-to-nearest mode, no floating-point  #
8791#               traps, and precision control = double extended.         #
8792#                                                                       #
8793#       Step 1. Call sLogN to obtain Y = log(X), the natural log of X.  #
8794#                                                                       #
8795#       Step 2.   Compute log_10(X) = log(X) * (1/log(10)).             #
8796#            2.1  Restore the user FPCR                                 #
8797#            2.2  Return ans := Y * INV_L10.                            #
8798#                                                                       #
8799#       sLog2d:                                                         #
8800#                                                                       #
8801#       Step 0. If X < 0, create a NaN and raise the invalid operation  #
8802#               flag. Otherwise, save FPCR in D1; set FpCR to default.  #
8803#       Notes:  Default means round-to-nearest mode, no floating-point  #
8804#               traps, and precision control = double extended.         #
8805#                                                                       #
8806#       Step 1. Call slognd to obtain Y = log(X), the natural log of X. #
8807#       Notes:  Even if X is denormalized, log(X) is always normalized. #
8808#                                                                       #
8809#       Step 2.   Compute log_10(X) = log(X) * (1/log(2)).              #
8810#            2.1  Restore the user FPCR                                 #
8811#            2.2  Return ans := Y * INV_L2.                             #
8812#                                                                       #
8813#       sLog2:                                                          #
8814#                                                                       #
8815#       Step 0. If X < 0, create a NaN and raise the invalid operation  #
8816#               flag. Otherwise, save FPCR in D1; set FpCR to default.  #
8817#       Notes:  Default means round-to-nearest mode, no floating-point  #
8818#               traps, and precision control = double extended.         #
8819#                                                                       #
8820#       Step 1. If X is not an integer power of two, i.e., X != 2^k,    #
8821#               go to Step 3.                                           #
8822#                                                                       #
8823#       Step 2.   Return k.                                             #
8824#            2.1  Get integer k, X = 2^k.                               #
8825#            2.2  Restore the user FPCR.                                #
8826#            2.3  Return ans := convert-to-double-extended(k).          #
8827#                                                                       #
8828#       Step 3. Call sLogN to obtain Y = log(X), the natural log of X.  #
8829#                                                                       #
8830#       Step 4.   Compute log_2(X) = log(X) * (1/log(2)).               #
8831#            4.1  Restore the user FPCR                                 #
8832#            4.2  Return ans := Y * INV_L2.                             #
8833#                                                                       #
8834#########################################################################
8835
8836INV_L10:
8837        long            0x3FFD0000,0xDE5BD8A9,0x37287195,0x00000000
8838
8839INV_L2:
8840        long            0x3FFF0000,0xB8AA3B29,0x5C17F0BC,0x00000000
8841
8842        global          slog10
8843#--entry point for Log10(X), X is normalized
8844slog10:
8845        fmov.b          &0x1,%fp0
8846        fcmp.x          %fp0,(%a0)              # if operand == 1,
8847        fbeq.l          ld_pzero                # return an EXACT zero
8848
8849        mov.l           (%a0),%d1
8850        blt.w           invalid
8851        mov.l           %d0,-(%sp)
8852        clr.l           %d0
8853        bsr             slogn                   # log(X), X normal.
8854        fmov.l          (%sp)+,%fpcr
8855        fmul.x          INV_L10(%pc),%fp0
8856        bra             t_inx2
8857
8858        global          slog10d
8859#--entry point for Log10(X), X is denormalized
8860slog10d:
8861        mov.l           (%a0),%d1
8862        blt.w           invalid
8863        mov.l           %d0,-(%sp)
8864        clr.l           %d0
8865        bsr             slognd                  # log(X), X denorm.
8866        fmov.l          (%sp)+,%fpcr
8867        fmul.x          INV_L10(%pc),%fp0
8868        bra             t_minx2
8869
8870        global          slog2
8871#--entry point for Log2(X), X is normalized
8872slog2:
8873        mov.l           (%a0),%d1
8874        blt.w           invalid
8875
8876        mov.l           8(%a0),%d1
8877        bne.b           continue                # X is not 2^k
8878
8879        mov.l           4(%a0),%d1
8880        and.l           &0x7FFFFFFF,%d1
8881        bne.b           continue
8882
8883#--X = 2^k.
8884        mov.w           (%a0),%d1
8885        and.l           &0x00007FFF,%d1
8886        sub.l           &0x3FFF,%d1
8887        beq.l           ld_pzero
8888        fmov.l          %d0,%fpcr
8889        fmov.l          %d1,%fp0
8890        bra             t_inx2
8891
8892continue:
8893        mov.l           %d0,-(%sp)
8894        clr.l           %d0
8895        bsr             slogn                   # log(X), X normal.
8896        fmov.l          (%sp)+,%fpcr
8897        fmul.x          INV_L2(%pc),%fp0
8898        bra             t_inx2
8899
8900invalid:
8901        bra             t_operr
8902
8903        global          slog2d
8904#--entry point for Log2(X), X is denormalized
8905slog2d:
8906        mov.l           (%a0),%d1
8907        blt.w           invalid
8908        mov.l           %d0,-(%sp)
8909        clr.l           %d0
8910        bsr             slognd                  # log(X), X denorm.
8911        fmov.l          (%sp)+,%fpcr
8912        fmul.x          INV_L2(%pc),%fp0
8913        bra             t_minx2
8914
8915#########################################################################
8916# stwotox():  computes 2**X for a normalized input                      #
8917# stwotoxd(): computes 2**X for a denormalized input                    #
8918# stentox():  computes 10**X for a normalized input                     #
8919# stentoxd(): computes 10**X for a denormalized input                   #
8920#                                                                       #
8921# INPUT *************************************************************** #
8922#       a0 = pointer to extended precision input                        #
8923#       d0 = round precision,mode                                       #
8924#                                                                       #
8925# OUTPUT ************************************************************** #
8926#       fp0 = 2**X or 10**X                                             #
8927#                                                                       #
8928# ACCURACY and MONOTONICITY ******************************************* #
8929#       The returned result is within 2 ulps in 64 significant bit,     #
8930#       i.e. within 0.5001 ulp to 53 bits if the result is subsequently #
8931#       rounded to double precision. The result is provably monotonic   #
8932#       in double precision.                                            #
8933#                                                                       #
8934# ALGORITHM *********************************************************** #
8935#                                                                       #
8936#       twotox                                                          #
8937#       1. If |X| > 16480, go to ExpBig.                                #
8938#                                                                       #
8939#       2. If |X| < 2**(-70), go to ExpSm.                              #
8940#                                                                       #
8941#       3. Decompose X as X = N/64 + r where |r| <= 1/128. Furthermore  #
8942#               decompose N as                                          #
8943#                N = 64(M + M') + j,  j = 0,1,2,...,63.                 #
8944#                                                                       #
8945#       4. Overwrite r := r * log2. Then                                #
8946#               2**X = 2**(M') * 2**(M) * 2**(j/64) * exp(r).           #
8947#               Go to expr to compute that expression.                  #
8948#                                                                       #
8949#       tentox                                                          #
8950#       1. If |X| > 16480*log_10(2) (base 10 log of 2), go to ExpBig.   #
8951#                                                                       #
8952#       2. If |X| < 2**(-70), go to ExpSm.                              #
8953#                                                                       #
8954#       3. Set y := X*log_2(10)*64 (base 2 log of 10). Set              #
8955#               N := round-to-int(y). Decompose N as                    #
8956#                N = 64(M + M') + j,  j = 0,1,2,...,63.                 #
8957#                                                                       #
8958#       4. Define r as                                                  #
8959#               r := ((X - N*L1)-N*L2) * L10                            #
8960#               where L1, L2 are the leading and trailing parts of      #
8961#               log_10(2)/64 and L10 is the natural log of 10. Then     #
8962#               10**X = 2**(M') * 2**(M) * 2**(j/64) * exp(r).          #
8963#               Go to expr to compute that expression.                  #
8964#                                                                       #
8965#       expr                                                            #
8966#       1. Fetch 2**(j/64) from table as Fact1 and Fact2.               #
8967#                                                                       #
8968#       2. Overwrite Fact1 and Fact2 by                                 #
8969#               Fact1 := 2**(M) * Fact1                                 #
8970#               Fact2 := 2**(M) * Fact2                                 #
8971#               Thus Fact1 + Fact2 = 2**(M) * 2**(j/64).                #
8972#                                                                       #
8973#       3. Calculate P where 1 + P approximates exp(r):                 #
8974#               P = r + r*r*(A1+r*(A2+...+r*A5)).                       #
8975#                                                                       #
8976#       4. Let AdjFact := 2**(M'). Return                               #
8977#               AdjFact * ( Fact1 + ((Fact1*P) + Fact2) ).              #
8978#               Exit.                                                   #
8979#                                                                       #
8980#       ExpBig                                                          #
8981#       1. Generate overflow by Huge * Huge if X > 0; otherwise,        #
8982#               generate underflow by Tiny * Tiny.                      #
8983#                                                                       #
8984#       ExpSm                                                           #
8985#       1. Return 1 + X.                                                #
8986#                                                                       #
8987#########################################################################
8988
8989L2TEN64:
8990        long            0x406A934F,0x0979A371   # 64LOG10/LOG2
8991L10TWO1:
8992        long            0x3F734413,0x509F8000   # LOG2/64LOG10
8993
8994L10TWO2:
8995        long            0xBFCD0000,0xC0219DC1,0xDA994FD2,0x00000000
8996
8997LOG10:  long            0x40000000,0x935D8DDD,0xAAA8AC17,0x00000000
8998
8999LOG2:   long            0x3FFE0000,0xB17217F7,0xD1CF79AC,0x00000000
9000
9001EXPA5:  long            0x3F56C16D,0x6F7BD0B2
9002EXPA4:  long            0x3F811112,0x302C712C
9003EXPA3:  long            0x3FA55555,0x55554CC1
9004EXPA2:  long            0x3FC55555,0x55554A54
9005EXPA1:  long            0x3FE00000,0x00000000,0x00000000,0x00000000
9006
9007TEXPTBL:
9008        long            0x3FFF0000,0x80000000,0x00000000,0x3F738000
9009        long            0x3FFF0000,0x8164D1F3,0xBC030773,0x3FBEF7CA
9010        long            0x3FFF0000,0x82CD8698,0xAC2BA1D7,0x3FBDF8A9
9011        long            0x3FFF0000,0x843A28C3,0xACDE4046,0x3FBCD7C9
9012        long            0x3FFF0000,0x85AAC367,0xCC487B15,0xBFBDE8DA
9013        long            0x3FFF0000,0x871F6196,0x9E8D1010,0x3FBDE85C
9014        long            0x3FFF0000,0x88980E80,0x92DA8527,0x3FBEBBF1
9015        long            0x3FFF0000,0x8A14D575,0x496EFD9A,0x3FBB80CA
9016        long            0x3FFF0000,0x8B95C1E3,0xEA8BD6E7,0xBFBA8373
9017        long            0x3FFF0000,0x8D1ADF5B,0x7E5BA9E6,0xBFBE9670
9018        long            0x3FFF0000,0x8EA4398B,0x45CD53C0,0x3FBDB700
9019        long            0x3FFF0000,0x9031DC43,0x1466B1DC,0x3FBEEEB0
9020        long            0x3FFF0000,0x91C3D373,0xAB11C336,0x3FBBFD6D
9021        long            0x3FFF0000,0x935A2B2F,0x13E6E92C,0xBFBDB319
9022        long            0x3FFF0000,0x94F4EFA8,0xFEF70961,0x3FBDBA2B
9023        long            0x3FFF0000,0x96942D37,0x20185A00,0x3FBE91D5
9024        long            0x3FFF0000,0x9837F051,0x8DB8A96F,0x3FBE8D5A
9025        long            0x3FFF0000,0x99E04593,0x20B7FA65,0xBFBCDE7B
9026        long            0x3FFF0000,0x9B8D39B9,0xD54E5539,0xBFBEBAAF
9027        long            0x3FFF0000,0x9D3ED9A7,0x2CFFB751,0xBFBD86DA
9028        long            0x3FFF0000,0x9EF53260,0x91A111AE,0xBFBEBEDD
9029        long            0x3FFF0000,0xA0B0510F,0xB9714FC2,0x3FBCC96E
9030        long            0x3FFF0000,0xA2704303,0x0C496819,0xBFBEC90B
9031        long            0x3FFF0000,0xA43515AE,0x09E6809E,0x3FBBD1DB
9032        long            0x3FFF0000,0xA5FED6A9,0xB15138EA,0x3FBCE5EB
9033        long            0x3FFF0000,0xA7CD93B4,0xE965356A,0xBFBEC274
9034        long            0x3FFF0000,0xA9A15AB4,0xEA7C0EF8,0x3FBEA83C
9035        long            0x3FFF0000,0xAB7A39B5,0xA93ED337,0x3FBECB00
9036        long            0x3FFF0000,0xAD583EEA,0x42A14AC6,0x3FBE9301
9037        long            0x3FFF0000,0xAF3B78AD,0x690A4375,0xBFBD8367
9038        long            0x3FFF0000,0xB123F581,0xD2AC2590,0xBFBEF05F
9039        long            0x3FFF0000,0xB311C412,0xA9112489,0x3FBDFB3C
9040        long            0x3FFF0000,0xB504F333,0xF9DE6484,0x3FBEB2FB
9041        long            0x3FFF0000,0xB6FD91E3,0x28D17791,0x3FBAE2CB
9042        long            0x3FFF0000,0xB8FBAF47,0x62FB9EE9,0x3FBCDC3C
9043        long            0x3FFF0000,0xBAFF5AB2,0x133E45FB,0x3FBEE9AA
9044        long            0x3FFF0000,0xBD08A39F,0x580C36BF,0xBFBEAEFD
9045        long            0x3FFF0000,0xBF1799B6,0x7A731083,0xBFBCBF51
9046        long            0x3FFF0000,0xC12C4CCA,0x66709456,0x3FBEF88A
9047        long            0x3FFF0000,0xC346CCDA,0x24976407,0x3FBD83B2
9048        long            0x3FFF0000,0xC5672A11,0x5506DADD,0x3FBDF8AB
9049        long            0x3FFF0000,0xC78D74C8,0xABB9B15D,0xBFBDFB17
9050        long            0x3FFF0000,0xC9B9BD86,0x6E2F27A3,0xBFBEFE3C
9051        long            0x3FFF0000,0xCBEC14FE,0xF2727C5D,0xBFBBB6F8
9052        long            0x3FFF0000,0xCE248C15,0x1F8480E4,0xBFBCEE53
9053        long            0x3FFF0000,0xD06333DA,0xEF2B2595,0xBFBDA4AE
9054        long            0x3FFF0000,0xD2A81D91,0xF12AE45A,0x3FBC9124
9055        long            0x3FFF0000,0xD4F35AAB,0xCFEDFA1F,0x3FBEB243
9056        long            0x3FFF0000,0xD744FCCA,0xD69D6AF4,0x3FBDE69A
9057        long            0x3FFF0000,0xD99D15C2,0x78AFD7B6,0xBFB8BC61
9058        long            0x3FFF0000,0xDBFBB797,0xDAF23755,0x3FBDF610
9059        long            0x3FFF0000,0xDE60F482,0x5E0E9124,0xBFBD8BE1
9060        long            0x3FFF0000,0xE0CCDEEC,0x2A94E111,0x3FBACB12
9061        long            0x3FFF0000,0xE33F8972,0xBE8A5A51,0x3FBB9BFE
9062        long            0x3FFF0000,0xE5B906E7,0x7C8348A8,0x3FBCF2F4
9063        long            0x3FFF0000,0xE8396A50,0x3C4BDC68,0x3FBEF22F
9064        long            0x3FFF0000,0xEAC0C6E7,0xDD24392F,0xBFBDBF4A
9065        long            0x3FFF0000,0xED4F301E,0xD9942B84,0x3FBEC01A
9066        long            0x3FFF0000,0xEFE4B99B,0xDCDAF5CB,0x3FBE8CAC
9067        long            0x3FFF0000,0xF281773C,0x59FFB13A,0xBFBCBB3F
9068        long            0x3FFF0000,0xF5257D15,0x2486CC2C,0x3FBEF73A
9069        long            0x3FFF0000,0xF7D0DF73,0x0AD13BB9,0xBFB8B795
9070        long            0x3FFF0000,0xFA83B2DB,0x722A033A,0x3FBEF84B
9071        long            0x3FFF0000,0xFD3E0C0C,0xF486C175,0xBFBEF581
9072
9073        set             INT,L_SCR1
9074
9075        set             X,FP_SCR0
9076        set             XDCARE,X+2
9077        set             XFRAC,X+4
9078
9079        set             ADJFACT,FP_SCR0
9080
9081        set             FACT1,FP_SCR0
9082        set             FACT1HI,FACT1+4
9083        set             FACT1LOW,FACT1+8
9084
9085        set             FACT2,FP_SCR1
9086        set             FACT2HI,FACT2+4
9087        set             FACT2LOW,FACT2+8
9088
9089        global          stwotox
9090#--ENTRY POINT FOR 2**(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S
9091stwotox:
9092        fmovm.x         (%a0),&0x80             # LOAD INPUT
9093
9094        mov.l           (%a0),%d1
9095        mov.w           4(%a0),%d1
9096        fmov.x          %fp0,X(%a6)
9097        and.l           &0x7FFFFFFF,%d1
9098
9099        cmp.l           %d1,&0x3FB98000         # |X| >= 2**(-70)?
9100        bge.b           TWOOK1
9101        bra.w           EXPBORS
9102
9103TWOOK1:
9104        cmp.l           %d1,&0x400D80C0         # |X| > 16480?
9105        ble.b           TWOMAIN
9106        bra.w           EXPBORS
9107
9108TWOMAIN:
9109#--USUAL CASE, 2^(-70) <= |X| <= 16480
9110
9111        fmov.x          %fp0,%fp1
9112        fmul.s          &0x42800000,%fp1        # 64 * X
9113        fmov.l          %fp1,INT(%a6)           # N = ROUND-TO-INT(64 X)
9114        mov.l           %d2,-(%sp)
9115        lea             TEXPTBL(%pc),%a1        # LOAD ADDRESS OF TABLE OF 2^(J/64)
9116        fmov.l          INT(%a6),%fp1           # N --> FLOATING FMT
9117        mov.l           INT(%a6),%d1
9118        mov.l           %d1,%d2
9119        and.l           &0x3F,%d1               # D0 IS J
9120        asl.l           &4,%d1                  # DISPLACEMENT FOR 2^(J/64)
9121        add.l           %d1,%a1                 # ADDRESS FOR 2^(J/64)
9122        asr.l           &6,%d2                  # d2 IS L, N = 64L + J
9123        mov.l           %d2,%d1
9124        asr.l           &1,%d1                  # D0 IS M
9125        sub.l           %d1,%d2                 # d2 IS M', N = 64(M+M') + J
9126        add.l           &0x3FFF,%d2
9127
9128#--SUMMARY: a1 IS ADDRESS FOR THE LEADING PORTION OF 2^(J/64),
9129#--D0 IS M WHERE N = 64(M+M') + J. NOTE THAT |M| <= 16140 BY DESIGN.
9130#--ADJFACT = 2^(M').
9131#--REGISTERS SAVED SO FAR ARE (IN ORDER) FPCR, D0, FP1, a1, AND FP2.
9132
9133        fmovm.x         &0x0c,-(%sp)            # save fp2/fp3
9134
9135        fmul.s          &0x3C800000,%fp1        # (1/64)*N
9136        mov.l           (%a1)+,FACT1(%a6)
9137        mov.l           (%a1)+,FACT1HI(%a6)
9138        mov.l           (%a1)+,FACT1LOW(%a6)
9139        mov.w           (%a1)+,FACT2(%a6)
9140
9141        fsub.x          %fp1,%fp0               # X - (1/64)*INT(64 X)
9142
9143        mov.w           (%a1)+,FACT2HI(%a6)
9144        clr.w           FACT2HI+2(%a6)
9145        clr.l           FACT2LOW(%a6)
9146        add.w           %d1,FACT1(%a6)
9147        fmul.x          LOG2(%pc),%fp0          # FP0 IS R
9148        add.w           %d1,FACT2(%a6)
9149
9150        bra.w           expr
9151
9152EXPBORS:
9153#--FPCR, D0 SAVED
9154        cmp.l           %d1,&0x3FFF8000
9155        bgt.b           TEXPBIG
9156
9157#--|X| IS SMALL, RETURN 1 + X
9158
9159        fmov.l          %d0,%fpcr               # restore users round prec,mode
9160        fadd.s          &0x3F800000,%fp0        # RETURN 1 + X
9161        bra             t_pinx2
9162
9163TEXPBIG:
9164#--|X| IS LARGE, GENERATE OVERFLOW IF X > 0; ELSE GENERATE UNDERFLOW
9165#--REGISTERS SAVE SO FAR ARE FPCR AND  D0
9166        mov.l           X(%a6),%d1
9167        cmp.l           %d1,&0
9168        blt.b           EXPNEG
9169
9170        bra             t_ovfl2                 # t_ovfl expects positive value
9171
9172EXPNEG:
9173        bra             t_unfl2                 # t_unfl expects positive value
9174
9175        global          stwotoxd
9176stwotoxd:
9177#--ENTRY POINT FOR 2**(X) FOR DENORMALIZED ARGUMENT
9178
9179        fmov.l          %d0,%fpcr               # set user's rounding mode/precision
9180        fmov.s          &0x3F800000,%fp0        # RETURN 1 + X
9181        mov.l           (%a0),%d1
9182        or.l            &0x00800001,%d1
9183        fadd.s          %d1,%fp0
9184        bra             t_pinx2
9185
9186        global          stentox
9187#--ENTRY POINT FOR 10**(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S
9188stentox:
9189        fmovm.x         (%a0),&0x80             # LOAD INPUT
9190
9191        mov.l           (%a0),%d1
9192        mov.w           4(%a0),%d1
9193        fmov.x          %fp0,X(%a6)
9194        and.l           &0x7FFFFFFF,%d1
9195
9196        cmp.l           %d1,&0x3FB98000         # |X| >= 2**(-70)?
9197        bge.b           TENOK1
9198        bra.w           EXPBORS
9199
9200TENOK1:
9201        cmp.l           %d1,&0x400B9B07         # |X| <= 16480*log2/log10 ?
9202        ble.b           TENMAIN
9203        bra.w           EXPBORS
9204
9205TENMAIN:
9206#--USUAL CASE, 2^(-70) <= |X| <= 16480 LOG 2 / LOG 10
9207
9208        fmov.x          %fp0,%fp1
9209        fmul.d          L2TEN64(%pc),%fp1       # X*64*LOG10/LOG2
9210        fmov.l          %fp1,INT(%a6)           # N=INT(X*64*LOG10/LOG2)
9211        mov.l           %d2,-(%sp)
9212        lea             TEXPTBL(%pc),%a1        # LOAD ADDRESS OF TABLE OF 2^(J/64)
9213        fmov.l          INT(%a6),%fp1           # N --> FLOATING FMT
9214        mov.l           INT(%a6),%d1
9215        mov.l           %d1,%d2
9216        and.l           &0x3F,%d1               # D0 IS J
9217        asl.l           &4,%d1                  # DISPLACEMENT FOR 2^(J/64)
9218        add.l           %d1,%a1                 # ADDRESS FOR 2^(J/64)
9219        asr.l           &6,%d2                  # d2 IS L, N = 64L + J
9220        mov.l           %d2,%d1
9221        asr.l           &1,%d1                  # D0 IS M
9222        sub.l           %d1,%d2                 # d2 IS M', N = 64(M+M') + J
9223        add.l           &0x3FFF,%d2
9224
9225#--SUMMARY: a1 IS ADDRESS FOR THE LEADING PORTION OF 2^(J/64),
9226#--D0 IS M WHERE N = 64(M+M') + J. NOTE THAT |M| <= 16140 BY DESIGN.
9227#--ADJFACT = 2^(M').
9228#--REGISTERS SAVED SO FAR ARE (IN ORDER) FPCR, D0, FP1, a1, AND FP2.
9229        fmovm.x         &0x0c,-(%sp)            # save fp2/fp3
9230
9231        fmov.x          %fp1,%fp2
9232
9233        fmul.d          L10TWO1(%pc),%fp1       # N*(LOG2/64LOG10)_LEAD
9234        mov.l           (%a1)+,FACT1(%a6)
9235
9236        fmul.x          L10TWO2(%pc),%fp2       # N*(LOG2/64LOG10)_TRAIL
9237
9238        mov.l           (%a1)+,FACT1HI(%a6)
9239        mov.l           (%a1)+,FACT1LOW(%a6)
9240        fsub.x          %fp1,%fp0               # X - N L_LEAD
9241        mov.w           (%a1)+,FACT2(%a6)
9242
9243        fsub.x          %fp2,%fp0               # X - N L_TRAIL
9244
9245        mov.w           (%a1)+,FACT2HI(%a6)
9246        clr.w           FACT2HI+2(%a6)
9247        clr.l           FACT2LOW(%a6)
9248
9249        fmul.x          LOG10(%pc),%fp0         # FP0 IS R
9250        add.w           %d1,FACT1(%a6)
9251        add.w           %d1,FACT2(%a6)
9252
9253expr:
9254#--FPCR, FP2, FP3 ARE SAVED IN ORDER AS SHOWN.
9255#--ADJFACT CONTAINS 2**(M'), FACT1 + FACT2 = 2**(M) * 2**(J/64).
9256#--FP0 IS R. THE FOLLOWING CODE COMPUTES
9257#--     2**(M'+M) * 2**(J/64) * EXP(R)
9258
9259        fmov.x          %fp0,%fp1
9260        fmul.x          %fp1,%fp1               # FP1 IS S = R*R
9261
9262        fmov.d          EXPA5(%pc),%fp2         # FP2 IS A5
9263        fmov.d          EXPA4(%pc),%fp3         # FP3 IS A4
9264
9265        fmul.x          %fp1,%fp2               # FP2 IS S*A5
9266        fmul.x          %fp1,%fp3               # FP3 IS S*A4
9267
9268        fadd.d          EXPA3(%pc),%fp2         # FP2 IS A3+S*A5
9269        fadd.d          EXPA2(%pc),%fp3         # FP3 IS A2+S*A4
9270
9271        fmul.x          %fp1,%fp2               # FP2 IS S*(A3+S*A5)
9272        fmul.x          %fp1,%fp3               # FP3 IS S*(A2+S*A4)
9273
9274        fadd.d          EXPA1(%pc),%fp2         # FP2 IS A1+S*(A3+S*A5)
9275        fmul.x          %fp0,%fp3               # FP3 IS R*S*(A2+S*A4)
9276
9277        fmul.x          %fp1,%fp2               # FP2 IS S*(A1+S*(A3+S*A5))
9278        fadd.x          %fp3,%fp0               # FP0 IS R+R*S*(A2+S*A4)
9279        fadd.x          %fp2,%fp0               # FP0 IS EXP(R) - 1
9280
9281        fmovm.x         (%sp)+,&0x30            # restore fp2/fp3
9282
9283#--FINAL RECONSTRUCTION PROCESS
9284#--EXP(X) = 2^M*2^(J/64) + 2^M*2^(J/64)*(EXP(R)-1)  -  (1 OR 0)
9285
9286        fmul.x          FACT1(%a6),%fp0
9287        fadd.x          FACT2(%a6),%fp0
9288        fadd.x          FACT1(%a6),%fp0
9289
9290        fmov.l          %d0,%fpcr               # restore users round prec,mode
9291        mov.w           %d2,ADJFACT(%a6)        # INSERT EXPONENT
9292        mov.l           (%sp)+,%d2
9293        mov.l           &0x80000000,ADJFACT+4(%a6)
9294        clr.l           ADJFACT+8(%a6)
9295        mov.b           &FMUL_OP,%d1            # last inst is MUL
9296        fmul.x          ADJFACT(%a6),%fp0       # FINAL ADJUSTMENT
9297        bra             t_catch
9298
9299        global          stentoxd
9300stentoxd:
9301#--ENTRY POINT FOR 10**(X) FOR DENORMALIZED ARGUMENT
9302
9303        fmov.l          %d0,%fpcr               # set user's rounding mode/precision
9304        fmov.s          &0x3F800000,%fp0        # RETURN 1 + X
9305        mov.l           (%a0),%d1
9306        or.l            &0x00800001,%d1
9307        fadd.s          %d1,%fp0
9308        bra             t_pinx2
9309
9310#########################################################################
9311# smovcr(): returns the ROM constant at the offset specified in d1      #
9312#           rounded to the mode and precision specified in d0.          #
9313#                                                                       #
9314# INPUT *************************************************************** #
9315#       d0 = rnd prec,mode                                              #
9316#       d1 = ROM offset                                                 #
9317#                                                                       #
9318# OUTPUT ************************************************************** #
9319#       fp0 = the ROM constant rounded to the user's rounding mode,prec #
9320#                                                                       #
9321#########################################################################
9322
9323        global          smovcr
9324smovcr:
9325        mov.l           %d1,-(%sp)              # save rom offset for a sec
9326
9327        lsr.b           &0x4,%d0                # shift ctrl bits to lo
9328        mov.l           %d0,%d1                 # make a copy
9329        andi.w          &0x3,%d1                # extract rnd mode
9330        andi.w          &0xc,%d0                # extract rnd prec
9331        swap            %d0                     # put rnd prec in hi
9332        mov.w           %d1,%d0                 # put rnd mode in lo
9333
9334        mov.l           (%sp)+,%d1              # get rom offset
9335
9336#
9337# check range of offset
9338#
9339        tst.b           %d1                     # if zero, offset is to pi
9340        beq.b           pi_tbl                  # it is pi
9341        cmpi.b          %d1,&0x0a               # check range $01 - $0a
9342        ble.b           z_val                   # if in this range, return zero
9343        cmpi.b          %d1,&0x0e               # check range $0b - $0e
9344        ble.b           sm_tbl                  # valid constants in this range
9345        cmpi.b          %d1,&0x2f               # check range $10 - $2f
9346        ble.b           z_val                   # if in this range, return zero
9347        cmpi.b          %d1,&0x3f               # check range $30 - $3f
9348        ble.b           bg_tbl                  # valid constants in this range
9349
9350z_val:
9351        bra.l           ld_pzero                # return a zero
9352
9353#
9354# the answer is PI rounded to the proper precision.
9355#
9356# fetch a pointer to the answer table relating to the proper rounding
9357# precision.
9358#
9359pi_tbl:
9360        tst.b           %d0                     # is rmode RN?
9361        bne.b           pi_not_rn               # no
9362pi_rn:
9363        lea.l           PIRN(%pc),%a0           # yes; load PI RN table addr
9364        bra.w           set_finx
9365pi_not_rn:
9366        cmpi.b          %d0,&rp_mode            # is rmode RP?
9367        beq.b           pi_rp                   # yes
9368pi_rzrm:
9369        lea.l           PIRZRM(%pc),%a0         # no; load PI RZ,RM table addr
9370        bra.b           set_finx
9371pi_rp:
9372        lea.l           PIRP(%pc),%a0           # load PI RP table addr
9373        bra.b           set_finx
9374
9375#
9376# the answer is one of:
9377#       $0B     log10(2)        (inexact)
9378#       $0C     e               (inexact)
9379#       $0D     log2(e)         (inexact)
9380#       $0E     log10(e)        (exact)
9381#
9382# fetch a pointer to the answer table relating to the proper rounding
9383# precision.
9384#
9385sm_tbl:
9386        subi.b          &0xb,%d1                # make offset in 0-4 range
9387        tst.b           %d0                     # is rmode RN?
9388        bne.b           sm_not_rn               # no
9389sm_rn:
9390        lea.l           SMALRN(%pc),%a0         # yes; load RN table addr
9391sm_tbl_cont:
9392        cmpi.b          %d1,&0x2                # is result log10(e)?
9393        ble.b           set_finx                # no; answer is inexact
9394        bra.b           no_finx                 # yes; answer is exact
9395sm_not_rn:
9396        cmpi.b          %d0,&rp_mode            # is rmode RP?
9397        beq.b           sm_rp                   # yes
9398sm_rzrm:
9399        lea.l           SMALRZRM(%pc),%a0       # no; load RZ,RM table addr
9400        bra.b           sm_tbl_cont
9401sm_rp:
9402        lea.l           SMALRP(%pc),%a0         # load RP table addr
9403        bra.b           sm_tbl_cont
9404
9405#
9406# the answer is one of:
9407#       $30     ln(2)           (inexact)
9408#       $31     ln(10)          (inexact)
9409#       $32     10^0            (exact)
9410#       $33     10^1            (exact)
9411#       $34     10^2            (exact)
9412#       $35     10^4            (exact)
9413#       $36     10^8            (exact)
9414#       $37     10^16           (exact)
9415#       $38     10^32           (inexact)
9416#       $39     10^64           (inexact)
9417#       $3A     10^128          (inexact)
9418#       $3B     10^256          (inexact)
9419#       $3C     10^512          (inexact)
9420#       $3D     10^1024         (inexact)
9421#       $3E     10^2048         (inexact)
9422#       $3F     10^4096         (inexact)
9423#
9424# fetch a pointer to the answer table relating to the proper rounding
9425# precision.
9426#
9427bg_tbl:
9428        subi.b          &0x30,%d1               # make offset in 0-f range
9429        tst.b           %d0                     # is rmode RN?
9430        bne.b           bg_not_rn               # no
9431bg_rn:
9432        lea.l           BIGRN(%pc),%a0          # yes; load RN table addr
9433bg_tbl_cont:
9434        cmpi.b          %d1,&0x1                # is offset <= $31?
9435        ble.b           set_finx                # yes; answer is inexact
9436        cmpi.b          %d1,&0x7                # is $32 <= offset <= $37?
9437        ble.b           no_finx                 # yes; answer is exact
9438        bra.b           set_finx                # no; answer is inexact
9439bg_not_rn:
9440        cmpi.b          %d0,&rp_mode            # is rmode RP?
9441        beq.b           bg_rp                   # yes
9442bg_rzrm:
9443        lea.l           BIGRZRM(%pc),%a0        # no; load RZ,RM table addr
9444        bra.b           bg_tbl_cont
9445bg_rp:
9446        lea.l           BIGRP(%pc),%a0          # load RP table addr
9447        bra.b           bg_tbl_cont
9448
9449# answer is inexact, so set INEX2 and AINEX in the user's FPSR.
9450set_finx:
9451        ori.l           &inx2a_mask,USER_FPSR(%a6) # set INEX2/AINEX
9452no_finx:
9453        mulu.w          &0xc,%d1                # offset points into tables
9454        swap            %d0                     # put rnd prec in lo word
9455        tst.b           %d0                     # is precision extended?
9456
9457        bne.b           not_ext                 # if xprec, do not call round
9458
9459# Precision is extended
9460        fmovm.x         (%a0,%d1.w),&0x80       # return result in fp0
9461        rts
9462
9463# Precision is single or double
9464not_ext:
9465        swap            %d0                     # rnd prec in upper word
9466
9467# call round() to round the answer to the proper precision.
9468# exponents out of range for single or double DO NOT cause underflow
9469# or overflow.
9470        mov.w           0x0(%a0,%d1.w),FP_SCR1_EX(%a6) # load first word
9471        mov.l           0x4(%a0,%d1.w),FP_SCR1_HI(%a6) # load second word
9472        mov.l           0x8(%a0,%d1.w),FP_SCR1_LO(%a6) # load third word
9473        mov.l           %d0,%d1
9474        clr.l           %d0                     # clear g,r,s
9475        lea             FP_SCR1(%a6),%a0        # pass ptr to answer
9476        clr.w           LOCAL_SGN(%a0)          # sign always positive
9477        bsr.l           _round                  # round the mantissa
9478
9479        fmovm.x         (%a0),&0x80             # return rounded result in fp0
9480        rts
9481
9482        align           0x4
9483
9484PIRN:   long            0x40000000,0xc90fdaa2,0x2168c235        # pi
9485PIRZRM: long            0x40000000,0xc90fdaa2,0x2168c234        # pi
9486PIRP:   long            0x40000000,0xc90fdaa2,0x2168c235        # pi
9487
9488SMALRN: long            0x3ffd0000,0x9a209a84,0xfbcff798        # log10(2)
9489        long            0x40000000,0xadf85458,0xa2bb4a9a        # e
9490        long            0x3fff0000,0xb8aa3b29,0x5c17f0bc        # log2(e)
9491        long            0x3ffd0000,0xde5bd8a9,0x37287195        # log10(e)
9492        long            0x00000000,0x00000000,0x00000000        # 0.0
9493
9494SMALRZRM:
9495        long            0x3ffd0000,0x9a209a84,0xfbcff798        # log10(2)
9496        long            0x40000000,0xadf85458,0xa2bb4a9a        # e
9497        long            0x3fff0000,0xb8aa3b29,0x5c17f0bb        # log2(e)
9498        long            0x3ffd0000,0xde5bd8a9,0x37287195        # log10(e)
9499        long            0x00000000,0x00000000,0x00000000        # 0.0
9500
9501SMALRP: long            0x3ffd0000,0x9a209a84,0xfbcff799        # log10(2)
9502        long            0x40000000,0xadf85458,0xa2bb4a9b        # e
9503        long            0x3fff0000,0xb8aa3b29,0x5c17f0bc        # log2(e)
9504        long            0x3ffd0000,0xde5bd8a9,0x37287195        # log10(e)
9505        long            0x00000000,0x00000000,0x00000000        # 0.0
9506
9507BIGRN:  long            0x3ffe0000,0xb17217f7,0xd1cf79ac        # ln(2)
9508        long            0x40000000,0x935d8ddd,0xaaa8ac17        # ln(10)
9509
9510        long            0x3fff0000,0x80000000,0x00000000        # 10 ^ 0
9511        long            0x40020000,0xA0000000,0x00000000        # 10 ^ 1
9512        long            0x40050000,0xC8000000,0x00000000        # 10 ^ 2
9513        long            0x400C0000,0x9C400000,0x00000000        # 10 ^ 4
9514        long            0x40190000,0xBEBC2000,0x00000000        # 10 ^ 8
9515        long            0x40340000,0x8E1BC9BF,0x04000000        # 10 ^ 16
9516        long            0x40690000,0x9DC5ADA8,0x2B70B59E        # 10 ^ 32
9517        long            0x40D30000,0xC2781F49,0xFFCFA6D5        # 10 ^ 64
9518        long            0x41A80000,0x93BA47C9,0x80E98CE0        # 10 ^ 128
9519        long            0x43510000,0xAA7EEBFB,0x9DF9DE8E        # 10 ^ 256
9520        long            0x46A30000,0xE319A0AE,0xA60E91C7        # 10 ^ 512
9521        long            0x4D480000,0xC9767586,0x81750C17        # 10 ^ 1024
9522        long            0x5A920000,0x9E8B3B5D,0xC53D5DE5        # 10 ^ 2048
9523        long            0x75250000,0xC4605202,0x8A20979B        # 10 ^ 4096
9524
9525BIGRZRM:
9526        long            0x3ffe0000,0xb17217f7,0xd1cf79ab        # ln(2)
9527        long            0x40000000,0x935d8ddd,0xaaa8ac16        # ln(10)
9528
9529        long            0x3fff0000,0x80000000,0x00000000        # 10 ^ 0
9530        long            0x40020000,0xA0000000,0x00000000        # 10 ^ 1
9531        long            0x40050000,0xC8000000,0x00000000        # 10 ^ 2
9532        long            0x400C0000,0x9C400000,0x00000000        # 10 ^ 4
9533        long            0x40190000,0xBEBC2000,0x00000000        # 10 ^ 8
9534        long            0x40340000,0x8E1BC9BF,0x04000000        # 10 ^ 16
9535        long            0x40690000,0x9DC5ADA8,0x2B70B59D        # 10 ^ 32
9536        long            0x40D30000,0xC2781F49,0xFFCFA6D5        # 10 ^ 64
9537        long            0x41A80000,0x93BA47C9,0x80E98CDF        # 10 ^ 128
9538        long            0x43510000,0xAA7EEBFB,0x9DF9DE8D        # 10 ^ 256
9539        long            0x46A30000,0xE319A0AE,0xA60E91C6        # 10 ^ 512
9540        long            0x4D480000,0xC9767586,0x81750C17        # 10 ^ 1024
9541        long            0x5A920000,0x9E8B3B5D,0xC53D5DE4        # 10 ^ 2048
9542        long            0x75250000,0xC4605202,0x8A20979A        # 10 ^ 4096
9543
9544BIGRP:
9545        long            0x3ffe0000,0xb17217f7,0xd1cf79ac        # ln(2)
9546        long            0x40000000,0x935d8ddd,0xaaa8ac17        # ln(10)
9547
9548        long            0x3fff0000,0x80000000,0x00000000        # 10 ^ 0
9549        long            0x40020000,0xA0000000,0x00000000        # 10 ^ 1
9550        long            0x40050000,0xC8000000,0x00000000        # 10 ^ 2
9551        long            0x400C0000,0x9C400000,0x00000000        # 10 ^ 4
9552        long            0x40190000,0xBEBC2000,0x00000000        # 10 ^ 8
9553        long            0x40340000,0x8E1BC9BF,0x04000000        # 10 ^ 16
9554        long            0x40690000,0x9DC5ADA8,0x2B70B59E        # 10 ^ 32
9555        long            0x40D30000,0xC2781F49,0xFFCFA6D6        # 10 ^ 64
9556        long            0x41A80000,0x93BA47C9,0x80E98CE0        # 10 ^ 128
9557        long            0x43510000,0xAA7EEBFB,0x9DF9DE8E        # 10 ^ 256
9558        long            0x46A30000,0xE319A0AE,0xA60E91C7        # 10 ^ 512
9559        long            0x4D480000,0xC9767586,0x81750C18        # 10 ^ 1024
9560        long            0x5A920000,0x9E8B3B5D,0xC53D5DE5        # 10 ^ 2048
9561        long            0x75250000,0xC4605202,0x8A20979B        # 10 ^ 4096
9562
9563#########################################################################
9564# sscale(): computes the destination operand scaled by the source       #
9565#           operand. If the absoulute value of the source operand is    #
9566#           >= 2^14, an overflow or underflow is returned.              #
9567#                                                                       #
9568# INPUT *************************************************************** #
9569#       a0  = pointer to double-extended source operand X               #
9570#       a1  = pointer to double-extended destination operand Y          #
9571#                                                                       #
9572# OUTPUT ************************************************************** #
9573#       fp0 =  scale(X,Y)                                               #
9574#                                                                       #
9575#########################################################################
9576
9577set     SIGN,           L_SCR1
9578
9579        global          sscale
9580sscale:
9581        mov.l           %d0,-(%sp)              # store off ctrl bits for now
9582
9583        mov.w           DST_EX(%a1),%d1         # get dst exponent
9584        smi.b           SIGN(%a6)               # use SIGN to hold dst sign
9585        andi.l          &0x00007fff,%d1         # strip sign from dst exp
9586
9587        mov.w           SRC_EX(%a0),%d0         # check src bounds
9588        andi.w          &0x7fff,%d0             # clr src sign bit
9589        cmpi.w          %d0,&0x3fff             # is src ~ ZERO?
9590        blt.w           src_small               # yes
9591        cmpi.w          %d0,&0x400c             # no; is src too big?
9592        bgt.w           src_out                 # yes
9593
9594#
9595# Source is within 2^14 range.
9596#
9597src_ok:
9598        fintrz.x        SRC(%a0),%fp0           # calc int of src
9599        fmov.l          %fp0,%d0                # int src to d0
9600# don't want any accrued bits from the fintrz showing up later since
9601# we may need to read the fpsr for the last fp op in t_catch2().
9602        fmov.l          &0x0,%fpsr
9603
9604        tst.b           DST_HI(%a1)             # is dst denormalized?
9605        bmi.b           sok_norm
9606
9607# the dst is a DENORM. normalize the DENORM and add the adjustment to
9608# the src value. then, jump to the norm part of the routine.
9609sok_dnrm:
9610        mov.l           %d0,-(%sp)              # save src for now
9611
9612        mov.w           DST_EX(%a1),FP_SCR0_EX(%a6) # make a copy
9613        mov.l           DST_HI(%a1),FP_SCR0_HI(%a6)
9614        mov.l           DST_LO(%a1),FP_SCR0_LO(%a6)
9615
9616        lea             FP_SCR0(%a6),%a0        # pass ptr to DENORM
9617        bsr.l           norm                    # normalize the DENORM
9618        neg.l           %d0
9619        add.l           (%sp)+,%d0              # add adjustment to src
9620
9621        fmovm.x         FP_SCR0(%a6),&0x80      # load normalized DENORM
9622
9623        cmpi.w          %d0,&-0x3fff            # is the shft amt really low?
9624        bge.b           sok_norm2               # thank goodness no
9625
9626# the multiply factor that we're trying to create should be a denorm
9627# for the multiply to work. Therefore, we're going to actually do a
9628# multiply with a denorm which will cause an unimplemented data type
9629# exception to be put into the machine which will be caught and corrected
9630# later. we don't do this with the DENORMs above because this method
9631# is slower. but, don't fret, I don't see it being used much either.
9632        fmov.l          (%sp)+,%fpcr            # restore user fpcr
9633        mov.l           &0x80000000,%d1         # load normalized mantissa
9634        subi.l          &-0x3fff,%d0            # how many should we shift?
9635        neg.l           %d0                     # make it positive
9636        cmpi.b          %d0,&0x20               # is it > 32?
9637        bge.b           sok_dnrm_32             # yes
9638        lsr.l           %d0,%d1                 # no; bit stays in upper lw
9639        clr.l           -(%sp)                  # insert zero low mantissa
9640        mov.l           %d1,-(%sp)              # insert new high mantissa
9641        clr.l           -(%sp)                  # make zero exponent
9642        bra.b           sok_norm_cont
9643sok_dnrm_32:
9644        subi.b          &0x20,%d0               # get shift count
9645        lsr.l           %d0,%d1                 # make low mantissa longword
9646        mov.l           %d1,-(%sp)              # insert new low mantissa
9647        clr.l           -(%sp)                  # insert zero high mantissa
9648        clr.l           -(%sp)                  # make zero exponent
9649        bra.b           sok_norm_cont
9650
9651# the src will force the dst to a DENORM value or worse. so, let's
9652# create an fp multiply that will create the result.
9653sok_norm:
9654        fmovm.x         DST(%a1),&0x80          # load fp0 with normalized src
9655sok_norm2:
9656        fmov.l          (%sp)+,%fpcr            # restore user fpcr
9657
9658        addi.w          &0x3fff,%d0             # turn src amt into exp value
9659        swap            %d0                     # put exponent in high word
9660        clr.l           -(%sp)                  # insert new exponent
9661        mov.l           &0x80000000,-(%sp)      # insert new high mantissa
9662        mov.l           %d0,-(%sp)              # insert new lo mantissa
9663
9664sok_norm_cont:
9665        fmov.l          %fpcr,%d0               # d0 needs fpcr for t_catch2
9666        mov.b           &FMUL_OP,%d1            # last inst is MUL
9667        fmul.x          (%sp)+,%fp0             # do the multiply
9668        bra             t_catch2                # catch any exceptions
9669
9670#
9671# Source is outside of 2^14 range.  Test the sign and branch
9672# to the appropriate exception handler.
9673#
9674src_out:
9675        mov.l           (%sp)+,%d0              # restore ctrl bits
9676        exg             %a0,%a1                 # swap src,dst ptrs
9677        tst.b           SRC_EX(%a1)             # is src negative?
9678        bmi             t_unfl                  # yes; underflow
9679        bra             t_ovfl_sc               # no; overflow
9680
9681#
9682# The source input is below 1, so we check for denormalized numbers
9683# and set unfl.
9684#
9685src_small:
9686        tst.b           DST_HI(%a1)             # is dst denormalized?
9687        bpl.b           ssmall_done             # yes
9688
9689        mov.l           (%sp)+,%d0
9690        fmov.l          %d0,%fpcr               # no; load control bits
9691        mov.b           &FMOV_OP,%d1            # last inst is MOVE
9692        fmov.x          DST(%a1),%fp0           # simply return dest
9693        bra             t_catch2
9694ssmall_done:
9695        mov.l           (%sp)+,%d0              # load control bits into d1
9696        mov.l           %a1,%a0                 # pass ptr to dst
9697        bra             t_resdnrm
9698
9699#########################################################################
9700# smod(): computes the fp MOD of the input values X,Y.                  #
9701# srem(): computes the fp (IEEE) REM of the input values X,Y.           #
9702#                                                                       #
9703# INPUT *************************************************************** #
9704#       a0 = pointer to extended precision input X                      #
9705#       a1 = pointer to extended precision input Y                      #
9706#       d0 = round precision,mode                                       #
9707#                                                                       #
9708#       The input operands X and Y can be either normalized or          #
9709#       denormalized.                                                   #
9710#                                                                       #
9711# OUTPUT ************************************************************** #
9712#      fp0 = FREM(X,Y) or FMOD(X,Y)                                     #
9713#                                                                       #
9714# ALGORITHM *********************************************************** #
9715#                                                                       #
9716#       Step 1.  Save and strip signs of X and Y: signX := sign(X),     #
9717#                signY := sign(Y), X := |X|, Y := |Y|,                  #
9718#                signQ := signX EOR signY. Record whether MOD or REM    #
9719#                is requested.                                          #
9720#                                                                       #
9721#       Step 2.  Set L := expo(X)-expo(Y), k := 0, Q := 0.              #
9722#                If (L < 0) then                                        #
9723#                   R := X, go to Step 4.                               #
9724#                else                                                   #
9725#                   R := 2^(-L)X, j := L.                               #
9726#                endif                                                  #
9727#                                                                       #
9728#       Step 3.  Perform MOD(X,Y)                                       #
9729#            3.1 If R = Y, go to Step 9.                                #
9730#            3.2 If R > Y, then { R := R - Y, Q := Q + 1}               #
9731#            3.3 If j = 0, go to Step 4.                                #
9732#            3.4 k := k + 1, j := j - 1, Q := 2Q, R := 2R. Go to        #
9733#                Step 3.1.                                              #
9734#                                                                       #
9735#       Step 4.  At this point, R = X - QY = MOD(X,Y). Set              #
9736#                Last_Subtract := false (used in Step 7 below). If      #
9737#                MOD is requested, go to Step 6.                        #
9738#                                                                       #
9739#       Step 5.  R = MOD(X,Y), but REM(X,Y) is requested.               #
9740#            5.1 If R < Y/2, then R = MOD(X,Y) = REM(X,Y). Go to        #
9741#                Step 6.                                                #
9742#            5.2 If R > Y/2, then { set Last_Subtract := true,          #
9743#                Q := Q + 1, Y := signY*Y }. Go to Step 6.              #
9744#            5.3 This is the tricky case of R = Y/2. If Q is odd,       #
9745#                then { Q := Q + 1, signX := -signX }.                  #
9746#                                                                       #
9747#       Step 6.  R := signX*R.                                          #
9748#                                                                       #
9749#       Step 7.  If Last_Subtract = true, R := R - Y.                   #
9750#                                                                       #
9751#       Step 8.  Return signQ, last 7 bits of Q, and R as required.     #
9752#                                                                       #
9753#       Step 9.  At this point, R = 2^(-j)*X - Q Y = Y. Thus,           #
9754#                X = 2^(j)*(Q+1)Y. set Q := 2^(j)*(Q+1),                #
9755#                R := 0. Return signQ, last 7 bits of Q, and R.         #
9756#                                                                       #
9757#########################################################################
9758
9759        set             Mod_Flag,L_SCR3
9760        set             Sc_Flag,L_SCR3+1
9761
9762        set             SignY,L_SCR2
9763        set             SignX,L_SCR2+2
9764        set             SignQ,L_SCR3+2
9765
9766        set             Y,FP_SCR0
9767        set             Y_Hi,Y+4
9768        set             Y_Lo,Y+8
9769
9770        set             R,FP_SCR1
9771        set             R_Hi,R+4
9772        set             R_Lo,R+8
9773
9774Scale:
9775        long            0x00010000,0x80000000,0x00000000,0x00000000
9776
9777        global          smod
9778smod:
9779        clr.b           FPSR_QBYTE(%a6)
9780        mov.l           %d0,-(%sp)              # save ctrl bits
9781        clr.b           Mod_Flag(%a6)
9782        bra.b           Mod_Rem
9783
9784        global          srem
9785srem:
9786        clr.b           FPSR_QBYTE(%a6)
9787        mov.l           %d0,-(%sp)              # save ctrl bits
9788        mov.b           &0x1,Mod_Flag(%a6)
9789
9790Mod_Rem:
9791#..Save sign of X and Y
9792        movm.l          &0x3f00,-(%sp)          # save data registers
9793        mov.w           SRC_EX(%a0),%d3
9794        mov.w           %d3,SignY(%a6)
9795        and.l           &0x00007FFF,%d3         # Y := |Y|
9796
9797#
9798        mov.l           SRC_HI(%a0),%d4
9799        mov.l           SRC_LO(%a0),%d5         # (D3,D4,D5) is |Y|
9800
9801        tst.l           %d3
9802        bne.b           Y_Normal
9803
9804        mov.l           &0x00003FFE,%d3         # $3FFD + 1
9805        tst.l           %d4
9806        bne.b           HiY_not0
9807
9808HiY_0:
9809        mov.l           %d5,%d4
9810        clr.l           %d5
9811        sub.l           &32,%d3
9812        clr.l           %d6
9813        bfffo           %d4{&0:&32},%d6
9814        lsl.l           %d6,%d4
9815        sub.l           %d6,%d3                 # (D3,D4,D5) is normalized
9816#                                               ...with bias $7FFD
9817        bra.b           Chk_X
9818
9819HiY_not0:
9820        clr.l           %d6
9821        bfffo           %d4{&0:&32},%d6
9822        sub.l           %d6,%d3
9823        lsl.l           %d6,%d4
9824        mov.l           %d5,%d7                 # a copy of D5
9825        lsl.l           %d6,%d5
9826        neg.l           %d6
9827        add.l           &32,%d6
9828        lsr.l           %d6,%d7
9829        or.l            %d7,%d4                 # (D3,D4,D5) normalized
9830#                                       ...with bias $7FFD
9831        bra.b           Chk_X
9832
9833Y_Normal:
9834        add.l           &0x00003FFE,%d3         # (D3,D4,D5) normalized
9835#                                       ...with bias $7FFD
9836
9837Chk_X:
9838        mov.w           DST_EX(%a1),%d0
9839        mov.w           %d0,SignX(%a6)
9840        mov.w           SignY(%a6),%d1
9841        eor.l           %d0,%d1
9842        and.l           &0x00008000,%d1
9843        mov.w           %d1,SignQ(%a6)          # sign(Q) obtained
9844        and.l           &0x00007FFF,%d0
9845        mov.l           DST_HI(%a1),%d1
9846        mov.l           DST_LO(%a1),%d2         # (D0,D1,D2) is |X|
9847        tst.l           %d0
9848        bne.b           X_Normal
9849        mov.l           &0x00003FFE,%d0
9850        tst.l           %d1
9851        bne.b           HiX_not0
9852
9853HiX_0:
9854        mov.l           %d2,%d1
9855        clr.l           %d2
9856        sub.l           &32,%d0
9857        clr.l           %d6
9858        bfffo           %d1{&0:&32},%d6
9859        lsl.l           %d6,%d1
9860        sub.l           %d6,%d0                 # (D0,D1,D2) is normalized
9861#                                       ...with bias $7FFD
9862        bra.b           Init
9863
9864HiX_not0:
9865        clr.l           %d6
9866        bfffo           %d1{&0:&32},%d6
9867        sub.l           %d6,%d0
9868        lsl.l           %d6,%d1
9869        mov.l           %d2,%d7                 # a copy of D2
9870        lsl.l           %d6,%d2
9871        neg.l           %d6
9872        add.l           &32,%d6
9873        lsr.l           %d6,%d7
9874        or.l            %d7,%d1                 # (D0,D1,D2) normalized
9875#                                       ...with bias $7FFD
9876        bra.b           Init
9877
9878X_Normal:
9879        add.l           &0x00003FFE,%d0         # (D0,D1,D2) normalized
9880#                                       ...with bias $7FFD
9881
9882Init:
9883#
9884        mov.l           %d3,L_SCR1(%a6)         # save biased exp(Y)
9885        mov.l           %d0,-(%sp)              # save biased exp(X)
9886        sub.l           %d3,%d0                 # L := expo(X)-expo(Y)
9887
9888        clr.l           %d6                     # D6 := carry <- 0
9889        clr.l           %d3                     # D3 is Q
9890        mov.l           &0,%a1                  # A1 is k; j+k=L, Q=0
9891
9892#..(Carry,D1,D2) is R
9893        tst.l           %d0
9894        bge.b           Mod_Loop_pre
9895
9896#..expo(X) < expo(Y). Thus X = mod(X,Y)
9897#
9898        mov.l           (%sp)+,%d0              # restore d0
9899        bra.w           Get_Mod
9900
9901Mod_Loop_pre:
9902        addq.l          &0x4,%sp                # erase exp(X)
9903#..At this point  R = 2^(-L)X; Q = 0; k = 0; and  k+j = L
9904Mod_Loop:
9905        tst.l           %d6                     # test carry bit
9906        bgt.b           R_GT_Y
9907
9908#..At this point carry = 0, R = (D1,D2), Y = (D4,D5)
9909        cmp.l           %d1,%d4                 # compare hi(R) and hi(Y)
9910        bne.b           R_NE_Y
9911        cmp.l           %d2,%d5                 # compare lo(R) and lo(Y)
9912        bne.b           R_NE_Y
9913
9914#..At this point, R = Y
9915        bra.w           Rem_is_0
9916
9917R_NE_Y:
9918#..use the borrow of the previous compare
9919        bcs.b           R_LT_Y                  # borrow is set iff R < Y
9920
9921R_GT_Y:
9922#..If Carry is set, then Y < (Carry,D1,D2) < 2Y. Otherwise, Carry = 0
9923#..and Y < (D1,D2) < 2Y. Either way, perform R - Y
9924        sub.l           %d5,%d2                 # lo(R) - lo(Y)
9925        subx.l          %d4,%d1                 # hi(R) - hi(Y)
9926        clr.l           %d6                     # clear carry
9927        addq.l          &1,%d3                  # Q := Q + 1
9928
9929R_LT_Y:
9930#..At this point, Carry=0, R < Y. R = 2^(k-L)X - QY; k+j = L; j >= 0.
9931        tst.l           %d0                     # see if j = 0.
9932        beq.b           PostLoop
9933
9934        add.l           %d3,%d3                 # Q := 2Q
9935        add.l           %d2,%d2                 # lo(R) = 2lo(R)
9936        roxl.l          &1,%d1                  # hi(R) = 2hi(R) + carry
9937        scs             %d6                     # set Carry if 2(R) overflows
9938        addq.l          &1,%a1                  # k := k+1
9939        subq.l          &1,%d0                  # j := j - 1
9940#..At this point, R=(Carry,D1,D2) = 2^(k-L)X - QY, j+k=L, j >= 0, R < 2Y.
9941
9942        bra.b           Mod_Loop
9943
9944PostLoop:
9945#..k = L, j = 0, Carry = 0, R = (D1,D2) = X - QY, R < Y.
9946
9947#..normalize R.
9948        mov.l           L_SCR1(%a6),%d0         # new biased expo of R
9949        tst.l           %d1
9950        bne.b           HiR_not0
9951
9952HiR_0:
9953        mov.l           %d2,%d1
9954        clr.l           %d2
9955        sub.l           &32,%d0
9956        clr.l           %d6
9957        bfffo           %d1{&0:&32},%d6
9958        lsl.l           %d6,%d1
9959        sub.l           %d6,%d0                 # (D0,D1,D2) is normalized
9960#                                       ...with bias $7FFD
9961        bra.b           Get_Mod
9962
9963HiR_not0:
9964        clr.l           %d6
9965        bfffo           %d1{&0:&32},%d6
9966        bmi.b           Get_Mod                 # already normalized
9967        sub.l           %d6,%d0
9968        lsl.l           %d6,%d1
9969        mov.l           %d2,%d7                 # a copy of D2
9970        lsl.l           %d6,%d2
9971        neg.l           %d6
9972        add.l           &32,%d6
9973        lsr.l           %d6,%d7
9974        or.l            %d7,%d1                 # (D0,D1,D2) normalized
9975
9976#
9977Get_Mod:
9978        cmp.l           %d0,&0x000041FE
9979        bge.b           No_Scale
9980Do_Scale:
9981        mov.w           %d0,R(%a6)
9982        mov.l           %d1,R_Hi(%a6)
9983        mov.l           %d2,R_Lo(%a6)
9984        mov.l           L_SCR1(%a6),%d6
9985        mov.w           %d6,Y(%a6)
9986        mov.l           %d4,Y_Hi(%a6)
9987        mov.l           %d5,Y_Lo(%a6)
9988        fmov.x          R(%a6),%fp0             # no exception
9989        mov.b           &1,Sc_Flag(%a6)
9990        bra.b           ModOrRem
9991No_Scale:
9992        mov.l           %d1,R_Hi(%a6)
9993        mov.l           %d2,R_Lo(%a6)
9994        sub.l           &0x3FFE,%d0
9995        mov.w           %d0,R(%a6)
9996        mov.l           L_SCR1(%a6),%d6
9997        sub.l           &0x3FFE,%d6
9998        mov.l           %d6,L_SCR1(%a6)
9999        fmov.x          R(%a6),%fp0
10000        mov.w           %d6,Y(%a6)
10001        mov.l           %d4,Y_Hi(%a6)
10002        mov.l           %d5,Y_Lo(%a6)
10003        clr.b           Sc_Flag(%a6)
10004
10005#
10006ModOrRem:
10007        tst.b           Mod_Flag(%a6)
10008        beq.b           Fix_Sign
10009
10010        mov.l           L_SCR1(%a6),%d6         # new biased expo(Y)
10011        subq.l          &1,%d6                  # biased expo(Y/2)
10012        cmp.l           %d0,%d6
10013        blt.b           Fix_Sign
10014        bgt.b           Last_Sub
10015
10016        cmp.l           %d1,%d4
10017        bne.b           Not_EQ
10018        cmp.l           %d2,%d5
10019        bne.b           Not_EQ
10020        bra.w           Tie_Case
10021
10022Not_EQ:
10023        bcs.b           Fix_Sign
10024
10025Last_Sub:
10026#
10027        fsub.x          Y(%a6),%fp0             # no exceptions
10028        addq.l          &1,%d3                  # Q := Q + 1
10029
10030#
10031Fix_Sign:
10032#..Get sign of X
10033        mov.w           SignX(%a6),%d6
10034        bge.b           Get_Q
10035        fneg.x          %fp0
10036
10037#..Get Q
10038#
10039Get_Q:
10040        clr.l           %d6
10041        mov.w           SignQ(%a6),%d6          # D6 is sign(Q)
10042        mov.l           &8,%d7
10043        lsr.l           %d7,%d6
10044        and.l           &0x0000007F,%d3         # 7 bits of Q
10045        or.l            %d6,%d3                 # sign and bits of Q
10046#       swap            %d3
10047#       fmov.l          %fpsr,%d6
10048#       and.l           &0xFF00FFFF,%d6
10049#       or.l            %d3,%d6
10050#       fmov.l          %d6,%fpsr               # put Q in fpsr
10051        mov.b           %d3,FPSR_QBYTE(%a6)     # put Q in fpsr
10052
10053#
10054Restore:
10055        movm.l          (%sp)+,&0xfc            #  {%d2-%d7}
10056        mov.l           (%sp)+,%d0
10057        fmov.l          %d0,%fpcr
10058        tst.b           Sc_Flag(%a6)
10059        beq.b           Finish
10060        mov.b           &FMUL_OP,%d1            # last inst is MUL
10061        fmul.x          Scale(%pc),%fp0         # may cause underflow
10062        bra             t_catch2
10063# the '040 package did this apparently to see if the dst operand for the
10064# preceding fmul was a denorm. but, it better not have been since the
10065# algorithm just got done playing with fp0 and expected no exceptions
10066# as a result. trust me...
10067#       bra             t_avoid_unsupp          # check for denorm as a
10068#                                               ;result of the scaling
10069
10070Finish:
10071        mov.b           &FMOV_OP,%d1            # last inst is MOVE
10072        fmov.x          %fp0,%fp0               # capture exceptions & round
10073        bra             t_catch2
10074
10075Rem_is_0:
10076#..R = 2^(-j)X - Q Y = Y, thus R = 0 and quotient = 2^j (Q+1)
10077        addq.l          &1,%d3
10078        cmp.l           %d0,&8                  # D0 is j
10079        bge.b           Q_Big
10080
10081        lsl.l           %d0,%d3
10082        bra.b           Set_R_0
10083
10084Q_Big:
10085        clr.l           %d3
10086
10087Set_R_0:
10088        fmov.s          &0x00000000,%fp0
10089        clr.b           Sc_Flag(%a6)
10090        bra.w           Fix_Sign
10091
10092Tie_Case:
10093#..Check parity of Q
10094        mov.l           %d3,%d6
10095        and.l           &0x00000001,%d6
10096        tst.l           %d6
10097        beq.w           Fix_Sign                # Q is even
10098
10099#..Q is odd, Q := Q + 1, signX := -signX
10100        addq.l          &1,%d3
10101        mov.w           SignX(%a6),%d6
10102        eor.l           &0x00008000,%d6
10103        mov.w           %d6,SignX(%a6)
10104        bra.w           Fix_Sign
10105
10106qnan:   long            0x7fff0000, 0xffffffff, 0xffffffff
10107
10108#########################################################################
10109# XDEF **************************************************************** #
10110#       t_dz(): Handle DZ exception during transcendental emulation.    #
10111#               Sets N bit according to sign of source operand.         #
10112#       t_dz2(): Handle DZ exception during transcendental emulation.   #
10113#                Sets N bit always.                                     #
10114#                                                                       #
10115# XREF **************************************************************** #
10116#       None                                                            #
10117#                                                                       #
10118# INPUT *************************************************************** #
10119#       a0 = pointer to source operand                                  #
10120#                                                                       #
10121# OUTPUT ************************************************************** #
10122#       fp0 = default result                                            #
10123#                                                                       #
10124# ALGORITHM *********************************************************** #
10125#       - Store properly signed INF into fp0.                           #
10126#       - Set FPSR exception status dz bit, ccode inf bit, and          #
10127#         accrued dz bit.                                               #
10128#                                                                       #
10129#########################################################################
10130
10131        global          t_dz
10132t_dz:
10133        tst.b           SRC_EX(%a0)             # no; is src negative?
10134        bmi.b           t_dz2                   # yes
10135
10136dz_pinf:
10137        fmov.s          &0x7f800000,%fp0        # return +INF in fp0
10138        ori.l           &dzinf_mask,USER_FPSR(%a6) # set I/DZ/ADZ
10139        rts
10140
10141        global          t_dz2
10142t_dz2:
10143        fmov.s          &0xff800000,%fp0        # return -INF in fp0
10144        ori.l           &dzinf_mask+neg_mask,USER_FPSR(%a6) # set N/I/DZ/ADZ
10145        rts
10146
10147#################################################################
10148# OPERR exception:                                              #
10149#       - set FPSR exception status operr bit, condition code   #
10150#         nan bit; Store default NAN into fp0                   #
10151#################################################################
10152        global          t_operr
10153t_operr:
10154        ori.l           &opnan_mask,USER_FPSR(%a6) # set NaN/OPERR/AIOP
10155        fmovm.x         qnan(%pc),&0x80         # return default NAN in fp0
10156        rts
10157
10158#################################################################
10159# Extended DENORM:                                              #
10160#       - For all functions that have a denormalized input and  #
10161#         that f(x)=x, this is the entry point.                 #
10162#       - we only return the EXOP here if either underflow or   #
10163#         inexact is enabled.                                   #
10164#################################################################
10165
10166# Entry point for scale w/ extended denorm. The function does
10167# NOT set INEX2/AUNFL/AINEX.
10168        global          t_resdnrm
10169t_resdnrm:
10170        ori.l           &unfl_mask,USER_FPSR(%a6) # set UNFL
10171        bra.b           xdnrm_con
10172
10173        global          t_extdnrm
10174t_extdnrm:
10175        ori.l           &unfinx_mask,USER_FPSR(%a6) # set UNFL/INEX2/AUNFL/AINEX
10176
10177xdnrm_con:
10178        mov.l           %a0,%a1                 # make copy of src ptr
10179        mov.l           %d0,%d1                 # make copy of rnd prec,mode
10180        andi.b          &0xc0,%d1               # extended precision?
10181        bne.b           xdnrm_sd                # no
10182
10183# result precision is extended.
10184        tst.b           LOCAL_EX(%a0)           # is denorm negative?
10185        bpl.b           xdnrm_exit              # no
10186
10187        bset            &neg_bit,FPSR_CC(%a6)   # yes; set 'N' ccode bit
10188        bra.b           xdnrm_exit
10189
10190# result precision is single or double
10191xdnrm_sd:
10192        mov.l           %a1,-(%sp)
10193        tst.b           LOCAL_EX(%a0)           # is denorm pos or neg?
10194        smi.b           %d1                     # set d0 accordingly
10195        bsr.l           unf_sub
10196        mov.l           (%sp)+,%a1
10197xdnrm_exit:
10198        fmovm.x         (%a0),&0x80             # return default result in fp0
10199
10200        mov.b           FPCR_ENABLE(%a6),%d0
10201        andi.b          &0x0a,%d0               # is UNFL or INEX enabled?
10202        bne.b           xdnrm_ena               # yes
10203        rts
10204
10205################
10206# unfl enabled #
10207################
10208# we have a DENORM that needs to be converted into an EXOP.
10209# so, normalize the mantissa, add 0x6000 to the new exponent,
10210# and return the result in fp1.
10211xdnrm_ena:
10212        mov.w           LOCAL_EX(%a1),FP_SCR0_EX(%a6)
10213        mov.l           LOCAL_HI(%a1),FP_SCR0_HI(%a6)
10214        mov.l           LOCAL_LO(%a1),FP_SCR0_LO(%a6)
10215
10216        lea             FP_SCR0(%a6),%a0
10217        bsr.l           norm                    # normalize mantissa
10218        addi.l          &0x6000,%d0             # add extra bias
10219        andi.w          &0x8000,FP_SCR0_EX(%a6) # keep old sign
10220        or.w            %d0,FP_SCR0_EX(%a6)     # insert new exponent
10221
10222        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
10223        rts
10224
10225#################################################################
10226# UNFL exception:                                               #
10227#       - This routine is for cases where even an EXOP isn't    #
10228#         large enough to hold the range of this result.        #
10229#         In such a case, the EXOP equals zero.                 #
10230#       - Return the default result to the proper precision     #
10231#         with the sign of this result being the same as that   #
10232#         of the src operand.                                   #
10233#       - t_unfl2() is provided to force the result sign to     #
10234#         positive which is the desired result for fetox().     #
10235#################################################################
10236        global          t_unfl
10237t_unfl:
10238        ori.l           &unfinx_mask,USER_FPSR(%a6) # set UNFL/INEX2/AUNFL/AINEX
10239
10240        tst.b           (%a0)                   # is result pos or neg?
10241        smi.b           %d1                     # set d1 accordingly
10242        bsr.l           unf_sub                 # calc default unfl result
10243        fmovm.x         (%a0),&0x80             # return default result in fp0
10244
10245        fmov.s          &0x00000000,%fp1        # return EXOP in fp1
10246        rts
10247
10248# t_unfl2 ALWAYS tells unf_sub to create a positive result
10249        global          t_unfl2
10250t_unfl2:
10251        ori.l           &unfinx_mask,USER_FPSR(%a6) # set UNFL/INEX2/AUNFL/AINEX
10252
10253        sf.b            %d1                     # set d0 to represent positive
10254        bsr.l           unf_sub                 # calc default unfl result
10255        fmovm.x         (%a0),&0x80             # return default result in fp0
10256
10257        fmov.s          &0x0000000,%fp1         # return EXOP in fp1
10258        rts
10259
10260#################################################################
10261# OVFL exception:                                               #
10262#       - This routine is for cases where even an EXOP isn't    #
10263#         large enough to hold the range of this result.        #
10264#       - Return the default result to the proper precision     #
10265#         with the sign of this result being the same as that   #
10266#         of the src operand.                                   #
10267#       - t_ovfl2() is provided to force the result sign to     #
10268#         positive which is the desired result for fcosh().     #
10269#       - t_ovfl_sc() is provided for scale() which only sets   #
10270#         the inexact bits if the number is inexact for the     #
10271#         precision indicated.                                  #
10272#################################################################
10273
10274        global          t_ovfl_sc
10275t_ovfl_sc:
10276        ori.l           &ovfl_inx_mask,USER_FPSR(%a6) # set OVFL/AOVFL/AINEX
10277
10278        mov.b           %d0,%d1                 # fetch rnd mode/prec
10279        andi.b          &0xc0,%d1               # extract rnd prec
10280        beq.b           ovfl_work               # prec is extended
10281
10282        tst.b           LOCAL_HI(%a0)           # is dst a DENORM?
10283        bmi.b           ovfl_sc_norm            # no
10284
10285# dst op is a DENORM. we have to normalize the mantissa to see if the
10286# result would be inexact for the given precision. make a copy of the
10287# dst so we don't screw up the version passed to us.
10288        mov.w           LOCAL_EX(%a0),FP_SCR0_EX(%a6)
10289        mov.l           LOCAL_HI(%a0),FP_SCR0_HI(%a6)
10290        mov.l           LOCAL_LO(%a0),FP_SCR0_LO(%a6)
10291        lea             FP_SCR0(%a6),%a0        # pass ptr to FP_SCR0
10292        movm.l          &0xc080,-(%sp)          # save d0-d1/a0
10293        bsr.l           norm                    # normalize mantissa
10294        movm.l          (%sp)+,&0x0103          # restore d0-d1/a0
10295
10296ovfl_sc_norm:
10297        cmpi.b          %d1,&0x40               # is prec dbl?
10298        bne.b           ovfl_sc_dbl             # no; sgl
10299ovfl_sc_sgl:
10300        tst.l           LOCAL_LO(%a0)           # is lo lw of sgl set?
10301        bne.b           ovfl_sc_inx             # yes
10302        tst.b           3+LOCAL_HI(%a0)         # is lo byte of hi lw set?
10303        bne.b           ovfl_sc_inx             # yes
10304        bra.b           ovfl_work               # don't set INEX2
10305ovfl_sc_dbl:
10306        mov.l           LOCAL_LO(%a0),%d1       # are any of lo 11 bits of
10307        andi.l          &0x7ff,%d1              # dbl mantissa set?
10308        beq.b           ovfl_work               # no; don't set INEX2
10309ovfl_sc_inx:
10310        ori.l           &inex2_mask,USER_FPSR(%a6) # set INEX2
10311        bra.b           ovfl_work               # continue
10312
10313        global          t_ovfl
10314t_ovfl:
10315        ori.l           &ovfinx_mask,USER_FPSR(%a6) # set OVFL/INEX2/AOVFL/AINEX
10316
10317ovfl_work:
10318        tst.b           LOCAL_EX(%a0)           # what is the sign?
10319        smi.b           %d1                     # set d1 accordingly
10320        bsr.l           ovf_res                 # calc default ovfl result
10321        mov.b           %d0,FPSR_CC(%a6)        # insert new ccodes
10322        fmovm.x         (%a0),&0x80             # return default result in fp0
10323
10324        fmov.s          &0x00000000,%fp1        # return EXOP in fp1
10325        rts
10326
10327# t_ovfl2 ALWAYS tells ovf_res to create a positive result
10328        global          t_ovfl2
10329t_ovfl2:
10330        ori.l           &ovfinx_mask,USER_FPSR(%a6) # set OVFL/INEX2/AOVFL/AINEX
10331
10332        sf.b            %d1                     # clear sign flag for positive
10333        bsr.l           ovf_res                 # calc default ovfl result
10334        mov.b           %d0,FPSR_CC(%a6)        # insert new ccodes
10335        fmovm.x         (%a0),&0x80             # return default result in fp0
10336
10337        fmov.s          &0x00000000,%fp1        # return EXOP in fp1
10338        rts
10339
10340#################################################################
10341# t_catch():                                                    #
10342#       - the last operation of a transcendental emulation      #
10343#         routine may have caused an underflow or overflow.     #
10344#         we find out if this occurred by doing an fsave and    #
10345#         checking the exception bit. if one did occur, then we #
10346#         jump to fgen_except() which creates the default       #
10347#         result and EXOP for us.                               #
10348#################################################################
10349        global          t_catch
10350t_catch:
10351
10352        fsave           -(%sp)
10353        tst.b           0x2(%sp)
10354        bmi.b           catch
10355        add.l           &0xc,%sp
10356
10357#################################################################
10358# INEX2 exception:                                              #
10359#       - The inex2 and ainex bits are set.                     #
10360#################################################################
10361        global          t_inx2
10362t_inx2:
10363        fblt.w          t_minx2
10364        fbeq.w          inx2_zero
10365
10366        global          t_pinx2
10367t_pinx2:
10368        ori.w           &inx2a_mask,2+USER_FPSR(%a6) # set INEX2/AINEX
10369        rts
10370
10371        global          t_minx2
10372t_minx2:
10373        ori.l           &inx2a_mask+neg_mask,USER_FPSR(%a6) # set N/INEX2/AINEX
10374        rts
10375
10376inx2_zero:
10377        mov.b           &z_bmask,FPSR_CC(%a6)
10378        ori.w           &inx2a_mask,2+USER_FPSR(%a6) # set INEX2/AINEX
10379        rts
10380
10381# an underflow or overflow exception occurred.
10382# we must set INEX/AINEX since the fmul/fdiv/fmov emulation may not!
10383catch:
10384        ori.w           &inx2a_mask,FPSR_EXCEPT(%a6)
10385catch2:
10386        bsr.l           fgen_except
10387        add.l           &0xc,%sp
10388        rts
10389
10390        global          t_catch2
10391t_catch2:
10392
10393        fsave           -(%sp)
10394
10395        tst.b           0x2(%sp)
10396        bmi.b           catch2
10397        add.l           &0xc,%sp
10398
10399        fmov.l          %fpsr,%d0
10400        or.l            %d0,USER_FPSR(%a6)
10401
10402        rts
10403
10404#########################################################################
10405
10406#########################################################################
10407# unf_res(): underflow default result calculation for transcendentals   #
10408#                                                                       #
10409# INPUT:                                                                #
10410#       d0   : rnd mode,precision                                       #
10411#       d1.b : sign bit of result ('11111111 = (-) ; '00000000 = (+))   #
10412# OUTPUT:                                                               #
10413#       a0   : points to result (in instruction memory)                 #
10414#########################################################################
10415unf_sub:
10416        ori.l           &unfinx_mask,USER_FPSR(%a6)
10417
10418        andi.w          &0x10,%d1               # keep sign bit in 4th spot
10419
10420        lsr.b           &0x4,%d0                # shift rnd prec,mode to lo bits
10421        andi.b          &0xf,%d0                # strip hi rnd mode bit
10422        or.b            %d1,%d0                 # concat {sgn,mode,prec}
10423
10424        mov.l           %d0,%d1                 # make a copy
10425        lsl.b           &0x1,%d1                # mult index 2 by 2
10426
10427        mov.b           (tbl_unf_cc.b,%pc,%d0.w*1),FPSR_CC(%a6) # insert ccode bits
10428        lea             (tbl_unf_result.b,%pc,%d1.w*8),%a0 # grab result ptr
10429        rts
10430
10431tbl_unf_cc:
10432        byte            0x4, 0x4, 0x4, 0x0
10433        byte            0x4, 0x4, 0x4, 0x0
10434        byte            0x4, 0x4, 0x4, 0x0
10435        byte            0x0, 0x0, 0x0, 0x0
10436        byte            0x8+0x4, 0x8+0x4, 0x8, 0x8+0x4
10437        byte            0x8+0x4, 0x8+0x4, 0x8, 0x8+0x4
10438        byte            0x8+0x4, 0x8+0x4, 0x8, 0x8+0x4
10439
10440tbl_unf_result:
10441        long            0x00000000, 0x00000000, 0x00000000, 0x0 # ZERO;ext
10442        long            0x00000000, 0x00000000, 0x00000000, 0x0 # ZERO;ext
10443        long            0x00000000, 0x00000000, 0x00000000, 0x0 # ZERO;ext
10444        long            0x00000000, 0x00000000, 0x00000001, 0x0 # MIN; ext
10445
10446        long            0x3f810000, 0x00000000, 0x00000000, 0x0 # ZERO;sgl
10447        long            0x3f810000, 0x00000000, 0x00000000, 0x0 # ZERO;sgl
10448        long            0x3f810000, 0x00000000, 0x00000000, 0x0 # ZERO;sgl
10449        long            0x3f810000, 0x00000100, 0x00000000, 0x0 # MIN; sgl
10450
10451        long            0x3c010000, 0x00000000, 0x00000000, 0x0 # ZERO;dbl
10452        long            0x3c010000, 0x00000000, 0x00000000, 0x0 # ZER0;dbl
10453        long            0x3c010000, 0x00000000, 0x00000000, 0x0 # ZERO;dbl
10454        long            0x3c010000, 0x00000000, 0x00000800, 0x0 # MIN; dbl
10455
10456        long            0x0,0x0,0x0,0x0
10457        long            0x0,0x0,0x0,0x0
10458        long            0x0,0x0,0x0,0x0
10459        long            0x0,0x0,0x0,0x0
10460
10461        long            0x80000000, 0x00000000, 0x00000000, 0x0 # ZERO;ext
10462        long            0x80000000, 0x00000000, 0x00000000, 0x0 # ZERO;ext
10463        long            0x80000000, 0x00000000, 0x00000001, 0x0 # MIN; ext
10464        long            0x80000000, 0x00000000, 0x00000000, 0x0 # ZERO;ext
10465
10466        long            0xbf810000, 0x00000000, 0x00000000, 0x0 # ZERO;sgl
10467        long            0xbf810000, 0x00000000, 0x00000000, 0x0 # ZERO;sgl
10468        long            0xbf810000, 0x00000100, 0x00000000, 0x0 # MIN; sgl
10469        long            0xbf810000, 0x00000000, 0x00000000, 0x0 # ZERO;sgl
10470
10471        long            0xbc010000, 0x00000000, 0x00000000, 0x0 # ZERO;dbl
10472        long            0xbc010000, 0x00000000, 0x00000000, 0x0 # ZERO;dbl
10473        long            0xbc010000, 0x00000000, 0x00000800, 0x0 # MIN; dbl
10474        long            0xbc010000, 0x00000000, 0x00000000, 0x0 # ZERO;dbl
10475
10476############################################################
10477
10478#########################################################################
10479# src_zero(): Return signed zero according to sign of src operand.      #
10480#########################################################################
10481        global          src_zero
10482src_zero:
10483        tst.b           SRC_EX(%a0)             # get sign of src operand
10484        bmi.b           ld_mzero                # if neg, load neg zero
10485
10486#
10487# ld_pzero(): return a positive zero.
10488#
10489        global          ld_pzero
10490ld_pzero:
10491        fmov.s          &0x00000000,%fp0        # load +0
10492        mov.b           &z_bmask,FPSR_CC(%a6)   # set 'Z' ccode bit
10493        rts
10494
10495# ld_mzero(): return a negative zero.
10496        global          ld_mzero
10497ld_mzero:
10498        fmov.s          &0x80000000,%fp0        # load -0
10499        mov.b           &neg_bmask+z_bmask,FPSR_CC(%a6) # set 'N','Z' ccode bits
10500        rts
10501
10502#########################################################################
10503# dst_zero(): Return signed zero according to sign of dst operand.      #
10504#########################################################################
10505        global          dst_zero
10506dst_zero:
10507        tst.b           DST_EX(%a1)             # get sign of dst operand
10508        bmi.b           ld_mzero                # if neg, load neg zero
10509        bra.b           ld_pzero                # load positive zero
10510
10511#########################################################################
10512# src_inf(): Return signed inf according to sign of src operand.        #
10513#########################################################################
10514        global          src_inf
10515src_inf:
10516        tst.b           SRC_EX(%a0)             # get sign of src operand
10517        bmi.b           ld_minf                 # if negative branch
10518
10519#
10520# ld_pinf(): return a positive infinity.
10521#
10522        global          ld_pinf
10523ld_pinf:
10524        fmov.s          &0x7f800000,%fp0        # load +INF
10525        mov.b           &inf_bmask,FPSR_CC(%a6) # set 'INF' ccode bit
10526        rts
10527
10528#
10529# ld_minf():return a negative infinity.
10530#
10531        global          ld_minf
10532ld_minf:
10533        fmov.s          &0xff800000,%fp0        # load -INF
10534        mov.b           &neg_bmask+inf_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits
10535        rts
10536
10537#########################################################################
10538# dst_inf(): Return signed inf according to sign of dst operand.        #
10539#########################################################################
10540        global          dst_inf
10541dst_inf:
10542        tst.b           DST_EX(%a1)             # get sign of dst operand
10543        bmi.b           ld_minf                 # if negative branch
10544        bra.b           ld_pinf
10545
10546        global          szr_inf
10547#################################################################
10548# szr_inf(): Return +ZERO for a negative src operand or         #
10549#                   +INF for a positive src operand.            #
10550#            Routine used for fetox, ftwotox, and ftentox.      #
10551#################################################################
10552szr_inf:
10553        tst.b           SRC_EX(%a0)             # check sign of source
10554        bmi.b           ld_pzero
10555        bra.b           ld_pinf
10556
10557#########################################################################
10558# sopr_inf(): Return +INF for a positive src operand or                 #
10559#             jump to operand error routine for a negative src operand. #
10560#             Routine used for flogn, flognp1, flog10, and flog2.       #
10561#########################################################################
10562        global          sopr_inf
10563sopr_inf:
10564        tst.b           SRC_EX(%a0)             # check sign of source
10565        bmi.w           t_operr
10566        bra.b           ld_pinf
10567
10568#################################################################
10569# setoxm1i(): Return minus one for a negative src operand or    #
10570#             positive infinity for a positive src operand.     #
10571#             Routine used for fetoxm1.                         #
10572#################################################################
10573        global          setoxm1i
10574setoxm1i:
10575        tst.b           SRC_EX(%a0)             # check sign of source
10576        bmi.b           ld_mone
10577        bra.b           ld_pinf
10578
10579#########################################################################
10580# src_one(): Return signed one according to sign of src operand.        #
10581#########################################################################
10582        global          src_one
10583src_one:
10584        tst.b           SRC_EX(%a0)             # check sign of source
10585        bmi.b           ld_mone
10586
10587#
10588# ld_pone(): return positive one.
10589#
10590        global          ld_pone
10591ld_pone:
10592        fmov.s          &0x3f800000,%fp0        # load +1
10593        clr.b           FPSR_CC(%a6)
10594        rts
10595
10596#
10597# ld_mone(): return negative one.
10598#
10599        global          ld_mone
10600ld_mone:
10601        fmov.s          &0xbf800000,%fp0        # load -1
10602        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
10603        rts
10604
10605ppiby2: long            0x3fff0000, 0xc90fdaa2, 0x2168c235
10606mpiby2: long            0xbfff0000, 0xc90fdaa2, 0x2168c235
10607
10608#################################################################
10609# spi_2(): Return signed PI/2 according to sign of src operand. #
10610#################################################################
10611        global          spi_2
10612spi_2:
10613        tst.b           SRC_EX(%a0)             # check sign of source
10614        bmi.b           ld_mpi2
10615
10616#
10617# ld_ppi2(): return positive PI/2.
10618#
10619        global          ld_ppi2
10620ld_ppi2:
10621        fmov.l          %d0,%fpcr
10622        fmov.x          ppiby2(%pc),%fp0        # load +pi/2
10623        bra.w           t_pinx2                 # set INEX2
10624
10625#
10626# ld_mpi2(): return negative PI/2.
10627#
10628        global          ld_mpi2
10629ld_mpi2:
10630        fmov.l          %d0,%fpcr
10631        fmov.x          mpiby2(%pc),%fp0        # load -pi/2
10632        bra.w           t_minx2                 # set INEX2
10633
10634####################################################
10635# The following routines give support for fsincos. #
10636####################################################
10637
10638#
10639# ssincosz(): When the src operand is ZERO, store a one in the
10640#             cosine register and return a ZERO in fp0 w/ the same sign
10641#             as the src operand.
10642#
10643        global          ssincosz
10644ssincosz:
10645        fmov.s          &0x3f800000,%fp1
10646        tst.b           SRC_EX(%a0)             # test sign
10647        bpl.b           sincoszp
10648        fmov.s          &0x80000000,%fp0        # return sin result in fp0
10649        mov.b           &z_bmask+neg_bmask,FPSR_CC(%a6)
10650        bra.b           sto_cos                 # store cosine result
10651sincoszp:
10652        fmov.s          &0x00000000,%fp0        # return sin result in fp0
10653        mov.b           &z_bmask,FPSR_CC(%a6)
10654        bra.b           sto_cos                 # store cosine result
10655
10656#
10657# ssincosi(): When the src operand is INF, store a QNAN in the cosine
10658#             register and jump to the operand error routine for negative
10659#             src operands.
10660#
10661        global          ssincosi
10662ssincosi:
10663        fmov.x          qnan(%pc),%fp1          # load NAN
10664        bsr.l           sto_cos                 # store cosine result
10665        bra.w           t_operr
10666
10667#
10668# ssincosqnan(): When the src operand is a QNAN, store the QNAN in the cosine
10669#                register and branch to the src QNAN routine.
10670#
10671        global          ssincosqnan
10672ssincosqnan:
10673        fmov.x          LOCAL_EX(%a0),%fp1
10674        bsr.l           sto_cos
10675        bra.w           src_qnan
10676
10677#
10678# ssincossnan(): When the src operand is an SNAN, store the SNAN w/ the SNAN bit set
10679#                in the cosine register and branch to the src SNAN routine.
10680#
10681        global          ssincossnan
10682ssincossnan:
10683        fmov.x          LOCAL_EX(%a0),%fp1
10684        bsr.l           sto_cos
10685        bra.w           src_snan
10686
10687########################################################################
10688
10689#########################################################################
10690# sto_cos(): store fp1 to the fpreg designated by the CMDREG dst field. #
10691#            fp1 holds the result of the cosine portion of ssincos().   #
10692#            the value in fp1 will not take any exceptions when moved.  #
10693# INPUT:                                                                #
10694#       fp1 : fp value to store                                         #
10695# MODIFIED:                                                             #
10696#       d0                                                              #
10697#########################################################################
10698        global          sto_cos
10699sto_cos:
10700        mov.b           1+EXC_CMDREG(%a6),%d0
10701        andi.w          &0x7,%d0
10702        mov.w           (tbl_sto_cos.b,%pc,%d0.w*2),%d0
10703        jmp             (tbl_sto_cos.b,%pc,%d0.w*1)
10704
10705tbl_sto_cos:
10706        short           sto_cos_0 - tbl_sto_cos
10707        short           sto_cos_1 - tbl_sto_cos
10708        short           sto_cos_2 - tbl_sto_cos
10709        short           sto_cos_3 - tbl_sto_cos
10710        short           sto_cos_4 - tbl_sto_cos
10711        short           sto_cos_5 - tbl_sto_cos
10712        short           sto_cos_6 - tbl_sto_cos
10713        short           sto_cos_7 - tbl_sto_cos
10714
10715sto_cos_0:
10716        fmovm.x         &0x40,EXC_FP0(%a6)
10717        rts
10718sto_cos_1:
10719        fmovm.x         &0x40,EXC_FP1(%a6)
10720        rts
10721sto_cos_2:
10722        fmov.x          %fp1,%fp2
10723        rts
10724sto_cos_3:
10725        fmov.x          %fp1,%fp3
10726        rts
10727sto_cos_4:
10728        fmov.x          %fp1,%fp4
10729        rts
10730sto_cos_5:
10731        fmov.x          %fp1,%fp5
10732        rts
10733sto_cos_6:
10734        fmov.x          %fp1,%fp6
10735        rts
10736sto_cos_7:
10737        fmov.x          %fp1,%fp7
10738        rts
10739
10740##################################################################
10741        global          smod_sdnrm
10742        global          smod_snorm
10743smod_sdnrm:
10744smod_snorm:
10745        mov.b           DTAG(%a6),%d1
10746        beq.l           smod
10747        cmpi.b          %d1,&ZERO
10748        beq.w           smod_zro
10749        cmpi.b          %d1,&INF
10750        beq.l           t_operr
10751        cmpi.b          %d1,&DENORM
10752        beq.l           smod
10753        cmpi.b          %d1,&SNAN
10754        beq.l           dst_snan
10755        bra.l           dst_qnan
10756
10757        global          smod_szero
10758smod_szero:
10759        mov.b           DTAG(%a6),%d1
10760        beq.l           t_operr
10761        cmpi.b          %d1,&ZERO
10762        beq.l           t_operr
10763        cmpi.b          %d1,&INF
10764        beq.l           t_operr
10765        cmpi.b          %d1,&DENORM
10766        beq.l           t_operr
10767        cmpi.b          %d1,&QNAN
10768        beq.l           dst_qnan
10769        bra.l           dst_snan
10770
10771        global          smod_sinf
10772smod_sinf:
10773        mov.b           DTAG(%a6),%d1
10774        beq.l           smod_fpn
10775        cmpi.b          %d1,&ZERO
10776        beq.l           smod_zro
10777        cmpi.b          %d1,&INF
10778        beq.l           t_operr
10779        cmpi.b          %d1,&DENORM
10780        beq.l           smod_fpn
10781        cmpi.b          %d1,&QNAN
10782        beq.l           dst_qnan
10783        bra.l           dst_snan
10784
10785smod_zro:
10786srem_zro:
10787        mov.b           SRC_EX(%a0),%d1         # get src sign
10788        mov.b           DST_EX(%a1),%d0         # get dst sign
10789        eor.b           %d0,%d1                 # get qbyte sign
10790        andi.b          &0x80,%d1
10791        mov.b           %d1,FPSR_QBYTE(%a6)
10792        tst.b           %d0
10793        bpl.w           ld_pzero
10794        bra.w           ld_mzero
10795
10796smod_fpn:
10797srem_fpn:
10798        clr.b           FPSR_QBYTE(%a6)
10799        mov.l           %d0,-(%sp)
10800        mov.b           SRC_EX(%a0),%d1         # get src sign
10801        mov.b           DST_EX(%a1),%d0         # get dst sign
10802        eor.b           %d0,%d1                 # get qbyte sign
10803        andi.b          &0x80,%d1
10804        mov.b           %d1,FPSR_QBYTE(%a6)
10805        cmpi.b          DTAG(%a6),&DENORM
10806        bne.b           smod_nrm
10807        lea             DST(%a1),%a0
10808        mov.l           (%sp)+,%d0
10809        bra             t_resdnrm
10810smod_nrm:
10811        fmov.l          (%sp)+,%fpcr
10812        fmov.x          DST(%a1),%fp0
10813        tst.b           DST_EX(%a1)
10814        bmi.b           smod_nrm_neg
10815        rts
10816
10817smod_nrm_neg:
10818        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'N' ccode
10819        rts
10820
10821#########################################################################
10822        global          srem_snorm
10823        global          srem_sdnrm
10824srem_sdnrm:
10825srem_snorm:
10826        mov.b           DTAG(%a6),%d1
10827        beq.l           srem
10828        cmpi.b          %d1,&ZERO
10829        beq.w           srem_zro
10830        cmpi.b          %d1,&INF
10831        beq.l           t_operr
10832        cmpi.b          %d1,&DENORM
10833        beq.l           srem
10834        cmpi.b          %d1,&QNAN
10835        beq.l           dst_qnan
10836        bra.l           dst_snan
10837
10838        global          srem_szero
10839srem_szero:
10840        mov.b           DTAG(%a6),%d1
10841        beq.l           t_operr
10842        cmpi.b          %d1,&ZERO
10843        beq.l           t_operr
10844        cmpi.b          %d1,&INF
10845        beq.l           t_operr
10846        cmpi.b          %d1,&DENORM
10847        beq.l           t_operr
10848        cmpi.b          %d1,&QNAN
10849        beq.l           dst_qnan
10850        bra.l           dst_snan
10851
10852        global          srem_sinf
10853srem_sinf:
10854        mov.b           DTAG(%a6),%d1
10855        beq.w           srem_fpn
10856        cmpi.b          %d1,&ZERO
10857        beq.w           srem_zro
10858        cmpi.b          %d1,&INF
10859        beq.l           t_operr
10860        cmpi.b          %d1,&DENORM
10861        beq.l           srem_fpn
10862        cmpi.b          %d1,&QNAN
10863        beq.l           dst_qnan
10864        bra.l           dst_snan
10865
10866#########################################################################
10867        global          sscale_snorm
10868        global          sscale_sdnrm
10869sscale_snorm:
10870sscale_sdnrm:
10871        mov.b           DTAG(%a6),%d1
10872        beq.l           sscale
10873        cmpi.b          %d1,&ZERO
10874        beq.l           dst_zero
10875        cmpi.b          %d1,&INF
10876        beq.l           dst_inf
10877        cmpi.b          %d1,&DENORM
10878        beq.l           sscale
10879        cmpi.b          %d1,&QNAN
10880        beq.l           dst_qnan
10881        bra.l           dst_snan
10882
10883        global          sscale_szero
10884sscale_szero:
10885        mov.b           DTAG(%a6),%d1
10886        beq.l           sscale
10887        cmpi.b          %d1,&ZERO
10888        beq.l           dst_zero
10889        cmpi.b          %d1,&INF
10890        beq.l           dst_inf
10891        cmpi.b          %d1,&DENORM
10892        beq.l           sscale
10893        cmpi.b          %d1,&QNAN
10894        beq.l           dst_qnan
10895        bra.l           dst_snan
10896
10897        global          sscale_sinf
10898sscale_sinf:
10899        mov.b           DTAG(%a6),%d1
10900        beq.l           t_operr
10901        cmpi.b          %d1,&QNAN
10902        beq.l           dst_qnan
10903        cmpi.b          %d1,&SNAN
10904        beq.l           dst_snan
10905        bra.l           t_operr
10906
10907########################################################################
10908
10909#
10910# sop_sqnan(): The src op for frem/fmod/fscale was a QNAN.
10911#
10912        global          sop_sqnan
10913sop_sqnan:
10914        mov.b           DTAG(%a6),%d1
10915        cmpi.b          %d1,&QNAN
10916        beq.b           dst_qnan
10917        cmpi.b          %d1,&SNAN
10918        beq.b           dst_snan
10919        bra.b           src_qnan
10920
10921#
10922# sop_ssnan(): The src op for frem/fmod/fscale was an SNAN.
10923#
10924        global          sop_ssnan
10925sop_ssnan:
10926        mov.b           DTAG(%a6),%d1
10927        cmpi.b          %d1,&QNAN
10928        beq.b           dst_qnan_src_snan
10929        cmpi.b          %d1,&SNAN
10930        beq.b           dst_snan
10931        bra.b           src_snan
10932
10933dst_qnan_src_snan:
10934        ori.l           &snaniop_mask,USER_FPSR(%a6) # set NAN/SNAN/AIOP
10935        bra.b           dst_qnan
10936
10937#
10938# dst_qnan(): Return the dst SNAN w/ the SNAN bit set.
10939#
10940        global          dst_snan
10941dst_snan:
10942        fmov.x          DST(%a1),%fp0           # the fmove sets the SNAN bit
10943        fmov.l          %fpsr,%d0               # catch resulting status
10944        or.l            %d0,USER_FPSR(%a6)      # store status
10945        rts
10946
10947#
10948# dst_qnan(): Return the dst QNAN.
10949#
10950        global          dst_qnan
10951dst_qnan:
10952        fmov.x          DST(%a1),%fp0           # return the non-signalling nan
10953        tst.b           DST_EX(%a1)             # set ccodes according to QNAN sign
10954        bmi.b           dst_qnan_m
10955dst_qnan_p:
10956        mov.b           &nan_bmask,FPSR_CC(%a6)
10957        rts
10958dst_qnan_m:
10959        mov.b           &neg_bmask+nan_bmask,FPSR_CC(%a6)
10960        rts
10961
10962#
10963# src_snan(): Return the src SNAN w/ the SNAN bit set.
10964#
10965        global          src_snan
10966src_snan:
10967        fmov.x          SRC(%a0),%fp0           # the fmove sets the SNAN bit
10968        fmov.l          %fpsr,%d0               # catch resulting status
10969        or.l            %d0,USER_FPSR(%a6)      # store status
10970        rts
10971
10972#
10973# src_qnan(): Return the src QNAN.
10974#
10975        global          src_qnan
10976src_qnan:
10977        fmov.x          SRC(%a0),%fp0           # return the non-signalling nan
10978        tst.b           SRC_EX(%a0)             # set ccodes according to QNAN sign
10979        bmi.b           dst_qnan_m
10980src_qnan_p:
10981        mov.b           &nan_bmask,FPSR_CC(%a6)
10982        rts
10983src_qnan_m:
10984        mov.b           &neg_bmask+nan_bmask,FPSR_CC(%a6)
10985        rts
10986
10987#
10988# fkern2.s:
10989#       These entry points are used by the exception handler
10990# routines where an instruction is selected by an index into
10991# a large jump table corresponding to a given instruction which
10992# has been decoded. Flow continues here where we now decode
10993# further according to the source operand type.
10994#
10995
10996        global          fsinh
10997fsinh:
10998        mov.b           STAG(%a6),%d1
10999        beq.l           ssinh
11000        cmpi.b          %d1,&ZERO
11001        beq.l           src_zero
11002        cmpi.b          %d1,&INF
11003        beq.l           src_inf
11004        cmpi.b          %d1,&DENORM
11005        beq.l           ssinhd
11006        cmpi.b          %d1,&QNAN
11007        beq.l           src_qnan
11008        bra.l           src_snan
11009
11010        global          flognp1
11011flognp1:
11012        mov.b           STAG(%a6),%d1
11013        beq.l           slognp1
11014        cmpi.b          %d1,&ZERO
11015        beq.l           src_zero
11016        cmpi.b          %d1,&INF
11017        beq.l           sopr_inf
11018        cmpi.b          %d1,&DENORM
11019        beq.l           slognp1d
11020        cmpi.b          %d1,&QNAN
11021        beq.l           src_qnan
11022        bra.l           src_snan
11023
11024        global          fetoxm1
11025fetoxm1:
11026        mov.b           STAG(%a6),%d1
11027        beq.l           setoxm1
11028        cmpi.b          %d1,&ZERO
11029        beq.l           src_zero
11030        cmpi.b          %d1,&INF
11031        beq.l           setoxm1i
11032        cmpi.b          %d1,&DENORM
11033        beq.l           setoxm1d
11034        cmpi.b          %d1,&QNAN
11035        beq.l           src_qnan
11036        bra.l           src_snan
11037
11038        global          ftanh
11039ftanh:
11040        mov.b           STAG(%a6),%d1
11041        beq.l           stanh
11042        cmpi.b          %d1,&ZERO
11043        beq.l           src_zero
11044        cmpi.b          %d1,&INF
11045        beq.l           src_one
11046        cmpi.b          %d1,&DENORM
11047        beq.l           stanhd
11048        cmpi.b          %d1,&QNAN
11049        beq.l           src_qnan
11050        bra.l           src_snan
11051
11052        global          fatan
11053fatan:
11054        mov.b           STAG(%a6),%d1
11055        beq.l           satan
11056        cmpi.b          %d1,&ZERO
11057        beq.l           src_zero
11058        cmpi.b          %d1,&INF
11059        beq.l           spi_2
11060        cmpi.b          %d1,&DENORM
11061        beq.l           satand
11062        cmpi.b          %d1,&QNAN
11063        beq.l           src_qnan
11064        bra.l           src_snan
11065
11066        global          fasin
11067fasin:
11068        mov.b           STAG(%a6),%d1
11069        beq.l           sasin
11070        cmpi.b          %d1,&ZERO
11071        beq.l           src_zero
11072        cmpi.b          %d1,&INF
11073        beq.l           t_operr
11074        cmpi.b          %d1,&DENORM
11075        beq.l           sasind
11076        cmpi.b          %d1,&QNAN
11077        beq.l           src_qnan
11078        bra.l           src_snan
11079
11080        global          fatanh
11081fatanh:
11082        mov.b           STAG(%a6),%d1
11083        beq.l           satanh
11084        cmpi.b          %d1,&ZERO
11085        beq.l           src_zero
11086        cmpi.b          %d1,&INF
11087        beq.l           t_operr
11088        cmpi.b          %d1,&DENORM
11089        beq.l           satanhd
11090        cmpi.b          %d1,&QNAN
11091        beq.l           src_qnan
11092        bra.l           src_snan
11093
11094        global          fsine
11095fsine:
11096        mov.b           STAG(%a6),%d1
11097        beq.l           ssin
11098        cmpi.b          %d1,&ZERO
11099        beq.l           src_zero
11100        cmpi.b          %d1,&INF
11101        beq.l           t_operr
11102        cmpi.b          %d1,&DENORM
11103        beq.l           ssind
11104        cmpi.b          %d1,&QNAN
11105        beq.l           src_qnan
11106        bra.l           src_snan
11107
11108        global          ftan
11109ftan:
11110        mov.b           STAG(%a6),%d1
11111        beq.l           stan
11112        cmpi.b          %d1,&ZERO
11113        beq.l           src_zero
11114        cmpi.b          %d1,&INF
11115        beq.l           t_operr
11116        cmpi.b          %d1,&DENORM
11117        beq.l           stand
11118        cmpi.b          %d1,&QNAN
11119        beq.l           src_qnan
11120        bra.l           src_snan
11121
11122        global          fetox
11123fetox:
11124        mov.b           STAG(%a6),%d1
11125        beq.l           setox
11126        cmpi.b          %d1,&ZERO
11127        beq.l           ld_pone
11128        cmpi.b          %d1,&INF
11129        beq.l           szr_inf
11130        cmpi.b          %d1,&DENORM
11131        beq.l           setoxd
11132        cmpi.b          %d1,&QNAN
11133        beq.l           src_qnan
11134        bra.l           src_snan
11135
11136        global          ftwotox
11137ftwotox:
11138        mov.b           STAG(%a6),%d1
11139        beq.l           stwotox
11140        cmpi.b          %d1,&ZERO
11141        beq.l           ld_pone
11142        cmpi.b          %d1,&INF
11143        beq.l           szr_inf
11144        cmpi.b          %d1,&DENORM
11145        beq.l           stwotoxd
11146        cmpi.b          %d1,&QNAN
11147        beq.l           src_qnan
11148        bra.l           src_snan
11149
11150        global          ftentox
11151ftentox:
11152        mov.b           STAG(%a6),%d1
11153        beq.l           stentox
11154        cmpi.b          %d1,&ZERO
11155        beq.l           ld_pone
11156        cmpi.b          %d1,&INF
11157        beq.l           szr_inf
11158        cmpi.b          %d1,&DENORM
11159        beq.l           stentoxd
11160        cmpi.b          %d1,&QNAN
11161        beq.l           src_qnan
11162        bra.l           src_snan
11163
11164        global          flogn
11165flogn:
11166        mov.b           STAG(%a6),%d1
11167        beq.l           slogn
11168        cmpi.b          %d1,&ZERO
11169        beq.l           t_dz2
11170        cmpi.b          %d1,&INF
11171        beq.l           sopr_inf
11172        cmpi.b          %d1,&DENORM
11173        beq.l           slognd
11174        cmpi.b          %d1,&QNAN
11175        beq.l           src_qnan
11176        bra.l           src_snan
11177
11178        global          flog10
11179flog10:
11180        mov.b           STAG(%a6),%d1
11181        beq.l           slog10
11182        cmpi.b          %d1,&ZERO
11183        beq.l           t_dz2
11184        cmpi.b          %d1,&INF
11185        beq.l           sopr_inf
11186        cmpi.b          %d1,&DENORM
11187        beq.l           slog10d
11188        cmpi.b          %d1,&QNAN
11189        beq.l           src_qnan
11190        bra.l           src_snan
11191
11192        global          flog2
11193flog2:
11194        mov.b           STAG(%a6),%d1
11195        beq.l           slog2
11196        cmpi.b          %d1,&ZERO
11197        beq.l           t_dz2
11198        cmpi.b          %d1,&INF
11199        beq.l           sopr_inf
11200        cmpi.b          %d1,&DENORM
11201        beq.l           slog2d
11202        cmpi.b          %d1,&QNAN
11203        beq.l           src_qnan
11204        bra.l           src_snan
11205
11206        global          fcosh
11207fcosh:
11208        mov.b           STAG(%a6),%d1
11209        beq.l           scosh
11210        cmpi.b          %d1,&ZERO
11211        beq.l           ld_pone
11212        cmpi.b          %d1,&INF
11213        beq.l           ld_pinf
11214        cmpi.b          %d1,&DENORM
11215        beq.l           scoshd
11216        cmpi.b          %d1,&QNAN
11217        beq.l           src_qnan
11218        bra.l           src_snan
11219
11220        global          facos
11221facos:
11222        mov.b           STAG(%a6),%d1
11223        beq.l           sacos
11224        cmpi.b          %d1,&ZERO
11225        beq.l           ld_ppi2
11226        cmpi.b          %d1,&INF
11227        beq.l           t_operr
11228        cmpi.b          %d1,&DENORM
11229        beq.l           sacosd
11230        cmpi.b          %d1,&QNAN
11231        beq.l           src_qnan
11232        bra.l           src_snan
11233
11234        global          fcos
11235fcos:
11236        mov.b           STAG(%a6),%d1
11237        beq.l           scos
11238        cmpi.b          %d1,&ZERO
11239        beq.l           ld_pone
11240        cmpi.b          %d1,&INF
11241        beq.l           t_operr
11242        cmpi.b          %d1,&DENORM
11243        beq.l           scosd
11244        cmpi.b          %d1,&QNAN
11245        beq.l           src_qnan
11246        bra.l           src_snan
11247
11248        global          fgetexp
11249fgetexp:
11250        mov.b           STAG(%a6),%d1
11251        beq.l           sgetexp
11252        cmpi.b          %d1,&ZERO
11253        beq.l           src_zero
11254        cmpi.b          %d1,&INF
11255        beq.l           t_operr
11256        cmpi.b          %d1,&DENORM
11257        beq.l           sgetexpd
11258        cmpi.b          %d1,&QNAN
11259        beq.l           src_qnan
11260        bra.l           src_snan
11261
11262        global          fgetman
11263fgetman:
11264        mov.b           STAG(%a6),%d1
11265        beq.l           sgetman
11266        cmpi.b          %d1,&ZERO
11267        beq.l           src_zero
11268        cmpi.b          %d1,&INF
11269        beq.l           t_operr
11270        cmpi.b          %d1,&DENORM
11271        beq.l           sgetmand
11272        cmpi.b          %d1,&QNAN
11273        beq.l           src_qnan
11274        bra.l           src_snan
11275
11276        global          fsincos
11277fsincos:
11278        mov.b           STAG(%a6),%d1
11279        beq.l           ssincos
11280        cmpi.b          %d1,&ZERO
11281        beq.l           ssincosz
11282        cmpi.b          %d1,&INF
11283        beq.l           ssincosi
11284        cmpi.b          %d1,&DENORM
11285        beq.l           ssincosd
11286        cmpi.b          %d1,&QNAN
11287        beq.l           ssincosqnan
11288        bra.l           ssincossnan
11289
11290        global          fmod
11291fmod:
11292        mov.b           STAG(%a6),%d1
11293        beq.l           smod_snorm
11294        cmpi.b          %d1,&ZERO
11295        beq.l           smod_szero
11296        cmpi.b          %d1,&INF
11297        beq.l           smod_sinf
11298        cmpi.b          %d1,&DENORM
11299        beq.l           smod_sdnrm
11300        cmpi.b          %d1,&QNAN
11301        beq.l           sop_sqnan
11302        bra.l           sop_ssnan
11303
11304        global          frem
11305frem:
11306        mov.b           STAG(%a6),%d1
11307        beq.l           srem_snorm
11308        cmpi.b          %d1,&ZERO
11309        beq.l           srem_szero
11310        cmpi.b          %d1,&INF
11311        beq.l           srem_sinf
11312        cmpi.b          %d1,&DENORM
11313        beq.l           srem_sdnrm
11314        cmpi.b          %d1,&QNAN
11315        beq.l           sop_sqnan
11316        bra.l           sop_ssnan
11317
11318        global          fscale
11319fscale:
11320        mov.b           STAG(%a6),%d1
11321        beq.l           sscale_snorm
11322        cmpi.b          %d1,&ZERO
11323        beq.l           sscale_szero
11324        cmpi.b          %d1,&INF
11325        beq.l           sscale_sinf
11326        cmpi.b          %d1,&DENORM
11327        beq.l           sscale_sdnrm
11328        cmpi.b          %d1,&QNAN
11329        beq.l           sop_sqnan
11330        bra.l           sop_ssnan
11331
11332#########################################################################
11333# XDEF **************************************************************** #
11334#       fgen_except(): catch an exception during transcendental         #
11335#                      emulation                                        #
11336#                                                                       #
11337# XREF **************************************************************** #
11338#       fmul() - emulate a multiply instruction                         #
11339#       fadd() - emulate an add instruction                             #
11340#       fin() - emulate an fmove instruction                            #
11341#                                                                       #
11342# INPUT *************************************************************** #
11343#       fp0 = destination operand                                       #
11344#       d0  = type of instruction that took exception                   #
11345#       fsave frame = source operand                                    #
11346#                                                                       #
11347# OUTPUT ************************************************************** #
11348#       fp0 = result                                                    #
11349#       fp1 = EXOP                                                      #
11350#                                                                       #
11351# ALGORITHM *********************************************************** #
11352#       An exception occurred on the last instruction of the            #
11353# transcendental emulation. hopefully, this won't be happening much     #
11354# because it will be VERY slow.                                         #
11355#       The only exceptions capable of passing through here are         #
11356# Overflow, Underflow, and Unsupported Data Type.                       #
11357#                                                                       #
11358#########################################################################
11359
11360        global          fgen_except
11361fgen_except:
11362        cmpi.b          0x3(%sp),&0x7           # is exception UNSUPP?
11363        beq.b           fge_unsupp              # yes
11364
11365        mov.b           &NORM,STAG(%a6)
11366
11367fge_cont:
11368        mov.b           &NORM,DTAG(%a6)
11369
11370# ok, I have a problem with putting the dst op at FP_DST. the emulation
11371# routines aren't supposed to alter the operands but we've just squashed
11372# FP_DST here...
11373
11374# 8/17/93 - this turns out to be more of a "cleanliness" standpoint
11375# then a potential bug. to begin with, only the dyadic functions
11376# frem,fmod, and fscale would get the dst trashed here. But, for
11377# the 060SP, the FP_DST is never used again anyways.
11378        fmovm.x         &0x80,FP_DST(%a6)       # dst op is in fp0
11379
11380        lea             0x4(%sp),%a0            # pass: ptr to src op
11381        lea             FP_DST(%a6),%a1         # pass: ptr to dst op
11382
11383        cmpi.b          %d1,&FMOV_OP
11384        beq.b           fge_fin                 # it was an "fmov"
11385        cmpi.b          %d1,&FADD_OP
11386        beq.b           fge_fadd                # it was an "fadd"
11387fge_fmul:
11388        bsr.l           fmul
11389        rts
11390fge_fadd:
11391        bsr.l           fadd
11392        rts
11393fge_fin:
11394        bsr.l           fin
11395        rts
11396
11397fge_unsupp:
11398        mov.b           &DENORM,STAG(%a6)
11399        bra.b           fge_cont
11400
11401#
11402# This table holds the offsets of the emulation routines for each individual
11403# math operation relative to the address of this table. Included are
11404# routines like fadd/fmul/fabs as well as the transcendentals.
11405# The location within the table is determined by the extension bits of the
11406# operation longword.
11407#
11408
11409        swbeg           &109
11410tbl_unsupp:
11411        long            fin             - tbl_unsupp    # 00: fmove
11412        long            fint            - tbl_unsupp    # 01: fint
11413        long            fsinh           - tbl_unsupp    # 02: fsinh
11414        long            fintrz          - tbl_unsupp    # 03: fintrz
11415        long            fsqrt           - tbl_unsupp    # 04: fsqrt
11416        long            tbl_unsupp      - tbl_unsupp
11417        long            flognp1         - tbl_unsupp    # 06: flognp1
11418        long            tbl_unsupp      - tbl_unsupp
11419        long            fetoxm1         - tbl_unsupp    # 08: fetoxm1
11420        long            ftanh           - tbl_unsupp    # 09: ftanh
11421        long            fatan           - tbl_unsupp    # 0a: fatan
11422        long            tbl_unsupp      - tbl_unsupp
11423        long            fasin           - tbl_unsupp    # 0c: fasin
11424        long            fatanh          - tbl_unsupp    # 0d: fatanh
11425        long            fsine           - tbl_unsupp    # 0e: fsin
11426        long            ftan            - tbl_unsupp    # 0f: ftan
11427        long            fetox           - tbl_unsupp    # 10: fetox
11428        long            ftwotox         - tbl_unsupp    # 11: ftwotox
11429        long            ftentox         - tbl_unsupp    # 12: ftentox
11430        long            tbl_unsupp      - tbl_unsupp
11431        long            flogn           - tbl_unsupp    # 14: flogn
11432        long            flog10          - tbl_unsupp    # 15: flog10
11433        long            flog2           - tbl_unsupp    # 16: flog2
11434        long            tbl_unsupp      - tbl_unsupp
11435        long            fabs            - tbl_unsupp    # 18: fabs
11436        long            fcosh           - tbl_unsupp    # 19: fcosh
11437        long            fneg            - tbl_unsupp    # 1a: fneg
11438        long            tbl_unsupp      - tbl_unsupp
11439        long            facos           - tbl_unsupp    # 1c: facos
11440        long            fcos            - tbl_unsupp    # 1d: fcos
11441        long            fgetexp         - tbl_unsupp    # 1e: fgetexp
11442        long            fgetman         - tbl_unsupp    # 1f: fgetman
11443        long            fdiv            - tbl_unsupp    # 20: fdiv
11444        long            fmod            - tbl_unsupp    # 21: fmod
11445        long            fadd            - tbl_unsupp    # 22: fadd
11446        long            fmul            - tbl_unsupp    # 23: fmul
11447        long            fsgldiv         - tbl_unsupp    # 24: fsgldiv
11448        long            frem            - tbl_unsupp    # 25: frem
11449        long            fscale          - tbl_unsupp    # 26: fscale
11450        long            fsglmul         - tbl_unsupp    # 27: fsglmul
11451        long            fsub            - tbl_unsupp    # 28: fsub
11452        long            tbl_unsupp      - tbl_unsupp
11453        long            tbl_unsupp      - tbl_unsupp
11454        long            tbl_unsupp      - tbl_unsupp
11455        long            tbl_unsupp      - tbl_unsupp
11456        long            tbl_unsupp      - tbl_unsupp
11457        long            tbl_unsupp      - tbl_unsupp
11458        long            tbl_unsupp      - tbl_unsupp
11459        long            fsincos         - tbl_unsupp    # 30: fsincos
11460        long            fsincos         - tbl_unsupp    # 31: fsincos
11461        long            fsincos         - tbl_unsupp    # 32: fsincos
11462        long            fsincos         - tbl_unsupp    # 33: fsincos
11463        long            fsincos         - tbl_unsupp    # 34: fsincos
11464        long            fsincos         - tbl_unsupp    # 35: fsincos
11465        long            fsincos         - tbl_unsupp    # 36: fsincos
11466        long            fsincos         - tbl_unsupp    # 37: fsincos
11467        long            fcmp            - tbl_unsupp    # 38: fcmp
11468        long            tbl_unsupp      - tbl_unsupp
11469        long            ftst            - tbl_unsupp    # 3a: ftst
11470        long            tbl_unsupp      - tbl_unsupp
11471        long            tbl_unsupp      - tbl_unsupp
11472        long            tbl_unsupp      - tbl_unsupp
11473        long            tbl_unsupp      - tbl_unsupp
11474        long            tbl_unsupp      - tbl_unsupp
11475        long            fsin            - tbl_unsupp    # 40: fsmove
11476        long            fssqrt          - tbl_unsupp    # 41: fssqrt
11477        long            tbl_unsupp      - tbl_unsupp
11478        long            tbl_unsupp      - tbl_unsupp
11479        long            fdin            - tbl_unsupp    # 44: fdmove
11480        long            fdsqrt          - tbl_unsupp    # 45: fdsqrt
11481        long            tbl_unsupp      - tbl_unsupp
11482        long            tbl_unsupp      - tbl_unsupp
11483        long            tbl_unsupp      - tbl_unsupp
11484        long            tbl_unsupp      - tbl_unsupp
11485        long            tbl_unsupp      - tbl_unsupp
11486        long            tbl_unsupp      - tbl_unsupp
11487        long            tbl_unsupp      - tbl_unsupp
11488        long            tbl_unsupp      - tbl_unsupp
11489        long            tbl_unsupp      - tbl_unsupp
11490        long            tbl_unsupp      - tbl_unsupp
11491        long            tbl_unsupp      - tbl_unsupp
11492        long            tbl_unsupp      - tbl_unsupp
11493        long            tbl_unsupp      - tbl_unsupp
11494        long            tbl_unsupp      - tbl_unsupp
11495        long            tbl_unsupp      - tbl_unsupp
11496        long            tbl_unsupp      - tbl_unsupp
11497        long            tbl_unsupp      - tbl_unsupp
11498        long            tbl_unsupp      - tbl_unsupp
11499        long            fsabs           - tbl_unsupp    # 58: fsabs
11500        long            tbl_unsupp      - tbl_unsupp
11501        long            fsneg           - tbl_unsupp    # 5a: fsneg
11502        long            tbl_unsupp      - tbl_unsupp
11503        long            fdabs           - tbl_unsupp    # 5c: fdabs
11504        long            tbl_unsupp      - tbl_unsupp
11505        long            fdneg           - tbl_unsupp    # 5e: fdneg
11506        long            tbl_unsupp      - tbl_unsupp
11507        long            fsdiv           - tbl_unsupp    # 60: fsdiv
11508        long            tbl_unsupp      - tbl_unsupp
11509        long            fsadd           - tbl_unsupp    # 62: fsadd
11510        long            fsmul           - tbl_unsupp    # 63: fsmul
11511        long            fddiv           - tbl_unsupp    # 64: fddiv
11512        long            tbl_unsupp      - tbl_unsupp
11513        long            fdadd           - tbl_unsupp    # 66: fdadd
11514        long            fdmul           - tbl_unsupp    # 67: fdmul
11515        long            fssub           - tbl_unsupp    # 68: fssub
11516        long            tbl_unsupp      - tbl_unsupp
11517        long            tbl_unsupp      - tbl_unsupp
11518        long            tbl_unsupp      - tbl_unsupp
11519        long            fdsub           - tbl_unsupp    # 6c: fdsub
11520
11521#########################################################################
11522# XDEF **************************************************************** #
11523#       fmul(): emulates the fmul instruction                           #
11524#       fsmul(): emulates the fsmul instruction                         #
11525#       fdmul(): emulates the fdmul instruction                         #
11526#                                                                       #
11527# XREF **************************************************************** #
11528#       scale_to_zero_src() - scale src exponent to zero                #
11529#       scale_to_zero_dst() - scale dst exponent to zero                #
11530#       unf_res() - return default underflow result                     #
11531#       ovf_res() - return default overflow result                      #
11532#       res_qnan() - return QNAN result                                 #
11533#       res_snan() - return SNAN result                                 #
11534#                                                                       #
11535# INPUT *************************************************************** #
11536#       a0 = pointer to extended precision source operand               #
11537#       a1 = pointer to extended precision destination operand          #
11538#       d0  rnd prec,mode                                               #
11539#                                                                       #
11540# OUTPUT ************************************************************** #
11541#       fp0 = result                                                    #
11542#       fp1 = EXOP (if exception occurred)                              #
11543#                                                                       #
11544# ALGORITHM *********************************************************** #
11545#       Handle NANs, infinities, and zeroes as special cases. Divide    #
11546# norms/denorms into ext/sgl/dbl precision.                             #
11547#       For norms/denorms, scale the exponents such that a multiply     #
11548# instruction won't cause an exception. Use the regular fmul to         #
11549# compute a result. Check if the regular operands would have taken      #
11550# an exception. If so, return the default overflow/underflow result     #
11551# and return the EXOP if exceptions are enabled. Else, scale the        #
11552# result operand to the proper exponent.                                #
11553#                                                                       #
11554#########################################################################
11555
11556        align           0x10
11557tbl_fmul_ovfl:
11558        long            0x3fff - 0x7ffe         # ext_max
11559        long            0x3fff - 0x407e         # sgl_max
11560        long            0x3fff - 0x43fe         # dbl_max
11561tbl_fmul_unfl:
11562        long            0x3fff + 0x0001         # ext_unfl
11563        long            0x3fff - 0x3f80         # sgl_unfl
11564        long            0x3fff - 0x3c00         # dbl_unfl
11565
11566        global          fsmul
11567fsmul:
11568        andi.b          &0x30,%d0               # clear rnd prec
11569        ori.b           &s_mode*0x10,%d0        # insert sgl prec
11570        bra.b           fmul
11571
11572        global          fdmul
11573fdmul:
11574        andi.b          &0x30,%d0
11575        ori.b           &d_mode*0x10,%d0        # insert dbl prec
11576
11577        global          fmul
11578fmul:
11579        mov.l           %d0,L_SCR3(%a6)         # store rnd info
11580
11581        clr.w           %d1
11582        mov.b           DTAG(%a6),%d1
11583        lsl.b           &0x3,%d1
11584        or.b            STAG(%a6),%d1           # combine src tags
11585        bne.w           fmul_not_norm           # optimize on non-norm input
11586
11587fmul_norm:
11588        mov.w           DST_EX(%a1),FP_SCR1_EX(%a6)
11589        mov.l           DST_HI(%a1),FP_SCR1_HI(%a6)
11590        mov.l           DST_LO(%a1),FP_SCR1_LO(%a6)
11591
11592        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
11593        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
11594        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
11595
11596        bsr.l           scale_to_zero_src       # scale src exponent
11597        mov.l           %d0,-(%sp)              # save scale factor 1
11598
11599        bsr.l           scale_to_zero_dst       # scale dst exponent
11600
11601        add.l           %d0,(%sp)               # SCALE_FACTOR = scale1 + scale2
11602
11603        mov.w           2+L_SCR3(%a6),%d1       # fetch precision
11604        lsr.b           &0x6,%d1                # shift to lo bits
11605        mov.l           (%sp)+,%d0              # load S.F.
11606        cmp.l           %d0,(tbl_fmul_ovfl.w,%pc,%d1.w*4) # would result ovfl?
11607        beq.w           fmul_may_ovfl           # result may rnd to overflow
11608        blt.w           fmul_ovfl               # result will overflow
11609
11610        cmp.l           %d0,(tbl_fmul_unfl.w,%pc,%d1.w*4) # would result unfl?
11611        beq.w           fmul_may_unfl           # result may rnd to no unfl
11612        bgt.w           fmul_unfl               # result will underflow
11613
11614#
11615# NORMAL:
11616# - the result of the multiply operation will neither overflow nor underflow.
11617# - do the multiply to the proper precision and rounding mode.
11618# - scale the result exponent using the scale factor. if both operands were
11619# normalized then we really don't need to go through this scaling. but for now,
11620# this will do.
11621#
11622fmul_normal:
11623        fmovm.x         FP_SCR1(%a6),&0x80      # load dst operand
11624
11625        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
11626        fmov.l          &0x0,%fpsr              # clear FPSR
11627
11628        fmul.x          FP_SCR0(%a6),%fp0       # execute multiply
11629
11630        fmov.l          %fpsr,%d1               # save status
11631        fmov.l          &0x0,%fpcr              # clear FPCR
11632
11633        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
11634
11635fmul_normal_exit:
11636        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
11637        mov.l           %d2,-(%sp)              # save d2
11638        mov.w           FP_SCR0_EX(%a6),%d1     # load {sgn,exp}
11639        mov.l           %d1,%d2                 # make a copy
11640        andi.l          &0x7fff,%d1             # strip sign
11641        andi.w          &0x8000,%d2             # keep old sign
11642        sub.l           %d0,%d1                 # add scale factor
11643        or.w            %d2,%d1                 # concat old sign,new exp
11644        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
11645        mov.l           (%sp)+,%d2              # restore d2
11646        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
11647        rts
11648
11649#
11650# OVERFLOW:
11651# - the result of the multiply operation is an overflow.
11652# - do the multiply to the proper precision and rounding mode in order to
11653# set the inexact bits.
11654# - calculate the default result and return it in fp0.
11655# - if overflow or inexact is enabled, we need a multiply result rounded to
11656# extended precision. if the original operation was extended, then we have this
11657# result. if the original operation was single or double, we have to do another
11658# multiply using extended precision and the correct rounding mode. the result
11659# of this operation then has its exponent scaled by -0x6000 to create the
11660# exceptional operand.
11661#
11662fmul_ovfl:
11663        fmovm.x         FP_SCR1(%a6),&0x80      # load dst operand
11664
11665        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
11666        fmov.l          &0x0,%fpsr              # clear FPSR
11667
11668        fmul.x          FP_SCR0(%a6),%fp0       # execute multiply
11669
11670        fmov.l          %fpsr,%d1               # save status
11671        fmov.l          &0x0,%fpcr              # clear FPCR
11672
11673        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
11674
11675# save setting this until now because this is where fmul_may_ovfl may jump in
11676fmul_ovfl_tst:
11677        or.l            &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
11678
11679        mov.b           FPCR_ENABLE(%a6),%d1
11680        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
11681        bne.b           fmul_ovfl_ena           # yes
11682
11683# calculate the default result
11684fmul_ovfl_dis:
11685        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
11686        sne             %d1                     # set sign param accordingly
11687        mov.l           L_SCR3(%a6),%d0         # pass rnd prec,mode
11688        bsr.l           ovf_res                 # calculate default result
11689        or.b            %d0,FPSR_CC(%a6)        # set INF,N if applicable
11690        fmovm.x         (%a0),&0x80             # return default result in fp0
11691        rts
11692
11693#
11694# OVFL is enabled; Create EXOP:
11695# - if precision is extended, then we have the EXOP. simply bias the exponent
11696# with an extra -0x6000. if the precision is single or double, we need to
11697# calculate a result rounded to extended precision.
11698#
11699fmul_ovfl_ena:
11700        mov.l           L_SCR3(%a6),%d1
11701        andi.b          &0xc0,%d1               # test the rnd prec
11702        bne.b           fmul_ovfl_ena_sd        # it's sgl or dbl
11703
11704fmul_ovfl_ena_cont:
11705        fmovm.x         &0x80,FP_SCR0(%a6)      # move result to stack
11706
11707        mov.l           %d2,-(%sp)              # save d2
11708        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
11709        mov.w           %d1,%d2                 # make a copy
11710        andi.l          &0x7fff,%d1             # strip sign
11711        sub.l           %d0,%d1                 # add scale factor
11712        subi.l          &0x6000,%d1             # subtract bias
11713        andi.w          &0x7fff,%d1             # clear sign bit
11714        andi.w          &0x8000,%d2             # keep old sign
11715        or.w            %d2,%d1                 # concat old sign,new exp
11716        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
11717        mov.l           (%sp)+,%d2              # restore d2
11718        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
11719        bra.b           fmul_ovfl_dis
11720
11721fmul_ovfl_ena_sd:
11722        fmovm.x         FP_SCR1(%a6),&0x80      # load dst operand
11723
11724        mov.l           L_SCR3(%a6),%d1
11725        andi.b          &0x30,%d1               # keep rnd mode only
11726        fmov.l          %d1,%fpcr               # set FPCR
11727
11728        fmul.x          FP_SCR0(%a6),%fp0       # execute multiply
11729
11730        fmov.l          &0x0,%fpcr              # clear FPCR
11731        bra.b           fmul_ovfl_ena_cont
11732
11733#
11734# may OVERFLOW:
11735# - the result of the multiply operation MAY overflow.
11736# - do the multiply to the proper precision and rounding mode in order to
11737# set the inexact bits.
11738# - calculate the default result and return it in fp0.
11739#
11740fmul_may_ovfl:
11741        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
11742
11743        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
11744        fmov.l          &0x0,%fpsr              # clear FPSR
11745
11746        fmul.x          FP_SCR0(%a6),%fp0       # execute multiply
11747
11748        fmov.l          %fpsr,%d1               # save status
11749        fmov.l          &0x0,%fpcr              # clear FPCR
11750
11751        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
11752
11753        fabs.x          %fp0,%fp1               # make a copy of result
11754        fcmp.b          %fp1,&0x2               # is |result| >= 2.b?
11755        fbge.w          fmul_ovfl_tst           # yes; overflow has occurred
11756
11757# no, it didn't overflow; we have correct result
11758        bra.w           fmul_normal_exit
11759
11760#
11761# UNDERFLOW:
11762# - the result of the multiply operation is an underflow.
11763# - do the multiply to the proper precision and rounding mode in order to
11764# set the inexact bits.
11765# - calculate the default result and return it in fp0.
11766# - if overflow or inexact is enabled, we need a multiply result rounded to
11767# extended precision. if the original operation was extended, then we have this
11768# result. if the original operation was single or double, we have to do another
11769# multiply using extended precision and the correct rounding mode. the result
11770# of this operation then has its exponent scaled by -0x6000 to create the
11771# exceptional operand.
11772#
11773fmul_unfl:
11774        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
11775
11776# for fun, let's use only extended precision, round to zero. then, let
11777# the unf_res() routine figure out all the rest.
11778# will we get the correct answer.
11779        fmovm.x         FP_SCR1(%a6),&0x80      # load dst operand
11780
11781        fmov.l          &rz_mode*0x10,%fpcr     # set FPCR
11782        fmov.l          &0x0,%fpsr              # clear FPSR
11783
11784        fmul.x          FP_SCR0(%a6),%fp0       # execute multiply
11785
11786        fmov.l          %fpsr,%d1               # save status
11787        fmov.l          &0x0,%fpcr              # clear FPCR
11788
11789        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
11790
11791        mov.b           FPCR_ENABLE(%a6),%d1
11792        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
11793        bne.b           fmul_unfl_ena           # yes
11794
11795fmul_unfl_dis:
11796        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
11797
11798        lea             FP_SCR0(%a6),%a0        # pass: result addr
11799        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
11800        bsr.l           unf_res                 # calculate default result
11801        or.b            %d0,FPSR_CC(%a6)        # unf_res2 may have set 'Z'
11802        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
11803        rts
11804
11805#
11806# UNFL is enabled.
11807#
11808fmul_unfl_ena:
11809        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op
11810
11811        mov.l           L_SCR3(%a6),%d1
11812        andi.b          &0xc0,%d1               # is precision extended?
11813        bne.b           fmul_unfl_ena_sd        # no, sgl or dbl
11814
11815# if the rnd mode is anything but RZ, then we have to re-do the above
11816# multiplication because we used RZ for all.
11817        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
11818
11819fmul_unfl_ena_cont:
11820        fmov.l          &0x0,%fpsr              # clear FPSR
11821
11822        fmul.x          FP_SCR0(%a6),%fp1       # execute multiply
11823
11824        fmov.l          &0x0,%fpcr              # clear FPCR
11825
11826        fmovm.x         &0x40,FP_SCR0(%a6)      # save result to stack
11827        mov.l           %d2,-(%sp)              # save d2
11828        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
11829        mov.l           %d1,%d2                 # make a copy
11830        andi.l          &0x7fff,%d1             # strip sign
11831        andi.w          &0x8000,%d2             # keep old sign
11832        sub.l           %d0,%d1                 # add scale factor
11833        addi.l          &0x6000,%d1             # add bias
11834        andi.w          &0x7fff,%d1
11835        or.w            %d2,%d1                 # concat old sign,new exp
11836        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
11837        mov.l           (%sp)+,%d2              # restore d2
11838        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
11839        bra.w           fmul_unfl_dis
11840
11841fmul_unfl_ena_sd:
11842        mov.l           L_SCR3(%a6),%d1
11843        andi.b          &0x30,%d1               # use only rnd mode
11844        fmov.l          %d1,%fpcr               # set FPCR
11845
11846        bra.b           fmul_unfl_ena_cont
11847
11848# MAY UNDERFLOW:
11849# -use the correct rounding mode and precision. this code favors operations
11850# that do not underflow.
11851fmul_may_unfl:
11852        fmovm.x         FP_SCR1(%a6),&0x80      # load dst operand
11853
11854        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
11855        fmov.l          &0x0,%fpsr              # clear FPSR
11856
11857        fmul.x          FP_SCR0(%a6),%fp0       # execute multiply
11858
11859        fmov.l          %fpsr,%d1               # save status
11860        fmov.l          &0x0,%fpcr              # clear FPCR
11861
11862        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
11863
11864        fabs.x          %fp0,%fp1               # make a copy of result
11865        fcmp.b          %fp1,&0x2               # is |result| > 2.b?
11866        fbgt.w          fmul_normal_exit        # no; no underflow occurred
11867        fblt.w          fmul_unfl               # yes; underflow occurred
11868
11869#
11870# we still don't know if underflow occurred. result is ~ equal to 2. but,
11871# we don't know if the result was an underflow that rounded up to a 2 or
11872# a normalized number that rounded down to a 2. so, redo the entire operation
11873# using RZ as the rounding mode to see what the pre-rounded result is.
11874# this case should be relatively rare.
11875#
11876        fmovm.x         FP_SCR1(%a6),&0x40      # load dst operand
11877
11878        mov.l           L_SCR3(%a6),%d1
11879        andi.b          &0xc0,%d1               # keep rnd prec
11880        ori.b           &rz_mode*0x10,%d1       # insert RZ
11881
11882        fmov.l          %d1,%fpcr               # set FPCR
11883        fmov.l          &0x0,%fpsr              # clear FPSR
11884
11885        fmul.x          FP_SCR0(%a6),%fp1       # execute multiply
11886
11887        fmov.l          &0x0,%fpcr              # clear FPCR
11888        fabs.x          %fp1                    # make absolute value
11889        fcmp.b          %fp1,&0x2               # is |result| < 2.b?
11890        fbge.w          fmul_normal_exit        # no; no underflow occurred
11891        bra.w           fmul_unfl               # yes, underflow occurred
11892
11893################################################################################
11894
11895#
11896# Multiply: inputs are not both normalized; what are they?
11897#
11898fmul_not_norm:
11899        mov.w           (tbl_fmul_op.b,%pc,%d1.w*2),%d1
11900        jmp             (tbl_fmul_op.b,%pc,%d1.w)
11901
11902        swbeg           &48
11903tbl_fmul_op:
11904        short           fmul_norm       - tbl_fmul_op # NORM x NORM
11905        short           fmul_zero       - tbl_fmul_op # NORM x ZERO
11906        short           fmul_inf_src    - tbl_fmul_op # NORM x INF
11907        short           fmul_res_qnan   - tbl_fmul_op # NORM x QNAN
11908        short           fmul_norm       - tbl_fmul_op # NORM x DENORM
11909        short           fmul_res_snan   - tbl_fmul_op # NORM x SNAN
11910        short           tbl_fmul_op     - tbl_fmul_op #
11911        short           tbl_fmul_op     - tbl_fmul_op #
11912
11913        short           fmul_zero       - tbl_fmul_op # ZERO x NORM
11914        short           fmul_zero       - tbl_fmul_op # ZERO x ZERO
11915        short           fmul_res_operr  - tbl_fmul_op # ZERO x INF
11916        short           fmul_res_qnan   - tbl_fmul_op # ZERO x QNAN
11917        short           fmul_zero       - tbl_fmul_op # ZERO x DENORM
11918        short           fmul_res_snan   - tbl_fmul_op # ZERO x SNAN
11919        short           tbl_fmul_op     - tbl_fmul_op #
11920        short           tbl_fmul_op     - tbl_fmul_op #
11921
11922        short           fmul_inf_dst    - tbl_fmul_op # INF x NORM
11923        short           fmul_res_operr  - tbl_fmul_op # INF x ZERO
11924        short           fmul_inf_dst    - tbl_fmul_op # INF x INF
11925        short           fmul_res_qnan   - tbl_fmul_op # INF x QNAN
11926        short           fmul_inf_dst    - tbl_fmul_op # INF x DENORM
11927        short           fmul_res_snan   - tbl_fmul_op # INF x SNAN
11928        short           tbl_fmul_op     - tbl_fmul_op #
11929        short           tbl_fmul_op     - tbl_fmul_op #
11930
11931        short           fmul_res_qnan   - tbl_fmul_op # QNAN x NORM
11932        short           fmul_res_qnan   - tbl_fmul_op # QNAN x ZERO
11933        short           fmul_res_qnan   - tbl_fmul_op # QNAN x INF
11934        short           fmul_res_qnan   - tbl_fmul_op # QNAN x QNAN
11935        short           fmul_res_qnan   - tbl_fmul_op # QNAN x DENORM
11936        short           fmul_res_snan   - tbl_fmul_op # QNAN x SNAN
11937        short           tbl_fmul_op     - tbl_fmul_op #
11938        short           tbl_fmul_op     - tbl_fmul_op #
11939
11940        short           fmul_norm       - tbl_fmul_op # NORM x NORM
11941        short           fmul_zero       - tbl_fmul_op # NORM x ZERO
11942        short           fmul_inf_src    - tbl_fmul_op # NORM x INF
11943        short           fmul_res_qnan   - tbl_fmul_op # NORM x QNAN
11944        short           fmul_norm       - tbl_fmul_op # NORM x DENORM
11945        short           fmul_res_snan   - tbl_fmul_op # NORM x SNAN
11946        short           tbl_fmul_op     - tbl_fmul_op #
11947        short           tbl_fmul_op     - tbl_fmul_op #
11948
11949        short           fmul_res_snan   - tbl_fmul_op # SNAN x NORM
11950        short           fmul_res_snan   - tbl_fmul_op # SNAN x ZERO
11951        short           fmul_res_snan   - tbl_fmul_op # SNAN x INF
11952        short           fmul_res_snan   - tbl_fmul_op # SNAN x QNAN
11953        short           fmul_res_snan   - tbl_fmul_op # SNAN x DENORM
11954        short           fmul_res_snan   - tbl_fmul_op # SNAN x SNAN
11955        short           tbl_fmul_op     - tbl_fmul_op #
11956        short           tbl_fmul_op     - tbl_fmul_op #
11957
11958fmul_res_operr:
11959        bra.l           res_operr
11960fmul_res_snan:
11961        bra.l           res_snan
11962fmul_res_qnan:
11963        bra.l           res_qnan
11964
11965#
11966# Multiply: (Zero x Zero) || (Zero x norm) || (Zero x denorm)
11967#
11968        global          fmul_zero               # global for fsglmul
11969fmul_zero:
11970        mov.b           SRC_EX(%a0),%d0         # exclusive or the signs
11971        mov.b           DST_EX(%a1),%d1
11972        eor.b           %d0,%d1
11973        bpl.b           fmul_zero_p             # result ZERO is pos.
11974fmul_zero_n:
11975        fmov.s          &0x80000000,%fp0        # load -ZERO
11976        mov.b           &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/N
11977        rts
11978fmul_zero_p:
11979        fmov.s          &0x00000000,%fp0        # load +ZERO
11980        mov.b           &z_bmask,FPSR_CC(%a6)   # set Z
11981        rts
11982
11983#
11984# Multiply: (inf x inf) || (inf x norm) || (inf x denorm)
11985#
11986# Note: The j-bit for an infinity is a don't-care. However, to be
11987# strictly compatible w/ the 68881/882, we make sure to return an
11988# INF w/ the j-bit set if the input INF j-bit was set. Destination
11989# INFs take priority.
11990#
11991        global          fmul_inf_dst            # global for fsglmul
11992fmul_inf_dst:
11993        fmovm.x         DST(%a1),&0x80          # return INF result in fp0
11994        mov.b           SRC_EX(%a0),%d0         # exclusive or the signs
11995        mov.b           DST_EX(%a1),%d1
11996        eor.b           %d0,%d1
11997        bpl.b           fmul_inf_dst_p          # result INF is pos.
11998fmul_inf_dst_n:
11999        fabs.x          %fp0                    # clear result sign
12000        fneg.x          %fp0                    # set result sign
12001        mov.b           &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/N
12002        rts
12003fmul_inf_dst_p:
12004        fabs.x          %fp0                    # clear result sign
12005        mov.b           &inf_bmask,FPSR_CC(%a6) # set INF
12006        rts
12007
12008        global          fmul_inf_src            # global for fsglmul
12009fmul_inf_src:
12010        fmovm.x         SRC(%a0),&0x80          # return INF result in fp0
12011        mov.b           SRC_EX(%a0),%d0         # exclusive or the signs
12012        mov.b           DST_EX(%a1),%d1
12013        eor.b           %d0,%d1
12014        bpl.b           fmul_inf_dst_p          # result INF is pos.
12015        bra.b           fmul_inf_dst_n
12016
12017#########################################################################
12018# XDEF **************************************************************** #
12019#       fin(): emulates the fmove instruction                           #
12020#       fsin(): emulates the fsmove instruction                         #
12021#       fdin(): emulates the fdmove instruction                         #
12022#                                                                       #
12023# XREF **************************************************************** #
12024#       norm() - normalize mantissa for EXOP on denorm                  #
12025#       scale_to_zero_src() - scale src exponent to zero                #
12026#       ovf_res() - return default overflow result                      #
12027#       unf_res() - return default underflow result                     #
12028#       res_qnan_1op() - return QNAN result                             #
12029#       res_snan_1op() - return SNAN result                             #
12030#                                                                       #
12031# INPUT *************************************************************** #
12032#       a0 = pointer to extended precision source operand               #
12033#       d0 = round prec/mode                                            #
12034#                                                                       #
12035# OUTPUT ************************************************************** #
12036#       fp0 = result                                                    #
12037#       fp1 = EXOP (if exception occurred)                              #
12038#                                                                       #
12039# ALGORITHM *********************************************************** #
12040#       Handle NANs, infinities, and zeroes as special cases. Divide    #
12041# norms into extended, single, and double precision.                    #
12042#       Norms can be emulated w/ a regular fmove instruction. For       #
12043# sgl/dbl, must scale exponent and perform an "fmove". Check to see     #
12044# if the result would have overflowed/underflowed. If so, use unf_res() #
12045# or ovf_res() to return the default result. Also return EXOP if        #
12046# exception is enabled. If no exception, return the default result.     #
12047#       Unnorms don't pass through here.                                #
12048#                                                                       #
12049#########################################################################
12050
12051        global          fsin
12052fsin:
12053        andi.b          &0x30,%d0               # clear rnd prec
12054        ori.b           &s_mode*0x10,%d0        # insert sgl precision
12055        bra.b           fin
12056
12057        global          fdin
12058fdin:
12059        andi.b          &0x30,%d0               # clear rnd prec
12060        ori.b           &d_mode*0x10,%d0        # insert dbl precision
12061
12062        global          fin
12063fin:
12064        mov.l           %d0,L_SCR3(%a6)         # store rnd info
12065
12066        mov.b           STAG(%a6),%d1           # fetch src optype tag
12067        bne.w           fin_not_norm            # optimize on non-norm input
12068
12069#
12070# FP MOVE IN: NORMs and DENORMs ONLY!
12071#
12072fin_norm:
12073        andi.b          &0xc0,%d0               # is precision extended?
12074        bne.w           fin_not_ext             # no, so go handle dbl or sgl
12075
12076#
12077# precision selected is extended. so...we cannot get an underflow
12078# or overflow because of rounding to the correct precision. so...
12079# skip the scaling and unscaling...
12080#
12081        tst.b           SRC_EX(%a0)             # is the operand negative?
12082        bpl.b           fin_norm_done           # no
12083        bset            &neg_bit,FPSR_CC(%a6)   # yes, so set 'N' ccode bit
12084fin_norm_done:
12085        fmovm.x         SRC(%a0),&0x80          # return result in fp0
12086        rts
12087
12088#
12089# for an extended precision DENORM, the UNFL exception bit is set
12090# the accrued bit is NOT set in this instance(no inexactness!)
12091#
12092fin_denorm:
12093        andi.b          &0xc0,%d0               # is precision extended?
12094        bne.w           fin_not_ext             # no, so go handle dbl or sgl
12095
12096        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
12097        tst.b           SRC_EX(%a0)             # is the operand negative?
12098        bpl.b           fin_denorm_done         # no
12099        bset            &neg_bit,FPSR_CC(%a6)   # yes, so set 'N' ccode bit
12100fin_denorm_done:
12101        fmovm.x         SRC(%a0),&0x80          # return result in fp0
12102        btst            &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled?
12103        bne.b           fin_denorm_unfl_ena     # yes
12104        rts
12105
12106#
12107# the input is an extended DENORM and underflow is enabled in the FPCR.
12108# normalize the mantissa and add the bias of 0x6000 to the resulting negative
12109# exponent and insert back into the operand.
12110#
12111fin_denorm_unfl_ena:
12112        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
12113        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
12114        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
12115        lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
12116        bsr.l           norm                    # normalize result
12117        neg.w           %d0                     # new exponent = -(shft val)
12118        addi.w          &0x6000,%d0             # add new bias to exponent
12119        mov.w           FP_SCR0_EX(%a6),%d1     # fetch old sign,exp
12120        andi.w          &0x8000,%d1             # keep old sign
12121        andi.w          &0x7fff,%d0             # clear sign position
12122        or.w            %d1,%d0                 # concat new exo,old sign
12123        mov.w           %d0,FP_SCR0_EX(%a6)     # insert new exponent
12124        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
12125        rts
12126
12127#
12128# operand is to be rounded to single or double precision
12129#
12130fin_not_ext:
12131        cmpi.b          %d0,&s_mode*0x10        # separate sgl/dbl prec
12132        bne.b           fin_dbl
12133
12134#
12135# operand is to be rounded to single precision
12136#
12137fin_sgl:
12138        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
12139        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
12140        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
12141        bsr.l           scale_to_zero_src       # calculate scale factor
12142
12143        cmpi.l          %d0,&0x3fff-0x3f80      # will move in underflow?
12144        bge.w           fin_sd_unfl             # yes; go handle underflow
12145        cmpi.l          %d0,&0x3fff-0x407e      # will move in overflow?
12146        beq.w           fin_sd_may_ovfl         # maybe; go check
12147        blt.w           fin_sd_ovfl             # yes; go handle overflow
12148
12149#
12150# operand will NOT overflow or underflow when moved into the fp reg file
12151#
12152fin_sd_normal:
12153        fmov.l          &0x0,%fpsr              # clear FPSR
12154        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
12155
12156        fmov.x          FP_SCR0(%a6),%fp0       # perform move
12157
12158        fmov.l          %fpsr,%d1               # save FPSR
12159        fmov.l          &0x0,%fpcr              # clear FPCR
12160
12161        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
12162
12163fin_sd_normal_exit:
12164        mov.l           %d2,-(%sp)              # save d2
12165        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
12166        mov.w           FP_SCR0_EX(%a6),%d1     # load {sgn,exp}
12167        mov.w           %d1,%d2                 # make a copy
12168        andi.l          &0x7fff,%d1             # strip sign
12169        sub.l           %d0,%d1                 # add scale factor
12170        andi.w          &0x8000,%d2             # keep old sign
12171        or.w            %d1,%d2                 # concat old sign,new exponent
12172        mov.w           %d2,FP_SCR0_EX(%a6)     # insert new exponent
12173        mov.l           (%sp)+,%d2              # restore d2
12174        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
12175        rts
12176
12177#
12178# operand is to be rounded to double precision
12179#
12180fin_dbl:
12181        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
12182        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
12183        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
12184        bsr.l           scale_to_zero_src       # calculate scale factor
12185
12186        cmpi.l          %d0,&0x3fff-0x3c00      # will move in underflow?
12187        bge.w           fin_sd_unfl             # yes; go handle underflow
12188        cmpi.l          %d0,&0x3fff-0x43fe      # will move in overflow?
12189        beq.w           fin_sd_may_ovfl         # maybe; go check
12190        blt.w           fin_sd_ovfl             # yes; go handle overflow
12191        bra.w           fin_sd_normal           # no; ho handle normalized op
12192
12193#
12194# operand WILL underflow when moved in to the fp register file
12195#
12196fin_sd_unfl:
12197        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
12198
12199        tst.b           FP_SCR0_EX(%a6)         # is operand negative?
12200        bpl.b           fin_sd_unfl_tst
12201        bset            &neg_bit,FPSR_CC(%a6)   # set 'N' ccode bit
12202
12203# if underflow or inexact is enabled, then go calculate the EXOP first.
12204fin_sd_unfl_tst:
12205        mov.b           FPCR_ENABLE(%a6),%d1
12206        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
12207        bne.b           fin_sd_unfl_ena         # yes
12208
12209fin_sd_unfl_dis:
12210        lea             FP_SCR0(%a6),%a0        # pass: result addr
12211        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
12212        bsr.l           unf_res                 # calculate default result
12213        or.b            %d0,FPSR_CC(%a6)        # unf_res may have set 'Z'
12214        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
12215        rts
12216
12217#
12218# operand will underflow AND underflow or inexact is enabled.
12219# Therefore, we must return the result rounded to extended precision.
12220#
12221fin_sd_unfl_ena:
12222        mov.l           FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
12223        mov.l           FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
12224        mov.w           FP_SCR0_EX(%a6),%d1     # load current exponent
12225
12226        mov.l           %d2,-(%sp)              # save d2
12227        mov.w           %d1,%d2                 # make a copy
12228        andi.l          &0x7fff,%d1             # strip sign
12229        sub.l           %d0,%d1                 # subtract scale factor
12230        andi.w          &0x8000,%d2             # extract old sign
12231        addi.l          &0x6000,%d1             # add new bias
12232        andi.w          &0x7fff,%d1
12233        or.w            %d1,%d2                 # concat old sign,new exp
12234        mov.w           %d2,FP_SCR1_EX(%a6)     # insert new exponent
12235        fmovm.x         FP_SCR1(%a6),&0x40      # return EXOP in fp1
12236        mov.l           (%sp)+,%d2              # restore d2
12237        bra.b           fin_sd_unfl_dis
12238
12239#
12240# operand WILL overflow.
12241#
12242fin_sd_ovfl:
12243        fmov.l          &0x0,%fpsr              # clear FPSR
12244        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
12245
12246        fmov.x          FP_SCR0(%a6),%fp0       # perform move
12247
12248        fmov.l          &0x0,%fpcr              # clear FPCR
12249        fmov.l          %fpsr,%d1               # save FPSR
12250
12251        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
12252
12253fin_sd_ovfl_tst:
12254        or.l            &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
12255
12256        mov.b           FPCR_ENABLE(%a6),%d1
12257        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
12258        bne.b           fin_sd_ovfl_ena         # yes
12259
12260#
12261# OVFL is not enabled; therefore, we must create the default result by
12262# calling ovf_res().
12263#
12264fin_sd_ovfl_dis:
12265        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
12266        sne             %d1                     # set sign param accordingly
12267        mov.l           L_SCR3(%a6),%d0         # pass: prec,mode
12268        bsr.l           ovf_res                 # calculate default result
12269        or.b            %d0,FPSR_CC(%a6)        # set INF,N if applicable
12270        fmovm.x         (%a0),&0x80             # return default result in fp0
12271        rts
12272
12273#
12274# OVFL is enabled.
12275# the INEX2 bit has already been updated by the round to the correct precision.
12276# now, round to extended(and don't alter the FPSR).
12277#
12278fin_sd_ovfl_ena:
12279        mov.l           %d2,-(%sp)              # save d2
12280        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
12281        mov.l           %d1,%d2                 # make a copy
12282        andi.l          &0x7fff,%d1             # strip sign
12283        andi.w          &0x8000,%d2             # keep old sign
12284        sub.l           %d0,%d1                 # add scale factor
12285        sub.l           &0x6000,%d1             # subtract bias
12286        andi.w          &0x7fff,%d1
12287        or.w            %d2,%d1
12288        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
12289        mov.l           (%sp)+,%d2              # restore d2
12290        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
12291        bra.b           fin_sd_ovfl_dis
12292
12293#
12294# the move in MAY overflow. so...
12295#
12296fin_sd_may_ovfl:
12297        fmov.l          &0x0,%fpsr              # clear FPSR
12298        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
12299
12300        fmov.x          FP_SCR0(%a6),%fp0       # perform the move
12301
12302        fmov.l          %fpsr,%d1               # save status
12303        fmov.l          &0x0,%fpcr              # clear FPCR
12304
12305        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
12306
12307        fabs.x          %fp0,%fp1               # make a copy of result
12308        fcmp.b          %fp1,&0x2               # is |result| >= 2.b?
12309        fbge.w          fin_sd_ovfl_tst         # yes; overflow has occurred
12310
12311# no, it didn't overflow; we have correct result
12312        bra.w           fin_sd_normal_exit
12313
12314##########################################################################
12315
12316#
12317# operand is not a NORM: check its optype and branch accordingly
12318#
12319fin_not_norm:
12320        cmpi.b          %d1,&DENORM             # weed out DENORM
12321        beq.w           fin_denorm
12322        cmpi.b          %d1,&SNAN               # weed out SNANs
12323        beq.l           res_snan_1op
12324        cmpi.b          %d1,&QNAN               # weed out QNANs
12325        beq.l           res_qnan_1op
12326
12327#
12328# do the fmove in; at this point, only possible ops are ZERO and INF.
12329# use fmov to determine ccodes.
12330# prec:mode should be zero at this point but it won't affect answer anyways.
12331#
12332        fmov.x          SRC(%a0),%fp0           # do fmove in
12333        fmov.l          %fpsr,%d0               # no exceptions possible
12334        rol.l           &0x8,%d0                # put ccodes in lo byte
12335        mov.b           %d0,FPSR_CC(%a6)        # insert correct ccodes
12336        rts
12337
12338#########################################################################
12339# XDEF **************************************************************** #
12340#       fdiv(): emulates the fdiv instruction                           #
12341#       fsdiv(): emulates the fsdiv instruction                         #
12342#       fddiv(): emulates the fddiv instruction                         #
12343#                                                                       #
12344# XREF **************************************************************** #
12345#       scale_to_zero_src() - scale src exponent to zero                #
12346#       scale_to_zero_dst() - scale dst exponent to zero                #
12347#       unf_res() - return default underflow result                     #
12348#       ovf_res() - return default overflow result                      #
12349#       res_qnan() - return QNAN result                                 #
12350#       res_snan() - return SNAN result                                 #
12351#                                                                       #
12352# INPUT *************************************************************** #
12353#       a0 = pointer to extended precision source operand               #
12354#       a1 = pointer to extended precision destination operand          #
12355#       d0  rnd prec,mode                                               #
12356#                                                                       #
12357# OUTPUT ************************************************************** #
12358#       fp0 = result                                                    #
12359#       fp1 = EXOP (if exception occurred)                              #
12360#                                                                       #
12361# ALGORITHM *********************************************************** #
12362#       Handle NANs, infinities, and zeroes as special cases. Divide    #
12363# norms/denorms into ext/sgl/dbl precision.                             #
12364#       For norms/denorms, scale the exponents such that a divide       #
12365# instruction won't cause an exception. Use the regular fdiv to         #
12366# compute a result. Check if the regular operands would have taken      #
12367# an exception. If so, return the default overflow/underflow result     #
12368# and return the EXOP if exceptions are enabled. Else, scale the        #
12369# result operand to the proper exponent.                                #
12370#                                                                       #
12371#########################################################################
12372
12373        align           0x10
12374tbl_fdiv_unfl:
12375        long            0x3fff - 0x0000         # ext_unfl
12376        long            0x3fff - 0x3f81         # sgl_unfl
12377        long            0x3fff - 0x3c01         # dbl_unfl
12378
12379tbl_fdiv_ovfl:
12380        long            0x3fff - 0x7ffe         # ext overflow exponent
12381        long            0x3fff - 0x407e         # sgl overflow exponent
12382        long            0x3fff - 0x43fe         # dbl overflow exponent
12383
12384        global          fsdiv
12385fsdiv:
12386        andi.b          &0x30,%d0               # clear rnd prec
12387        ori.b           &s_mode*0x10,%d0        # insert sgl prec
12388        bra.b           fdiv
12389
12390        global          fddiv
12391fddiv:
12392        andi.b          &0x30,%d0               # clear rnd prec
12393        ori.b           &d_mode*0x10,%d0        # insert dbl prec
12394
12395        global          fdiv
12396fdiv:
12397        mov.l           %d0,L_SCR3(%a6)         # store rnd info
12398
12399        clr.w           %d1
12400        mov.b           DTAG(%a6),%d1
12401        lsl.b           &0x3,%d1
12402        or.b            STAG(%a6),%d1           # combine src tags
12403
12404        bne.w           fdiv_not_norm           # optimize on non-norm input
12405
12406#
12407# DIVIDE: NORMs and DENORMs ONLY!
12408#
12409fdiv_norm:
12410        mov.w           DST_EX(%a1),FP_SCR1_EX(%a6)
12411        mov.l           DST_HI(%a1),FP_SCR1_HI(%a6)
12412        mov.l           DST_LO(%a1),FP_SCR1_LO(%a6)
12413
12414        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
12415        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
12416        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
12417
12418        bsr.l           scale_to_zero_src       # scale src exponent
12419        mov.l           %d0,-(%sp)              # save scale factor 1
12420
12421        bsr.l           scale_to_zero_dst       # scale dst exponent
12422
12423        neg.l           (%sp)                   # SCALE FACTOR = scale1 - scale2
12424        add.l           %d0,(%sp)
12425
12426        mov.w           2+L_SCR3(%a6),%d1       # fetch precision
12427        lsr.b           &0x6,%d1                # shift to lo bits
12428        mov.l           (%sp)+,%d0              # load S.F.
12429        cmp.l           %d0,(tbl_fdiv_ovfl.b,%pc,%d1.w*4) # will result overflow?
12430        ble.w           fdiv_may_ovfl           # result will overflow
12431
12432        cmp.l           %d0,(tbl_fdiv_unfl.w,%pc,%d1.w*4) # will result underflow?
12433        beq.w           fdiv_may_unfl           # maybe
12434        bgt.w           fdiv_unfl               # yes; go handle underflow
12435
12436fdiv_normal:
12437        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
12438
12439        fmov.l          L_SCR3(%a6),%fpcr       # save FPCR
12440        fmov.l          &0x0,%fpsr              # clear FPSR
12441
12442        fdiv.x          FP_SCR0(%a6),%fp0       # perform divide
12443
12444        fmov.l          %fpsr,%d1               # save FPSR
12445        fmov.l          &0x0,%fpcr              # clear FPCR
12446
12447        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
12448
12449fdiv_normal_exit:
12450        fmovm.x         &0x80,FP_SCR0(%a6)      # store result on stack
12451        mov.l           %d2,-(%sp)              # store d2
12452        mov.w           FP_SCR0_EX(%a6),%d1     # load {sgn,exp}
12453        mov.l           %d1,%d2                 # make a copy
12454        andi.l          &0x7fff,%d1             # strip sign
12455        andi.w          &0x8000,%d2             # keep old sign
12456        sub.l           %d0,%d1                 # add scale factor
12457        or.w            %d2,%d1                 # concat old sign,new exp
12458        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
12459        mov.l           (%sp)+,%d2              # restore d2
12460        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
12461        rts
12462
12463tbl_fdiv_ovfl2:
12464        long            0x7fff
12465        long            0x407f
12466        long            0x43ff
12467
12468fdiv_no_ovfl:
12469        mov.l           (%sp)+,%d0              # restore scale factor
12470        bra.b           fdiv_normal_exit
12471
12472fdiv_may_ovfl:
12473        mov.l           %d0,-(%sp)              # save scale factor
12474
12475        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
12476
12477        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
12478        fmov.l          &0x0,%fpsr              # set FPSR
12479
12480        fdiv.x          FP_SCR0(%a6),%fp0       # execute divide
12481
12482        fmov.l          %fpsr,%d0
12483        fmov.l          &0x0,%fpcr
12484
12485        or.l            %d0,USER_FPSR(%a6)      # save INEX,N
12486
12487        fmovm.x         &0x01,-(%sp)            # save result to stack
12488        mov.w           (%sp),%d0               # fetch new exponent
12489        add.l           &0xc,%sp                # clear result from stack
12490        andi.l          &0x7fff,%d0             # strip sign
12491        sub.l           (%sp),%d0               # add scale factor
12492        cmp.l           %d0,(tbl_fdiv_ovfl2.b,%pc,%d1.w*4)
12493        blt.b           fdiv_no_ovfl
12494        mov.l           (%sp)+,%d0
12495
12496fdiv_ovfl_tst:
12497        or.l            &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
12498
12499        mov.b           FPCR_ENABLE(%a6),%d1
12500        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
12501        bne.b           fdiv_ovfl_ena           # yes
12502
12503fdiv_ovfl_dis:
12504        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
12505        sne             %d1                     # set sign param accordingly
12506        mov.l           L_SCR3(%a6),%d0         # pass prec:rnd
12507        bsr.l           ovf_res                 # calculate default result
12508        or.b            %d0,FPSR_CC(%a6)        # set INF if applicable
12509        fmovm.x         (%a0),&0x80             # return default result in fp0
12510        rts
12511
12512fdiv_ovfl_ena:
12513        mov.l           L_SCR3(%a6),%d1
12514        andi.b          &0xc0,%d1               # is precision extended?
12515        bne.b           fdiv_ovfl_ena_sd        # no, do sgl or dbl
12516
12517fdiv_ovfl_ena_cont:
12518        fmovm.x         &0x80,FP_SCR0(%a6)      # move result to stack
12519
12520        mov.l           %d2,-(%sp)              # save d2
12521        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
12522        mov.w           %d1,%d2                 # make a copy
12523        andi.l          &0x7fff,%d1             # strip sign
12524        sub.l           %d0,%d1                 # add scale factor
12525        subi.l          &0x6000,%d1             # subtract bias
12526        andi.w          &0x7fff,%d1             # clear sign bit
12527        andi.w          &0x8000,%d2             # keep old sign
12528        or.w            %d2,%d1                 # concat old sign,new exp
12529        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
12530        mov.l           (%sp)+,%d2              # restore d2
12531        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
12532        bra.b           fdiv_ovfl_dis
12533
12534fdiv_ovfl_ena_sd:
12535        fmovm.x         FP_SCR1(%a6),&0x80      # load dst operand
12536
12537        mov.l           L_SCR3(%a6),%d1
12538        andi.b          &0x30,%d1               # keep rnd mode
12539        fmov.l          %d1,%fpcr               # set FPCR
12540
12541        fdiv.x          FP_SCR0(%a6),%fp0       # execute divide
12542
12543        fmov.l          &0x0,%fpcr              # clear FPCR
12544        bra.b           fdiv_ovfl_ena_cont
12545
12546fdiv_unfl:
12547        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
12548
12549        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
12550
12551        fmov.l          &rz_mode*0x10,%fpcr     # set FPCR
12552        fmov.l          &0x0,%fpsr              # clear FPSR
12553
12554        fdiv.x          FP_SCR0(%a6),%fp0       # execute divide
12555
12556        fmov.l          %fpsr,%d1               # save status
12557        fmov.l          &0x0,%fpcr              # clear FPCR
12558
12559        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
12560
12561        mov.b           FPCR_ENABLE(%a6),%d1
12562        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
12563        bne.b           fdiv_unfl_ena           # yes
12564
12565fdiv_unfl_dis:
12566        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
12567
12568        lea             FP_SCR0(%a6),%a0        # pass: result addr
12569        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
12570        bsr.l           unf_res                 # calculate default result
12571        or.b            %d0,FPSR_CC(%a6)        # 'Z' may have been set
12572        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
12573        rts
12574
12575#
12576# UNFL is enabled.
12577#
12578fdiv_unfl_ena:
12579        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op
12580
12581        mov.l           L_SCR3(%a6),%d1
12582        andi.b          &0xc0,%d1               # is precision extended?
12583        bne.b           fdiv_unfl_ena_sd        # no, sgl or dbl
12584
12585        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
12586
12587fdiv_unfl_ena_cont:
12588        fmov.l          &0x0,%fpsr              # clear FPSR
12589
12590        fdiv.x          FP_SCR0(%a6),%fp1       # execute divide
12591
12592        fmov.l          &0x0,%fpcr              # clear FPCR
12593
12594        fmovm.x         &0x40,FP_SCR0(%a6)      # save result to stack
12595        mov.l           %d2,-(%sp)              # save d2
12596        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
12597        mov.l           %d1,%d2                 # make a copy
12598        andi.l          &0x7fff,%d1             # strip sign
12599        andi.w          &0x8000,%d2             # keep old sign
12600        sub.l           %d0,%d1                 # add scale factoer
12601        addi.l          &0x6000,%d1             # add bias
12602        andi.w          &0x7fff,%d1
12603        or.w            %d2,%d1                 # concat old sign,new exp
12604        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exp
12605        mov.l           (%sp)+,%d2              # restore d2
12606        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
12607        bra.w           fdiv_unfl_dis
12608
12609fdiv_unfl_ena_sd:
12610        mov.l           L_SCR3(%a6),%d1
12611        andi.b          &0x30,%d1               # use only rnd mode
12612        fmov.l          %d1,%fpcr               # set FPCR
12613
12614        bra.b           fdiv_unfl_ena_cont
12615
12616#
12617# the divide operation MAY underflow:
12618#
12619fdiv_may_unfl:
12620        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
12621
12622        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
12623        fmov.l          &0x0,%fpsr              # clear FPSR
12624
12625        fdiv.x          FP_SCR0(%a6),%fp0       # execute divide
12626
12627        fmov.l          %fpsr,%d1               # save status
12628        fmov.l          &0x0,%fpcr              # clear FPCR
12629
12630        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
12631
12632        fabs.x          %fp0,%fp1               # make a copy of result
12633        fcmp.b          %fp1,&0x1               # is |result| > 1.b?
12634        fbgt.w          fdiv_normal_exit        # no; no underflow occurred
12635        fblt.w          fdiv_unfl               # yes; underflow occurred
12636
12637#
12638# we still don't know if underflow occurred. result is ~ equal to 1. but,
12639# we don't know if the result was an underflow that rounded up to a 1
12640# or a normalized number that rounded down to a 1. so, redo the entire
12641# operation using RZ as the rounding mode to see what the pre-rounded
12642# result is. this case should be relatively rare.
12643#
12644        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op into fp1
12645
12646        mov.l           L_SCR3(%a6),%d1
12647        andi.b          &0xc0,%d1               # keep rnd prec
12648        ori.b           &rz_mode*0x10,%d1       # insert RZ
12649
12650        fmov.l          %d1,%fpcr               # set FPCR
12651        fmov.l          &0x0,%fpsr              # clear FPSR
12652
12653        fdiv.x          FP_SCR0(%a6),%fp1       # execute divide
12654
12655        fmov.l          &0x0,%fpcr              # clear FPCR
12656        fabs.x          %fp1                    # make absolute value
12657        fcmp.b          %fp1,&0x1               # is |result| < 1.b?
12658        fbge.w          fdiv_normal_exit        # no; no underflow occurred
12659        bra.w           fdiv_unfl               # yes; underflow occurred
12660
12661############################################################################
12662
12663#
12664# Divide: inputs are not both normalized; what are they?
12665#
12666fdiv_not_norm:
12667        mov.w           (tbl_fdiv_op.b,%pc,%d1.w*2),%d1
12668        jmp             (tbl_fdiv_op.b,%pc,%d1.w*1)
12669
12670        swbeg           &48
12671tbl_fdiv_op:
12672        short           fdiv_norm       - tbl_fdiv_op # NORM / NORM
12673        short           fdiv_inf_load   - tbl_fdiv_op # NORM / ZERO
12674        short           fdiv_zero_load  - tbl_fdiv_op # NORM / INF
12675        short           fdiv_res_qnan   - tbl_fdiv_op # NORM / QNAN
12676        short           fdiv_norm       - tbl_fdiv_op # NORM / DENORM
12677        short           fdiv_res_snan   - tbl_fdiv_op # NORM / SNAN
12678        short           tbl_fdiv_op     - tbl_fdiv_op #
12679        short           tbl_fdiv_op     - tbl_fdiv_op #
12680
12681        short           fdiv_zero_load  - tbl_fdiv_op # ZERO / NORM
12682        short           fdiv_res_operr  - tbl_fdiv_op # ZERO / ZERO
12683        short           fdiv_zero_load  - tbl_fdiv_op # ZERO / INF
12684        short           fdiv_res_qnan   - tbl_fdiv_op # ZERO / QNAN
12685        short           fdiv_zero_load  - tbl_fdiv_op # ZERO / DENORM
12686        short           fdiv_res_snan   - tbl_fdiv_op # ZERO / SNAN
12687        short           tbl_fdiv_op     - tbl_fdiv_op #
12688        short           tbl_fdiv_op     - tbl_fdiv_op #
12689
12690        short           fdiv_inf_dst    - tbl_fdiv_op # INF / NORM
12691        short           fdiv_inf_dst    - tbl_fdiv_op # INF / ZERO
12692        short           fdiv_res_operr  - tbl_fdiv_op # INF / INF
12693        short           fdiv_res_qnan   - tbl_fdiv_op # INF / QNAN
12694        short           fdiv_inf_dst    - tbl_fdiv_op # INF / DENORM
12695        short           fdiv_res_snan   - tbl_fdiv_op # INF / SNAN
12696        short           tbl_fdiv_op     - tbl_fdiv_op #
12697        short           tbl_fdiv_op     - tbl_fdiv_op #
12698
12699        short           fdiv_res_qnan   - tbl_fdiv_op # QNAN / NORM
12700        short           fdiv_res_qnan   - tbl_fdiv_op # QNAN / ZERO
12701        short           fdiv_res_qnan   - tbl_fdiv_op # QNAN / INF
12702        short           fdiv_res_qnan   - tbl_fdiv_op # QNAN / QNAN
12703        short           fdiv_res_qnan   - tbl_fdiv_op # QNAN / DENORM
12704        short           fdiv_res_snan   - tbl_fdiv_op # QNAN / SNAN
12705        short           tbl_fdiv_op     - tbl_fdiv_op #
12706        short           tbl_fdiv_op     - tbl_fdiv_op #
12707
12708        short           fdiv_norm       - tbl_fdiv_op # DENORM / NORM
12709        short           fdiv_inf_load   - tbl_fdiv_op # DENORM / ZERO
12710        short           fdiv_zero_load  - tbl_fdiv_op # DENORM / INF
12711        short           fdiv_res_qnan   - tbl_fdiv_op # DENORM / QNAN
12712        short           fdiv_norm       - tbl_fdiv_op # DENORM / DENORM
12713        short           fdiv_res_snan   - tbl_fdiv_op # DENORM / SNAN
12714        short           tbl_fdiv_op     - tbl_fdiv_op #
12715        short           tbl_fdiv_op     - tbl_fdiv_op #
12716
12717        short           fdiv_res_snan   - tbl_fdiv_op # SNAN / NORM
12718        short           fdiv_res_snan   - tbl_fdiv_op # SNAN / ZERO
12719        short           fdiv_res_snan   - tbl_fdiv_op # SNAN / INF
12720        short           fdiv_res_snan   - tbl_fdiv_op # SNAN / QNAN
12721        short           fdiv_res_snan   - tbl_fdiv_op # SNAN / DENORM
12722        short           fdiv_res_snan   - tbl_fdiv_op # SNAN / SNAN
12723        short           tbl_fdiv_op     - tbl_fdiv_op #
12724        short           tbl_fdiv_op     - tbl_fdiv_op #
12725
12726fdiv_res_qnan:
12727        bra.l           res_qnan
12728fdiv_res_snan:
12729        bra.l           res_snan
12730fdiv_res_operr:
12731        bra.l           res_operr
12732
12733        global          fdiv_zero_load          # global for fsgldiv
12734fdiv_zero_load:
12735        mov.b           SRC_EX(%a0),%d0         # result sign is exclusive
12736        mov.b           DST_EX(%a1),%d1         # or of input signs.
12737        eor.b           %d0,%d1
12738        bpl.b           fdiv_zero_load_p        # result is positive
12739        fmov.s          &0x80000000,%fp0        # load a -ZERO
12740        mov.b           &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/N
12741        rts
12742fdiv_zero_load_p:
12743        fmov.s          &0x00000000,%fp0        # load a +ZERO
12744        mov.b           &z_bmask,FPSR_CC(%a6)   # set Z
12745        rts
12746
12747#
12748# The destination was In Range and the source was a ZERO. The result,
12749# Therefore, is an INF w/ the proper sign.
12750# So, determine the sign and return a new INF (w/ the j-bit cleared).
12751#
12752        global          fdiv_inf_load           # global for fsgldiv
12753fdiv_inf_load:
12754        ori.w           &dz_mask+adz_mask,2+USER_FPSR(%a6) # no; set DZ/ADZ
12755        mov.b           SRC_EX(%a0),%d0         # load both signs
12756        mov.b           DST_EX(%a1),%d1
12757        eor.b           %d0,%d1
12758        bpl.b           fdiv_inf_load_p         # result is positive
12759        fmov.s          &0xff800000,%fp0        # make result -INF
12760        mov.b           &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/N
12761        rts
12762fdiv_inf_load_p:
12763        fmov.s          &0x7f800000,%fp0        # make result +INF
12764        mov.b           &inf_bmask,FPSR_CC(%a6) # set INF
12765        rts
12766
12767#
12768# The destination was an INF w/ an In Range or ZERO source, the result is
12769# an INF w/ the proper sign.
12770# The 68881/882 returns the destination INF w/ the new sign(if the j-bit of the
12771# dst INF is set, then then j-bit of the result INF is also set).
12772#
12773        global          fdiv_inf_dst            # global for fsgldiv
12774fdiv_inf_dst:
12775        mov.b           DST_EX(%a1),%d0         # load both signs
12776        mov.b           SRC_EX(%a0),%d1
12777        eor.b           %d0,%d1
12778        bpl.b           fdiv_inf_dst_p          # result is positive
12779
12780        fmovm.x         DST(%a1),&0x80          # return result in fp0
12781        fabs.x          %fp0                    # clear sign bit
12782        fneg.x          %fp0                    # set sign bit
12783        mov.b           &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/NEG
12784        rts
12785
12786fdiv_inf_dst_p:
12787        fmovm.x         DST(%a1),&0x80          # return result in fp0
12788        fabs.x          %fp0                    # return positive INF
12789        mov.b           &inf_bmask,FPSR_CC(%a6) # set INF
12790        rts
12791
12792#########################################################################
12793# XDEF **************************************************************** #
12794#       fneg(): emulates the fneg instruction                           #
12795#       fsneg(): emulates the fsneg instruction                         #
12796#       fdneg(): emulates the fdneg instruction                         #
12797#                                                                       #
12798# XREF **************************************************************** #
12799#       norm() - normalize a denorm to provide EXOP                     #
12800#       scale_to_zero_src() - scale sgl/dbl source exponent             #
12801#       ovf_res() - return default overflow result                      #
12802#       unf_res() - return default underflow result                     #
12803#       res_qnan_1op() - return QNAN result                             #
12804#       res_snan_1op() - return SNAN result                             #
12805#                                                                       #
12806# INPUT *************************************************************** #
12807#       a0 = pointer to extended precision source operand               #
12808#       d0 = rnd prec,mode                                              #
12809#                                                                       #
12810# OUTPUT ************************************************************** #
12811#       fp0 = result                                                    #
12812#       fp1 = EXOP (if exception occurred)                              #
12813#                                                                       #
12814# ALGORITHM *********************************************************** #
12815#       Handle NANs, zeroes, and infinities as special cases. Separate  #
12816# norms/denorms into ext/sgl/dbl precisions. Extended precision can be  #
12817# emulated by simply setting sign bit. Sgl/dbl operands must be scaled  #
12818# and an actual fneg performed to see if overflow/underflow would have  #
12819# occurred. If so, return default underflow/overflow result. Else,      #
12820# scale the result exponent and return result. FPSR gets set based on   #
12821# the result value.                                                     #
12822#                                                                       #
12823#########################################################################
12824
12825        global          fsneg
12826fsneg:
12827        andi.b          &0x30,%d0               # clear rnd prec
12828        ori.b           &s_mode*0x10,%d0        # insert sgl precision
12829        bra.b           fneg
12830
12831        global          fdneg
12832fdneg:
12833        andi.b          &0x30,%d0               # clear rnd prec
12834        ori.b           &d_mode*0x10,%d0        # insert dbl prec
12835
12836        global          fneg
12837fneg:
12838        mov.l           %d0,L_SCR3(%a6)         # store rnd info
12839        mov.b           STAG(%a6),%d1
12840        bne.w           fneg_not_norm           # optimize on non-norm input
12841
12842#
12843# NEGATE SIGN : norms and denorms ONLY!
12844#
12845fneg_norm:
12846        andi.b          &0xc0,%d0               # is precision extended?
12847        bne.w           fneg_not_ext            # no; go handle sgl or dbl
12848
12849#
12850# precision selected is extended. so...we can not get an underflow
12851# or overflow because of rounding to the correct precision. so...
12852# skip the scaling and unscaling...
12853#
12854        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
12855        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
12856        mov.w           SRC_EX(%a0),%d0
12857        eori.w          &0x8000,%d0             # negate sign
12858        bpl.b           fneg_norm_load          # sign is positive
12859        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
12860fneg_norm_load:
12861        mov.w           %d0,FP_SCR0_EX(%a6)
12862        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
12863        rts
12864
12865#
12866# for an extended precision DENORM, the UNFL exception bit is set
12867# the accrued bit is NOT set in this instance(no inexactness!)
12868#
12869fneg_denorm:
12870        andi.b          &0xc0,%d0               # is precision extended?
12871        bne.b           fneg_not_ext            # no; go handle sgl or dbl
12872
12873        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
12874
12875        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
12876        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
12877        mov.w           SRC_EX(%a0),%d0
12878        eori.w          &0x8000,%d0             # negate sign
12879        bpl.b           fneg_denorm_done        # no
12880        mov.b           &neg_bmask,FPSR_CC(%a6) # yes, set 'N' ccode bit
12881fneg_denorm_done:
12882        mov.w           %d0,FP_SCR0_EX(%a6)
12883        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
12884
12885        btst            &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled?
12886        bne.b           fneg_ext_unfl_ena       # yes
12887        rts
12888
12889#
12890# the input is an extended DENORM and underflow is enabled in the FPCR.
12891# normalize the mantissa and add the bias of 0x6000 to the resulting negative
12892# exponent and insert back into the operand.
12893#
12894fneg_ext_unfl_ena:
12895        lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
12896        bsr.l           norm                    # normalize result
12897        neg.w           %d0                     # new exponent = -(shft val)
12898        addi.w          &0x6000,%d0             # add new bias to exponent
12899        mov.w           FP_SCR0_EX(%a6),%d1     # fetch old sign,exp
12900        andi.w          &0x8000,%d1             # keep old sign
12901        andi.w          &0x7fff,%d0             # clear sign position
12902        or.w            %d1,%d0                 # concat old sign, new exponent
12903        mov.w           %d0,FP_SCR0_EX(%a6)     # insert new exponent
12904        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
12905        rts
12906
12907#
12908# operand is either single or double
12909#
12910fneg_not_ext:
12911        cmpi.b          %d0,&s_mode*0x10        # separate sgl/dbl prec
12912        bne.b           fneg_dbl
12913
12914#
12915# operand is to be rounded to single precision
12916#
12917fneg_sgl:
12918        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
12919        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
12920        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
12921        bsr.l           scale_to_zero_src       # calculate scale factor
12922
12923        cmpi.l          %d0,&0x3fff-0x3f80      # will move in underflow?
12924        bge.w           fneg_sd_unfl            # yes; go handle underflow
12925        cmpi.l          %d0,&0x3fff-0x407e      # will move in overflow?
12926        beq.w           fneg_sd_may_ovfl        # maybe; go check
12927        blt.w           fneg_sd_ovfl            # yes; go handle overflow
12928
12929#
12930# operand will NOT overflow or underflow when moved in to the fp reg file
12931#
12932fneg_sd_normal:
12933        fmov.l          &0x0,%fpsr              # clear FPSR
12934        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
12935
12936        fneg.x          FP_SCR0(%a6),%fp0       # perform negation
12937
12938        fmov.l          %fpsr,%d1               # save FPSR
12939        fmov.l          &0x0,%fpcr              # clear FPCR
12940
12941        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
12942
12943fneg_sd_normal_exit:
12944        mov.l           %d2,-(%sp)              # save d2
12945        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
12946        mov.w           FP_SCR0_EX(%a6),%d1     # load sgn,exp
12947        mov.w           %d1,%d2                 # make a copy
12948        andi.l          &0x7fff,%d1             # strip sign
12949        sub.l           %d0,%d1                 # add scale factor
12950        andi.w          &0x8000,%d2             # keep old sign
12951        or.w            %d1,%d2                 # concat old sign,new exp
12952        mov.w           %d2,FP_SCR0_EX(%a6)     # insert new exponent
12953        mov.l           (%sp)+,%d2              # restore d2
12954        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
12955        rts
12956
12957#
12958# operand is to be rounded to double precision
12959#
12960fneg_dbl:
12961        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
12962        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
12963        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
12964        bsr.l           scale_to_zero_src       # calculate scale factor
12965
12966        cmpi.l          %d0,&0x3fff-0x3c00      # will move in underflow?
12967        bge.b           fneg_sd_unfl            # yes; go handle underflow
12968        cmpi.l          %d0,&0x3fff-0x43fe      # will move in overflow?
12969        beq.w           fneg_sd_may_ovfl        # maybe; go check
12970        blt.w           fneg_sd_ovfl            # yes; go handle overflow
12971        bra.w           fneg_sd_normal          # no; ho handle normalized op
12972
12973#
12974# operand WILL underflow when moved in to the fp register file
12975#
12976fneg_sd_unfl:
12977        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
12978
12979        eori.b          &0x80,FP_SCR0_EX(%a6)   # negate sign
12980        bpl.b           fneg_sd_unfl_tst
12981        bset            &neg_bit,FPSR_CC(%a6)   # set 'N' ccode bit
12982
12983# if underflow or inexact is enabled, go calculate EXOP first.
12984fneg_sd_unfl_tst:
12985        mov.b           FPCR_ENABLE(%a6),%d1
12986        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
12987        bne.b           fneg_sd_unfl_ena        # yes
12988
12989fneg_sd_unfl_dis:
12990        lea             FP_SCR0(%a6),%a0        # pass: result addr
12991        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
12992        bsr.l           unf_res                 # calculate default result
12993        or.b            %d0,FPSR_CC(%a6)        # unf_res may have set 'Z'
12994        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
12995        rts
12996
12997#
12998# operand will underflow AND underflow is enabled.
12999# Therefore, we must return the result rounded to extended precision.
13000#
13001fneg_sd_unfl_ena:
13002        mov.l           FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
13003        mov.l           FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
13004        mov.w           FP_SCR0_EX(%a6),%d1     # load current exponent
13005
13006        mov.l           %d2,-(%sp)              # save d2
13007        mov.l           %d1,%d2                 # make a copy
13008        andi.l          &0x7fff,%d1             # strip sign
13009        andi.w          &0x8000,%d2             # keep old sign
13010        sub.l           %d0,%d1                 # subtract scale factor
13011        addi.l          &0x6000,%d1             # add new bias
13012        andi.w          &0x7fff,%d1
13013        or.w            %d2,%d1                 # concat new sign,new exp
13014        mov.w           %d1,FP_SCR1_EX(%a6)     # insert new exp
13015        fmovm.x         FP_SCR1(%a6),&0x40      # return EXOP in fp1
13016        mov.l           (%sp)+,%d2              # restore d2
13017        bra.b           fneg_sd_unfl_dis
13018
13019#
13020# operand WILL overflow.
13021#
13022fneg_sd_ovfl:
13023        fmov.l          &0x0,%fpsr              # clear FPSR
13024        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
13025
13026        fneg.x          FP_SCR0(%a6),%fp0       # perform negation
13027
13028        fmov.l          &0x0,%fpcr              # clear FPCR
13029        fmov.l          %fpsr,%d1               # save FPSR
13030
13031        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
13032
13033fneg_sd_ovfl_tst:
13034        or.l            &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
13035
13036        mov.b           FPCR_ENABLE(%a6),%d1
13037        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
13038        bne.b           fneg_sd_ovfl_ena        # yes
13039
13040#
13041# OVFL is not enabled; therefore, we must create the default result by
13042# calling ovf_res().
13043#
13044fneg_sd_ovfl_dis:
13045        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
13046        sne             %d1                     # set sign param accordingly
13047        mov.l           L_SCR3(%a6),%d0         # pass: prec,mode
13048        bsr.l           ovf_res                 # calculate default result
13049        or.b            %d0,FPSR_CC(%a6)        # set INF,N if applicable
13050        fmovm.x         (%a0),&0x80             # return default result in fp0
13051        rts
13052
13053#
13054# OVFL is enabled.
13055# the INEX2 bit has already been updated by the round to the correct precision.
13056# now, round to extended(and don't alter the FPSR).
13057#
13058fneg_sd_ovfl_ena:
13059        mov.l           %d2,-(%sp)              # save d2
13060        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
13061        mov.l           %d1,%d2                 # make a copy
13062        andi.l          &0x7fff,%d1             # strip sign
13063        andi.w          &0x8000,%d2             # keep old sign
13064        sub.l           %d0,%d1                 # add scale factor
13065        subi.l          &0x6000,%d1             # subtract bias
13066        andi.w          &0x7fff,%d1
13067        or.w            %d2,%d1                 # concat sign,exp
13068        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
13069        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
13070        mov.l           (%sp)+,%d2              # restore d2
13071        bra.b           fneg_sd_ovfl_dis
13072
13073#
13074# the move in MAY underflow. so...
13075#
13076fneg_sd_may_ovfl:
13077        fmov.l          &0x0,%fpsr              # clear FPSR
13078        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
13079
13080        fneg.x          FP_SCR0(%a6),%fp0       # perform negation
13081
13082        fmov.l          %fpsr,%d1               # save status
13083        fmov.l          &0x0,%fpcr              # clear FPCR
13084
13085        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
13086
13087        fabs.x          %fp0,%fp1               # make a copy of result
13088        fcmp.b          %fp1,&0x2               # is |result| >= 2.b?
13089        fbge.w          fneg_sd_ovfl_tst        # yes; overflow has occurred
13090
13091# no, it didn't overflow; we have correct result
13092        bra.w           fneg_sd_normal_exit
13093
13094##########################################################################
13095
13096#
13097# input is not normalized; what is it?
13098#
13099fneg_not_norm:
13100        cmpi.b          %d1,&DENORM             # weed out DENORM
13101        beq.w           fneg_denorm
13102        cmpi.b          %d1,&SNAN               # weed out SNAN
13103        beq.l           res_snan_1op
13104        cmpi.b          %d1,&QNAN               # weed out QNAN
13105        beq.l           res_qnan_1op
13106
13107#
13108# do the fneg; at this point, only possible ops are ZERO and INF.
13109# use fneg to determine ccodes.
13110# prec:mode should be zero at this point but it won't affect answer anyways.
13111#
13112        fneg.x          SRC_EX(%a0),%fp0        # do fneg
13113        fmov.l          %fpsr,%d0
13114        rol.l           &0x8,%d0                # put ccodes in lo byte
13115        mov.b           %d0,FPSR_CC(%a6)        # insert correct ccodes
13116        rts
13117
13118#########################################################################
13119# XDEF **************************************************************** #
13120#       ftst(): emulates the ftest instruction                          #
13121#                                                                       #
13122# XREF **************************************************************** #
13123#       res{s,q}nan_1op() - set NAN result for monadic instruction      #
13124#                                                                       #
13125# INPUT *************************************************************** #
13126#       a0 = pointer to extended precision source operand               #
13127#                                                                       #
13128# OUTPUT ************************************************************** #
13129#       none                                                            #
13130#                                                                       #
13131# ALGORITHM *********************************************************** #
13132#       Check the source operand tag (STAG) and set the FPCR according  #
13133# to the operand type and sign.                                         #
13134#                                                                       #
13135#########################################################################
13136
13137        global          ftst
13138ftst:
13139        mov.b           STAG(%a6),%d1
13140        bne.b           ftst_not_norm           # optimize on non-norm input
13141
13142#
13143# Norm:
13144#
13145ftst_norm:
13146        tst.b           SRC_EX(%a0)             # is operand negative?
13147        bmi.b           ftst_norm_m             # yes
13148        rts
13149ftst_norm_m:
13150        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
13151        rts
13152
13153#
13154# input is not normalized; what is it?
13155#
13156ftst_not_norm:
13157        cmpi.b          %d1,&ZERO               # weed out ZERO
13158        beq.b           ftst_zero
13159        cmpi.b          %d1,&INF                # weed out INF
13160        beq.b           ftst_inf
13161        cmpi.b          %d1,&SNAN               # weed out SNAN
13162        beq.l           res_snan_1op
13163        cmpi.b          %d1,&QNAN               # weed out QNAN
13164        beq.l           res_qnan_1op
13165
13166#
13167# Denorm:
13168#
13169ftst_denorm:
13170        tst.b           SRC_EX(%a0)             # is operand negative?
13171        bmi.b           ftst_denorm_m           # yes
13172        rts
13173ftst_denorm_m:
13174        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
13175        rts
13176
13177#
13178# Infinity:
13179#
13180ftst_inf:
13181        tst.b           SRC_EX(%a0)             # is operand negative?
13182        bmi.b           ftst_inf_m              # yes
13183ftst_inf_p:
13184        mov.b           &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
13185        rts
13186ftst_inf_m:
13187        mov.b           &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'I','N' ccode bits
13188        rts
13189
13190#
13191# Zero:
13192#
13193ftst_zero:
13194        tst.b           SRC_EX(%a0)             # is operand negative?
13195        bmi.b           ftst_zero_m             # yes
13196ftst_zero_p:
13197        mov.b           &z_bmask,FPSR_CC(%a6)   # set 'N' ccode bit
13198        rts
13199ftst_zero_m:
13200        mov.b           &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
13201        rts
13202
13203#########################################################################
13204# XDEF **************************************************************** #
13205#       fint(): emulates the fint instruction                           #
13206#                                                                       #
13207# XREF **************************************************************** #
13208#       res_{s,q}nan_1op() - set NAN result for monadic operation       #
13209#                                                                       #
13210# INPUT *************************************************************** #
13211#       a0 = pointer to extended precision source operand               #
13212#       d0 = round precision/mode                                       #
13213#                                                                       #
13214# OUTPUT ************************************************************** #
13215#       fp0 = result                                                    #
13216#                                                                       #
13217# ALGORITHM *********************************************************** #
13218#       Separate according to operand type. Unnorms don't pass through  #
13219# here. For norms, load the rounding mode/prec, execute a "fint", then  #
13220# store the resulting FPSR bits.                                        #
13221#       For denorms, force the j-bit to a one and do the same as for    #
13222# norms. Denorms are so low that the answer will either be a zero or a  #
13223# one.                                                                  #
13224#       For zeroes/infs/NANs, return the same while setting the FPSR    #
13225# as appropriate.                                                       #
13226#                                                                       #
13227#########################################################################
13228
13229        global          fint
13230fint:
13231        mov.b           STAG(%a6),%d1
13232        bne.b           fint_not_norm           # optimize on non-norm input
13233
13234#
13235# Norm:
13236#
13237fint_norm:
13238        andi.b          &0x30,%d0               # set prec = ext
13239
13240        fmov.l          %d0,%fpcr               # set FPCR
13241        fmov.l          &0x0,%fpsr              # clear FPSR
13242
13243        fint.x          SRC(%a0),%fp0           # execute fint
13244
13245        fmov.l          &0x0,%fpcr              # clear FPCR
13246        fmov.l          %fpsr,%d0               # save FPSR
13247        or.l            %d0,USER_FPSR(%a6)      # set exception bits
13248
13249        rts
13250
13251#
13252# input is not normalized; what is it?
13253#
13254fint_not_norm:
13255        cmpi.b          %d1,&ZERO               # weed out ZERO
13256        beq.b           fint_zero
13257        cmpi.b          %d1,&INF                # weed out INF
13258        beq.b           fint_inf
13259        cmpi.b          %d1,&DENORM             # weed out DENORM
13260        beq.b           fint_denorm
13261        cmpi.b          %d1,&SNAN               # weed out SNAN
13262        beq.l           res_snan_1op
13263        bra.l           res_qnan_1op            # weed out QNAN
13264
13265#
13266# Denorm:
13267#
13268# for DENORMs, the result will be either (+/-)ZERO or (+/-)1.
13269# also, the INEX2 and AINEX exception bits will be set.
13270# so, we could either set these manually or force the DENORM
13271# to a very small NORM and ship it to the NORM routine.
13272# I do the latter.
13273#
13274fint_denorm:
13275        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6) # copy sign, zero exp
13276        mov.b           &0x80,FP_SCR0_HI(%a6)   # force DENORM ==> small NORM
13277        lea             FP_SCR0(%a6),%a0
13278        bra.b           fint_norm
13279
13280#
13281# Zero:
13282#
13283fint_zero:
13284        tst.b           SRC_EX(%a0)             # is ZERO negative?
13285        bmi.b           fint_zero_m             # yes
13286fint_zero_p:
13287        fmov.s          &0x00000000,%fp0        # return +ZERO in fp0
13288        mov.b           &z_bmask,FPSR_CC(%a6)   # set 'Z' ccode bit
13289        rts
13290fint_zero_m:
13291        fmov.s          &0x80000000,%fp0        # return -ZERO in fp0
13292        mov.b           &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
13293        rts
13294
13295#
13296# Infinity:
13297#
13298fint_inf:
13299        fmovm.x         SRC(%a0),&0x80          # return result in fp0
13300        tst.b           SRC_EX(%a0)             # is INF negative?
13301        bmi.b           fint_inf_m              # yes
13302fint_inf_p:
13303        mov.b           &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
13304        rts
13305fint_inf_m:
13306        mov.b           &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits
13307        rts
13308
13309#########################################################################
13310# XDEF **************************************************************** #
13311#       fintrz(): emulates the fintrz instruction                       #
13312#                                                                       #
13313# XREF **************************************************************** #
13314#       res_{s,q}nan_1op() - set NAN result for monadic operation       #
13315#                                                                       #
13316# INPUT *************************************************************** #
13317#       a0 = pointer to extended precision source operand               #
13318#       d0 = round precision/mode                                       #
13319#                                                                       #
13320# OUTPUT ************************************************************** #
13321#       fp0 = result                                                    #
13322#                                                                       #
13323# ALGORITHM *********************************************************** #
13324#       Separate according to operand type. Unnorms don't pass through  #
13325# here. For norms, load the rounding mode/prec, execute a "fintrz",     #
13326# then store the resulting FPSR bits.                                   #
13327#       For denorms, force the j-bit to a one and do the same as for    #
13328# norms. Denorms are so low that the answer will either be a zero or a  #
13329# one.                                                                  #
13330#       For zeroes/infs/NANs, return the same while setting the FPSR    #
13331# as appropriate.                                                       #
13332#                                                                       #
13333#########################################################################
13334
13335        global          fintrz
13336fintrz:
13337        mov.b           STAG(%a6),%d1
13338        bne.b           fintrz_not_norm         # optimize on non-norm input
13339
13340#
13341# Norm:
13342#
13343fintrz_norm:
13344        fmov.l          &0x0,%fpsr              # clear FPSR
13345
13346        fintrz.x        SRC(%a0),%fp0           # execute fintrz
13347
13348        fmov.l          %fpsr,%d0               # save FPSR
13349        or.l            %d0,USER_FPSR(%a6)      # set exception bits
13350
13351        rts
13352
13353#
13354# input is not normalized; what is it?
13355#
13356fintrz_not_norm:
13357        cmpi.b          %d1,&ZERO               # weed out ZERO
13358        beq.b           fintrz_zero
13359        cmpi.b          %d1,&INF                # weed out INF
13360        beq.b           fintrz_inf
13361        cmpi.b          %d1,&DENORM             # weed out DENORM
13362        beq.b           fintrz_denorm
13363        cmpi.b          %d1,&SNAN               # weed out SNAN
13364        beq.l           res_snan_1op
13365        bra.l           res_qnan_1op            # weed out QNAN
13366
13367#
13368# Denorm:
13369#
13370# for DENORMs, the result will be (+/-)ZERO.
13371# also, the INEX2 and AINEX exception bits will be set.
13372# so, we could either set these manually or force the DENORM
13373# to a very small NORM and ship it to the NORM routine.
13374# I do the latter.
13375#
13376fintrz_denorm:
13377        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6) # copy sign, zero exp
13378        mov.b           &0x80,FP_SCR0_HI(%a6)   # force DENORM ==> small NORM
13379        lea             FP_SCR0(%a6),%a0
13380        bra.b           fintrz_norm
13381
13382#
13383# Zero:
13384#
13385fintrz_zero:
13386        tst.b           SRC_EX(%a0)             # is ZERO negative?
13387        bmi.b           fintrz_zero_m           # yes
13388fintrz_zero_p:
13389        fmov.s          &0x00000000,%fp0        # return +ZERO in fp0
13390        mov.b           &z_bmask,FPSR_CC(%a6)   # set 'Z' ccode bit
13391        rts
13392fintrz_zero_m:
13393        fmov.s          &0x80000000,%fp0        # return -ZERO in fp0
13394        mov.b           &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
13395        rts
13396
13397#
13398# Infinity:
13399#
13400fintrz_inf:
13401        fmovm.x         SRC(%a0),&0x80          # return result in fp0
13402        tst.b           SRC_EX(%a0)             # is INF negative?
13403        bmi.b           fintrz_inf_m            # yes
13404fintrz_inf_p:
13405        mov.b           &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
13406        rts
13407fintrz_inf_m:
13408        mov.b           &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits
13409        rts
13410
13411#########################################################################
13412# XDEF **************************************************************** #
13413#       fabs():  emulates the fabs instruction                          #
13414#       fsabs(): emulates the fsabs instruction                         #
13415#       fdabs(): emulates the fdabs instruction                         #
13416#                                                                       #
13417# XREF **************************************************************** #
13418#       norm() - normalize denorm mantissa to provide EXOP              #
13419#       scale_to_zero_src() - make exponent. = 0; get scale factor      #
13420#       unf_res() - calculate underflow result                          #
13421#       ovf_res() - calculate overflow result                           #
13422#       res_{s,q}nan_1op() - set NAN result for monadic operation       #
13423#                                                                       #
13424# INPUT *************************************************************** #
13425#       a0 = pointer to extended precision source operand               #
13426#       d0 = rnd precision/mode                                         #
13427#                                                                       #
13428# OUTPUT ************************************************************** #
13429#       fp0 = result                                                    #
13430#       fp1 = EXOP (if exception occurred)                              #
13431#                                                                       #
13432# ALGORITHM *********************************************************** #
13433#       Handle NANs, infinities, and zeroes as special cases. Divide    #
13434# norms into extended, single, and double precision.                    #
13435#       Simply clear sign for extended precision norm. Ext prec denorm  #
13436# gets an EXOP created for it since it's an underflow.                  #
13437#       Double and single precision can overflow and underflow. First,  #
13438# scale the operand such that the exponent is zero. Perform an "fabs"   #
13439# using the correct rnd mode/prec. Check to see if the original         #
13440# exponent would take an exception. If so, use unf_res() or ovf_res()   #
13441# to calculate the default result. Also, create the EXOP for the        #
13442# exceptional case. If no exception should occur, insert the correct    #
13443# result exponent and return.                                           #
13444#       Unnorms don't pass through here.                                #
13445#                                                                       #
13446#########################################################################
13447
13448        global          fsabs
13449fsabs:
13450        andi.b          &0x30,%d0               # clear rnd prec
13451        ori.b           &s_mode*0x10,%d0        # insert sgl precision
13452        bra.b           fabs
13453
13454        global          fdabs
13455fdabs:
13456        andi.b          &0x30,%d0               # clear rnd prec
13457        ori.b           &d_mode*0x10,%d0        # insert dbl precision
13458
13459        global          fabs
13460fabs:
13461        mov.l           %d0,L_SCR3(%a6)         # store rnd info
13462        mov.b           STAG(%a6),%d1
13463        bne.w           fabs_not_norm           # optimize on non-norm input
13464
13465#
13466# ABSOLUTE VALUE: norms and denorms ONLY!
13467#
13468fabs_norm:
13469        andi.b          &0xc0,%d0               # is precision extended?
13470        bne.b           fabs_not_ext            # no; go handle sgl or dbl
13471
13472#
13473# precision selected is extended. so...we can not get an underflow
13474# or overflow because of rounding to the correct precision. so...
13475# skip the scaling and unscaling...
13476#
13477        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
13478        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
13479        mov.w           SRC_EX(%a0),%d1
13480        bclr            &15,%d1                 # force absolute value
13481        mov.w           %d1,FP_SCR0_EX(%a6)     # insert exponent
13482        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
13483        rts
13484
13485#
13486# for an extended precision DENORM, the UNFL exception bit is set
13487# the accrued bit is NOT set in this instance(no inexactness!)
13488#
13489fabs_denorm:
13490        andi.b          &0xc0,%d0               # is precision extended?
13491        bne.b           fabs_not_ext            # no
13492
13493        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
13494
13495        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
13496        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
13497        mov.w           SRC_EX(%a0),%d0
13498        bclr            &15,%d0                 # clear sign
13499        mov.w           %d0,FP_SCR0_EX(%a6)     # insert exponent
13500
13501        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
13502
13503        btst            &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled?
13504        bne.b           fabs_ext_unfl_ena
13505        rts
13506
13507#
13508# the input is an extended DENORM and underflow is enabled in the FPCR.
13509# normalize the mantissa and add the bias of 0x6000 to the resulting negative
13510# exponent and insert back into the operand.
13511#
13512fabs_ext_unfl_ena:
13513        lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
13514        bsr.l           norm                    # normalize result
13515        neg.w           %d0                     # new exponent = -(shft val)
13516        addi.w          &0x6000,%d0             # add new bias to exponent
13517        mov.w           FP_SCR0_EX(%a6),%d1     # fetch old sign,exp
13518        andi.w          &0x8000,%d1             # keep old sign
13519        andi.w          &0x7fff,%d0             # clear sign position
13520        or.w            %d1,%d0                 # concat old sign, new exponent
13521        mov.w           %d0,FP_SCR0_EX(%a6)     # insert new exponent
13522        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
13523        rts
13524
13525#
13526# operand is either single or double
13527#
13528fabs_not_ext:
13529        cmpi.b          %d0,&s_mode*0x10        # separate sgl/dbl prec
13530        bne.b           fabs_dbl
13531
13532#
13533# operand is to be rounded to single precision
13534#
13535fabs_sgl:
13536        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
13537        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
13538        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
13539        bsr.l           scale_to_zero_src       # calculate scale factor
13540
13541        cmpi.l          %d0,&0x3fff-0x3f80      # will move in underflow?
13542        bge.w           fabs_sd_unfl            # yes; go handle underflow
13543        cmpi.l          %d0,&0x3fff-0x407e      # will move in overflow?
13544        beq.w           fabs_sd_may_ovfl        # maybe; go check
13545        blt.w           fabs_sd_ovfl            # yes; go handle overflow
13546
13547#
13548# operand will NOT overflow or underflow when moved in to the fp reg file
13549#
13550fabs_sd_normal:
13551        fmov.l          &0x0,%fpsr              # clear FPSR
13552        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
13553
13554        fabs.x          FP_SCR0(%a6),%fp0       # perform absolute
13555
13556        fmov.l          %fpsr,%d1               # save FPSR
13557        fmov.l          &0x0,%fpcr              # clear FPCR
13558
13559        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
13560
13561fabs_sd_normal_exit:
13562        mov.l           %d2,-(%sp)              # save d2
13563        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
13564        mov.w           FP_SCR0_EX(%a6),%d1     # load sgn,exp
13565        mov.l           %d1,%d2                 # make a copy
13566        andi.l          &0x7fff,%d1             # strip sign
13567        sub.l           %d0,%d1                 # add scale factor
13568        andi.w          &0x8000,%d2             # keep old sign
13569        or.w            %d1,%d2                 # concat old sign,new exp
13570        mov.w           %d2,FP_SCR0_EX(%a6)     # insert new exponent
13571        mov.l           (%sp)+,%d2              # restore d2
13572        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
13573        rts
13574
13575#
13576# operand is to be rounded to double precision
13577#
13578fabs_dbl:
13579        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
13580        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
13581        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
13582        bsr.l           scale_to_zero_src       # calculate scale factor
13583
13584        cmpi.l          %d0,&0x3fff-0x3c00      # will move in underflow?
13585        bge.b           fabs_sd_unfl            # yes; go handle underflow
13586        cmpi.l          %d0,&0x3fff-0x43fe      # will move in overflow?
13587        beq.w           fabs_sd_may_ovfl        # maybe; go check
13588        blt.w           fabs_sd_ovfl            # yes; go handle overflow
13589        bra.w           fabs_sd_normal          # no; ho handle normalized op
13590
13591#
13592# operand WILL underflow when moved in to the fp register file
13593#
13594fabs_sd_unfl:
13595        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
13596
13597        bclr            &0x7,FP_SCR0_EX(%a6)    # force absolute value
13598
13599# if underflow or inexact is enabled, go calculate EXOP first.
13600        mov.b           FPCR_ENABLE(%a6),%d1
13601        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
13602        bne.b           fabs_sd_unfl_ena        # yes
13603
13604fabs_sd_unfl_dis:
13605        lea             FP_SCR0(%a6),%a0        # pass: result addr
13606        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
13607        bsr.l           unf_res                 # calculate default result
13608        or.b            %d0,FPSR_CC(%a6)        # set possible 'Z' ccode
13609        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
13610        rts
13611
13612#
13613# operand will underflow AND underflow is enabled.
13614# Therefore, we must return the result rounded to extended precision.
13615#
13616fabs_sd_unfl_ena:
13617        mov.l           FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
13618        mov.l           FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
13619        mov.w           FP_SCR0_EX(%a6),%d1     # load current exponent
13620
13621        mov.l           %d2,-(%sp)              # save d2
13622        mov.l           %d1,%d2                 # make a copy
13623        andi.l          &0x7fff,%d1             # strip sign
13624        andi.w          &0x8000,%d2             # keep old sign
13625        sub.l           %d0,%d1                 # subtract scale factor
13626        addi.l          &0x6000,%d1             # add new bias
13627        andi.w          &0x7fff,%d1
13628        or.w            %d2,%d1                 # concat new sign,new exp
13629        mov.w           %d1,FP_SCR1_EX(%a6)     # insert new exp
13630        fmovm.x         FP_SCR1(%a6),&0x40      # return EXOP in fp1
13631        mov.l           (%sp)+,%d2              # restore d2
13632        bra.b           fabs_sd_unfl_dis
13633
13634#
13635# operand WILL overflow.
13636#
13637fabs_sd_ovfl:
13638        fmov.l          &0x0,%fpsr              # clear FPSR
13639        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
13640
13641        fabs.x          FP_SCR0(%a6),%fp0       # perform absolute
13642
13643        fmov.l          &0x0,%fpcr              # clear FPCR
13644        fmov.l          %fpsr,%d1               # save FPSR
13645
13646        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
13647
13648fabs_sd_ovfl_tst:
13649        or.l            &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
13650
13651        mov.b           FPCR_ENABLE(%a6),%d1
13652        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
13653        bne.b           fabs_sd_ovfl_ena        # yes
13654
13655#
13656# OVFL is not enabled; therefore, we must create the default result by
13657# calling ovf_res().
13658#
13659fabs_sd_ovfl_dis:
13660        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
13661        sne             %d1                     # set sign param accordingly
13662        mov.l           L_SCR3(%a6),%d0         # pass: prec,mode
13663        bsr.l           ovf_res                 # calculate default result
13664        or.b            %d0,FPSR_CC(%a6)        # set INF,N if applicable
13665        fmovm.x         (%a0),&0x80             # return default result in fp0
13666        rts
13667
13668#
13669# OVFL is enabled.
13670# the INEX2 bit has already been updated by the round to the correct precision.
13671# now, round to extended(and don't alter the FPSR).
13672#
13673fabs_sd_ovfl_ena:
13674        mov.l           %d2,-(%sp)              # save d2
13675        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
13676        mov.l           %d1,%d2                 # make a copy
13677        andi.l          &0x7fff,%d1             # strip sign
13678        andi.w          &0x8000,%d2             # keep old sign
13679        sub.l           %d0,%d1                 # add scale factor
13680        subi.l          &0x6000,%d1             # subtract bias
13681        andi.w          &0x7fff,%d1
13682        or.w            %d2,%d1                 # concat sign,exp
13683        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
13684        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
13685        mov.l           (%sp)+,%d2              # restore d2
13686        bra.b           fabs_sd_ovfl_dis
13687
13688#
13689# the move in MAY underflow. so...
13690#
13691fabs_sd_may_ovfl:
13692        fmov.l          &0x0,%fpsr              # clear FPSR
13693        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
13694
13695        fabs.x          FP_SCR0(%a6),%fp0       # perform absolute
13696
13697        fmov.l          %fpsr,%d1               # save status
13698        fmov.l          &0x0,%fpcr              # clear FPCR
13699
13700        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
13701
13702        fabs.x          %fp0,%fp1               # make a copy of result
13703        fcmp.b          %fp1,&0x2               # is |result| >= 2.b?
13704        fbge.w          fabs_sd_ovfl_tst        # yes; overflow has occurred
13705
13706# no, it didn't overflow; we have correct result
13707        bra.w           fabs_sd_normal_exit
13708
13709##########################################################################
13710
13711#
13712# input is not normalized; what is it?
13713#
13714fabs_not_norm:
13715        cmpi.b          %d1,&DENORM             # weed out DENORM
13716        beq.w           fabs_denorm
13717        cmpi.b          %d1,&SNAN               # weed out SNAN
13718        beq.l           res_snan_1op
13719        cmpi.b          %d1,&QNAN               # weed out QNAN
13720        beq.l           res_qnan_1op
13721
13722        fabs.x          SRC(%a0),%fp0           # force absolute value
13723
13724        cmpi.b          %d1,&INF                # weed out INF
13725        beq.b           fabs_inf
13726fabs_zero:
13727        mov.b           &z_bmask,FPSR_CC(%a6)   # set 'Z' ccode bit
13728        rts
13729fabs_inf:
13730        mov.b           &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
13731        rts
13732
13733#########################################################################
13734# XDEF **************************************************************** #
13735#       fcmp(): fp compare op routine                                   #
13736#                                                                       #
13737# XREF **************************************************************** #
13738#       res_qnan() - return QNAN result                                 #
13739#       res_snan() - return SNAN result                                 #
13740#                                                                       #
13741# INPUT *************************************************************** #
13742#       a0 = pointer to extended precision source operand               #
13743#       a1 = pointer to extended precision destination operand          #
13744#       d0 = round prec/mode                                            #
13745#                                                                       #
13746# OUTPUT ************************************************************** #
13747#       None                                                            #
13748#                                                                       #
13749# ALGORITHM *********************************************************** #
13750#       Handle NANs and denorms as special cases. For everything else,  #
13751# just use the actual fcmp instruction to produce the correct condition #
13752# codes.                                                                #
13753#                                                                       #
13754#########################################################################
13755
13756        global          fcmp
13757fcmp:
13758        clr.w           %d1
13759        mov.b           DTAG(%a6),%d1
13760        lsl.b           &0x3,%d1
13761        or.b            STAG(%a6),%d1
13762        bne.b           fcmp_not_norm           # optimize on non-norm input
13763
13764#
13765# COMPARE FP OPs : NORMs, ZEROs, INFs, and "corrected" DENORMs
13766#
13767fcmp_norm:
13768        fmovm.x         DST(%a1),&0x80          # load dst op
13769
13770        fcmp.x          %fp0,SRC(%a0)           # do compare
13771
13772        fmov.l          %fpsr,%d0               # save FPSR
13773        rol.l           &0x8,%d0                # extract ccode bits
13774        mov.b           %d0,FPSR_CC(%a6)        # set ccode bits(no exc bits are set)
13775
13776        rts
13777
13778#
13779# fcmp: inputs are not both normalized; what are they?
13780#
13781fcmp_not_norm:
13782        mov.w           (tbl_fcmp_op.b,%pc,%d1.w*2),%d1
13783        jmp             (tbl_fcmp_op.b,%pc,%d1.w*1)
13784
13785        swbeg           &48
13786tbl_fcmp_op:
13787        short           fcmp_norm       - tbl_fcmp_op # NORM - NORM
13788        short           fcmp_norm       - tbl_fcmp_op # NORM - ZERO
13789        short           fcmp_norm       - tbl_fcmp_op # NORM - INF
13790        short           fcmp_res_qnan   - tbl_fcmp_op # NORM - QNAN
13791        short           fcmp_nrm_dnrm   - tbl_fcmp_op # NORM - DENORM
13792        short           fcmp_res_snan   - tbl_fcmp_op # NORM - SNAN
13793        short           tbl_fcmp_op     - tbl_fcmp_op #
13794        short           tbl_fcmp_op     - tbl_fcmp_op #
13795
13796        short           fcmp_norm       - tbl_fcmp_op # ZERO - NORM
13797        short           fcmp_norm       - tbl_fcmp_op # ZERO - ZERO
13798        short           fcmp_norm       - tbl_fcmp_op # ZERO - INF
13799        short           fcmp_res_qnan   - tbl_fcmp_op # ZERO - QNAN
13800        short           fcmp_dnrm_s     - tbl_fcmp_op # ZERO - DENORM
13801        short           fcmp_res_snan   - tbl_fcmp_op # ZERO - SNAN
13802        short           tbl_fcmp_op     - tbl_fcmp_op #
13803        short           tbl_fcmp_op     - tbl_fcmp_op #
13804
13805        short           fcmp_norm       - tbl_fcmp_op # INF - NORM
13806        short           fcmp_norm       - tbl_fcmp_op # INF - ZERO
13807        short           fcmp_norm       - tbl_fcmp_op # INF - INF
13808        short           fcmp_res_qnan   - tbl_fcmp_op # INF - QNAN
13809        short           fcmp_dnrm_s     - tbl_fcmp_op # INF - DENORM
13810        short           fcmp_res_snan   - tbl_fcmp_op # INF - SNAN
13811        short           tbl_fcmp_op     - tbl_fcmp_op #
13812        short           tbl_fcmp_op     - tbl_fcmp_op #
13813
13814        short           fcmp_res_qnan   - tbl_fcmp_op # QNAN - NORM
13815        short           fcmp_res_qnan   - tbl_fcmp_op # QNAN - ZERO
13816        short           fcmp_res_qnan   - tbl_fcmp_op # QNAN - INF
13817        short           fcmp_res_qnan   - tbl_fcmp_op # QNAN - QNAN
13818        short           fcmp_res_qnan   - tbl_fcmp_op # QNAN - DENORM
13819        short           fcmp_res_snan   - tbl_fcmp_op # QNAN - SNAN
13820        short           tbl_fcmp_op     - tbl_fcmp_op #
13821        short           tbl_fcmp_op     - tbl_fcmp_op #
13822
13823        short           fcmp_dnrm_nrm   - tbl_fcmp_op # DENORM - NORM
13824        short           fcmp_dnrm_d     - tbl_fcmp_op # DENORM - ZERO
13825        short           fcmp_dnrm_d     - tbl_fcmp_op # DENORM - INF
13826        short           fcmp_res_qnan   - tbl_fcmp_op # DENORM - QNAN
13827        short           fcmp_dnrm_sd    - tbl_fcmp_op # DENORM - DENORM
13828        short           fcmp_res_snan   - tbl_fcmp_op # DENORM - SNAN
13829        short           tbl_fcmp_op     - tbl_fcmp_op #
13830        short           tbl_fcmp_op     - tbl_fcmp_op #
13831
13832        short           fcmp_res_snan   - tbl_fcmp_op # SNAN - NORM
13833        short           fcmp_res_snan   - tbl_fcmp_op # SNAN - ZERO
13834        short           fcmp_res_snan   - tbl_fcmp_op # SNAN - INF
13835        short           fcmp_res_snan   - tbl_fcmp_op # SNAN - QNAN
13836        short           fcmp_res_snan   - tbl_fcmp_op # SNAN - DENORM
13837        short           fcmp_res_snan   - tbl_fcmp_op # SNAN - SNAN
13838        short           tbl_fcmp_op     - tbl_fcmp_op #
13839        short           tbl_fcmp_op     - tbl_fcmp_op #
13840
13841# unlike all other functions for QNAN and SNAN, fcmp does NOT set the
13842# 'N' bit for a negative QNAN or SNAN input so we must squelch it here.
13843fcmp_res_qnan:
13844        bsr.l           res_qnan
13845        andi.b          &0xf7,FPSR_CC(%a6)
13846        rts
13847fcmp_res_snan:
13848        bsr.l           res_snan
13849        andi.b          &0xf7,FPSR_CC(%a6)
13850        rts
13851
13852#
13853# DENORMs are a little more difficult.
13854# If you have a 2 DENORMs, then you can just force the j-bit to a one
13855# and use the fcmp_norm routine.
13856# If you have a DENORM and an INF or ZERO, just force the DENORM's j-bit to a one
13857# and use the fcmp_norm routine.
13858# If you have a DENORM and a NORM with opposite signs, then use fcmp_norm, also.
13859# But with a DENORM and a NORM of the same sign, the neg bit is set if the
13860# (1) signs are (+) and the DENORM is the dst or
13861# (2) signs are (-) and the DENORM is the src
13862#
13863
13864fcmp_dnrm_s:
13865        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
13866        mov.l           SRC_HI(%a0),%d0
13867        bset            &31,%d0                 # DENORM src; make into small norm
13868        mov.l           %d0,FP_SCR0_HI(%a6)
13869        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
13870        lea             FP_SCR0(%a6),%a0
13871        bra.w           fcmp_norm
13872
13873fcmp_dnrm_d:
13874        mov.l           DST_EX(%a1),FP_SCR0_EX(%a6)
13875        mov.l           DST_HI(%a1),%d0
13876        bset            &31,%d0                 # DENORM src; make into small norm
13877        mov.l           %d0,FP_SCR0_HI(%a6)
13878        mov.l           DST_LO(%a1),FP_SCR0_LO(%a6)
13879        lea             FP_SCR0(%a6),%a1
13880        bra.w           fcmp_norm
13881
13882fcmp_dnrm_sd:
13883        mov.w           DST_EX(%a1),FP_SCR1_EX(%a6)
13884        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
13885        mov.l           DST_HI(%a1),%d0
13886        bset            &31,%d0                 # DENORM dst; make into small norm
13887        mov.l           %d0,FP_SCR1_HI(%a6)
13888        mov.l           SRC_HI(%a0),%d0
13889        bset            &31,%d0                 # DENORM dst; make into small norm
13890        mov.l           %d0,FP_SCR0_HI(%a6)
13891        mov.l           DST_LO(%a1),FP_SCR1_LO(%a6)
13892        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
13893        lea             FP_SCR1(%a6),%a1
13894        lea             FP_SCR0(%a6),%a0
13895        bra.w           fcmp_norm
13896
13897fcmp_nrm_dnrm:
13898        mov.b           SRC_EX(%a0),%d0         # determine if like signs
13899        mov.b           DST_EX(%a1),%d1
13900        eor.b           %d0,%d1
13901        bmi.w           fcmp_dnrm_s
13902
13903# signs are the same, so must determine the answer ourselves.
13904        tst.b           %d0                     # is src op negative?
13905        bmi.b           fcmp_nrm_dnrm_m         # yes
13906        rts
13907fcmp_nrm_dnrm_m:
13908        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'Z' ccode bit
13909        rts
13910
13911fcmp_dnrm_nrm:
13912        mov.b           SRC_EX(%a0),%d0         # determine if like signs
13913        mov.b           DST_EX(%a1),%d1
13914        eor.b           %d0,%d1
13915        bmi.w           fcmp_dnrm_d
13916
13917# signs are the same, so must determine the answer ourselves.
13918        tst.b           %d0                     # is src op negative?
13919        bpl.b           fcmp_dnrm_nrm_m         # no
13920        rts
13921fcmp_dnrm_nrm_m:
13922        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'Z' ccode bit
13923        rts
13924
13925#########################################################################
13926# XDEF **************************************************************** #
13927#       fsglmul(): emulates the fsglmul instruction                     #
13928#                                                                       #
13929# XREF **************************************************************** #
13930#       scale_to_zero_src() - scale src exponent to zero                #
13931#       scale_to_zero_dst() - scale dst exponent to zero                #
13932#       unf_res4() - return default underflow result for sglop          #
13933#       ovf_res() - return default overflow result                      #
13934#       res_qnan() - return QNAN result                                 #
13935#       res_snan() - return SNAN result                                 #
13936#                                                                       #
13937# INPUT *************************************************************** #
13938#       a0 = pointer to extended precision source operand               #
13939#       a1 = pointer to extended precision destination operand          #
13940#       d0  rnd prec,mode                                               #
13941#                                                                       #
13942# OUTPUT ************************************************************** #
13943#       fp0 = result                                                    #
13944#       fp1 = EXOP (if exception occurred)                              #
13945#                                                                       #
13946# ALGORITHM *********************************************************** #
13947#       Handle NANs, infinities, and zeroes as special cases. Divide    #
13948# norms/denorms into ext/sgl/dbl precision.                             #
13949#       For norms/denorms, scale the exponents such that a multiply     #
13950# instruction won't cause an exception. Use the regular fsglmul to      #
13951# compute a result. Check if the regular operands would have taken      #
13952# an exception. If so, return the default overflow/underflow result     #
13953# and return the EXOP if exceptions are enabled. Else, scale the        #
13954# result operand to the proper exponent.                                #
13955#                                                                       #
13956#########################################################################
13957
13958        global          fsglmul
13959fsglmul:
13960        mov.l           %d0,L_SCR3(%a6)         # store rnd info
13961
13962        clr.w           %d1
13963        mov.b           DTAG(%a6),%d1
13964        lsl.b           &0x3,%d1
13965        or.b            STAG(%a6),%d1
13966
13967        bne.w           fsglmul_not_norm        # optimize on non-norm input
13968
13969fsglmul_norm:
13970        mov.w           DST_EX(%a1),FP_SCR1_EX(%a6)
13971        mov.l           DST_HI(%a1),FP_SCR1_HI(%a6)
13972        mov.l           DST_LO(%a1),FP_SCR1_LO(%a6)
13973
13974        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
13975        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
13976        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
13977
13978        bsr.l           scale_to_zero_src       # scale exponent
13979        mov.l           %d0,-(%sp)              # save scale factor 1
13980
13981        bsr.l           scale_to_zero_dst       # scale dst exponent
13982
13983        add.l           (%sp)+,%d0              # SCALE_FACTOR = scale1 + scale2
13984
13985        cmpi.l          %d0,&0x3fff-0x7ffe      # would result ovfl?
13986        beq.w           fsglmul_may_ovfl        # result may rnd to overflow
13987        blt.w           fsglmul_ovfl            # result will overflow
13988
13989        cmpi.l          %d0,&0x3fff+0x0001      # would result unfl?
13990        beq.w           fsglmul_may_unfl        # result may rnd to no unfl
13991        bgt.w           fsglmul_unfl            # result will underflow
13992
13993fsglmul_normal:
13994        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
13995
13996        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
13997        fmov.l          &0x0,%fpsr              # clear FPSR
13998
13999        fsglmul.x       FP_SCR0(%a6),%fp0       # execute sgl multiply
14000
14001        fmov.l          %fpsr,%d1               # save status
14002        fmov.l          &0x0,%fpcr              # clear FPCR
14003
14004        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
14005
14006fsglmul_normal_exit:
14007        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
14008        mov.l           %d2,-(%sp)              # save d2
14009        mov.w           FP_SCR0_EX(%a6),%d1     # load {sgn,exp}
14010        mov.l           %d1,%d2                 # make a copy
14011        andi.l          &0x7fff,%d1             # strip sign
14012        andi.w          &0x8000,%d2             # keep old sign
14013        sub.l           %d0,%d1                 # add scale factor
14014        or.w            %d2,%d1                 # concat old sign,new exp
14015        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
14016        mov.l           (%sp)+,%d2              # restore d2
14017        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
14018        rts
14019
14020fsglmul_ovfl:
14021        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
14022
14023        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
14024        fmov.l          &0x0,%fpsr              # clear FPSR
14025
14026        fsglmul.x       FP_SCR0(%a6),%fp0       # execute sgl multiply
14027
14028        fmov.l          %fpsr,%d1               # save status
14029        fmov.l          &0x0,%fpcr              # clear FPCR
14030
14031        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
14032
14033fsglmul_ovfl_tst:
14034
14035# save setting this until now because this is where fsglmul_may_ovfl may jump in
14036        or.l            &ovfl_inx_mask, USER_FPSR(%a6) # set ovfl/aovfl/ainex
14037
14038        mov.b           FPCR_ENABLE(%a6),%d1
14039        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
14040        bne.b           fsglmul_ovfl_ena        # yes
14041
14042fsglmul_ovfl_dis:
14043        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
14044        sne             %d1                     # set sign param accordingly
14045        mov.l           L_SCR3(%a6),%d0         # pass prec:rnd
14046        andi.b          &0x30,%d0               # force prec = ext
14047        bsr.l           ovf_res                 # calculate default result
14048        or.b            %d0,FPSR_CC(%a6)        # set INF,N if applicable
14049        fmovm.x         (%a0),&0x80             # return default result in fp0
14050        rts
14051
14052fsglmul_ovfl_ena:
14053        fmovm.x         &0x80,FP_SCR0(%a6)      # move result to stack
14054
14055        mov.l           %d2,-(%sp)              # save d2
14056        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
14057        mov.l           %d1,%d2                 # make a copy
14058        andi.l          &0x7fff,%d1             # strip sign
14059        sub.l           %d0,%d1                 # add scale factor
14060        subi.l          &0x6000,%d1             # subtract bias
14061        andi.w          &0x7fff,%d1
14062        andi.w          &0x8000,%d2             # keep old sign
14063        or.w            %d2,%d1                 # concat old sign,new exp
14064        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
14065        mov.l           (%sp)+,%d2              # restore d2
14066        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
14067        bra.b           fsglmul_ovfl_dis
14068
14069fsglmul_may_ovfl:
14070        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
14071
14072        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
14073        fmov.l          &0x0,%fpsr              # clear FPSR
14074
14075        fsglmul.x       FP_SCR0(%a6),%fp0       # execute sgl multiply
14076
14077        fmov.l          %fpsr,%d1               # save status
14078        fmov.l          &0x0,%fpcr              # clear FPCR
14079
14080        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
14081
14082        fabs.x          %fp0,%fp1               # make a copy of result
14083        fcmp.b          %fp1,&0x2               # is |result| >= 2.b?
14084        fbge.w          fsglmul_ovfl_tst        # yes; overflow has occurred
14085
14086# no, it didn't overflow; we have correct result
14087        bra.w           fsglmul_normal_exit
14088
14089fsglmul_unfl:
14090        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
14091
14092        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
14093
14094        fmov.l          &rz_mode*0x10,%fpcr     # set FPCR
14095        fmov.l          &0x0,%fpsr              # clear FPSR
14096
14097        fsglmul.x       FP_SCR0(%a6),%fp0       # execute sgl multiply
14098
14099        fmov.l          %fpsr,%d1               # save status
14100        fmov.l          &0x0,%fpcr              # clear FPCR
14101
14102        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
14103
14104        mov.b           FPCR_ENABLE(%a6),%d1
14105        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
14106        bne.b           fsglmul_unfl_ena        # yes
14107
14108fsglmul_unfl_dis:
14109        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
14110
14111        lea             FP_SCR0(%a6),%a0        # pass: result addr
14112        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
14113        bsr.l           unf_res4                # calculate default result
14114        or.b            %d0,FPSR_CC(%a6)        # 'Z' bit may have been set
14115        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
14116        rts
14117
14118#
14119# UNFL is enabled.
14120#
14121fsglmul_unfl_ena:
14122        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op
14123
14124        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
14125        fmov.l          &0x0,%fpsr              # clear FPSR
14126
14127        fsglmul.x       FP_SCR0(%a6),%fp1       # execute sgl multiply
14128
14129        fmov.l          &0x0,%fpcr              # clear FPCR
14130
14131        fmovm.x         &0x40,FP_SCR0(%a6)      # save result to stack
14132        mov.l           %d2,-(%sp)              # save d2
14133        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
14134        mov.l           %d1,%d2                 # make a copy
14135        andi.l          &0x7fff,%d1             # strip sign
14136        andi.w          &0x8000,%d2             # keep old sign
14137        sub.l           %d0,%d1                 # add scale factor
14138        addi.l          &0x6000,%d1             # add bias
14139        andi.w          &0x7fff,%d1
14140        or.w            %d2,%d1                 # concat old sign,new exp
14141        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
14142        mov.l           (%sp)+,%d2              # restore d2
14143        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
14144        bra.w           fsglmul_unfl_dis
14145
14146fsglmul_may_unfl:
14147        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
14148
14149        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
14150        fmov.l          &0x0,%fpsr              # clear FPSR
14151
14152        fsglmul.x       FP_SCR0(%a6),%fp0       # execute sgl multiply
14153
14154        fmov.l          %fpsr,%d1               # save status
14155        fmov.l          &0x0,%fpcr              # clear FPCR
14156
14157        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
14158
14159        fabs.x          %fp0,%fp1               # make a copy of result
14160        fcmp.b          %fp1,&0x2               # is |result| > 2.b?
14161        fbgt.w          fsglmul_normal_exit     # no; no underflow occurred
14162        fblt.w          fsglmul_unfl            # yes; underflow occurred
14163
14164#
14165# we still don't know if underflow occurred. result is ~ equal to 2. but,
14166# we don't know if the result was an underflow that rounded up to a 2 or
14167# a normalized number that rounded down to a 2. so, redo the entire operation
14168# using RZ as the rounding mode to see what the pre-rounded result is.
14169# this case should be relatively rare.
14170#
14171        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op into fp1
14172
14173        mov.l           L_SCR3(%a6),%d1
14174        andi.b          &0xc0,%d1               # keep rnd prec
14175        ori.b           &rz_mode*0x10,%d1       # insert RZ
14176
14177        fmov.l          %d1,%fpcr               # set FPCR
14178        fmov.l          &0x0,%fpsr              # clear FPSR
14179
14180        fsglmul.x       FP_SCR0(%a6),%fp1       # execute sgl multiply
14181
14182        fmov.l          &0x0,%fpcr              # clear FPCR
14183        fabs.x          %fp1                    # make absolute value
14184        fcmp.b          %fp1,&0x2               # is |result| < 2.b?
14185        fbge.w          fsglmul_normal_exit     # no; no underflow occurred
14186        bra.w           fsglmul_unfl            # yes, underflow occurred
14187
14188##############################################################################
14189
14190#
14191# Single Precision Multiply: inputs are not both normalized; what are they?
14192#
14193fsglmul_not_norm:
14194        mov.w           (tbl_fsglmul_op.b,%pc,%d1.w*2),%d1
14195        jmp             (tbl_fsglmul_op.b,%pc,%d1.w*1)
14196
14197        swbeg           &48
14198tbl_fsglmul_op:
14199        short           fsglmul_norm            - tbl_fsglmul_op # NORM x NORM
14200        short           fsglmul_zero            - tbl_fsglmul_op # NORM x ZERO
14201        short           fsglmul_inf_src         - tbl_fsglmul_op # NORM x INF
14202        short           fsglmul_res_qnan        - tbl_fsglmul_op # NORM x QNAN
14203        short           fsglmul_norm            - tbl_fsglmul_op # NORM x DENORM
14204        short           fsglmul_res_snan        - tbl_fsglmul_op # NORM x SNAN
14205        short           tbl_fsglmul_op          - tbl_fsglmul_op #
14206        short           tbl_fsglmul_op          - tbl_fsglmul_op #
14207
14208        short           fsglmul_zero            - tbl_fsglmul_op # ZERO x NORM
14209        short           fsglmul_zero            - tbl_fsglmul_op # ZERO x ZERO
14210        short           fsglmul_res_operr       - tbl_fsglmul_op # ZERO x INF
14211        short           fsglmul_res_qnan        - tbl_fsglmul_op # ZERO x QNAN
14212        short           fsglmul_zero            - tbl_fsglmul_op # ZERO x DENORM
14213        short           fsglmul_res_snan        - tbl_fsglmul_op # ZERO x SNAN
14214        short           tbl_fsglmul_op          - tbl_fsglmul_op #
14215        short           tbl_fsglmul_op          - tbl_fsglmul_op #
14216
14217        short           fsglmul_inf_dst         - tbl_fsglmul_op # INF x NORM
14218        short           fsglmul_res_operr       - tbl_fsglmul_op # INF x ZERO
14219        short           fsglmul_inf_dst         - tbl_fsglmul_op # INF x INF
14220        short           fsglmul_res_qnan        - tbl_fsglmul_op # INF x QNAN
14221        short           fsglmul_inf_dst         - tbl_fsglmul_op # INF x DENORM
14222        short           fsglmul_res_snan        - tbl_fsglmul_op # INF x SNAN
14223        short           tbl_fsglmul_op          - tbl_fsglmul_op #
14224        short           tbl_fsglmul_op          - tbl_fsglmul_op #
14225
14226        short           fsglmul_res_qnan        - tbl_fsglmul_op # QNAN x NORM
14227        short           fsglmul_res_qnan        - tbl_fsglmul_op # QNAN x ZERO
14228        short           fsglmul_res_qnan        - tbl_fsglmul_op # QNAN x INF
14229        short           fsglmul_res_qnan        - tbl_fsglmul_op # QNAN x QNAN
14230        short           fsglmul_res_qnan        - tbl_fsglmul_op # QNAN x DENORM
14231        short           fsglmul_res_snan        - tbl_fsglmul_op # QNAN x SNAN
14232        short           tbl_fsglmul_op          - tbl_fsglmul_op #
14233        short           tbl_fsglmul_op          - tbl_fsglmul_op #
14234
14235        short           fsglmul_norm            - tbl_fsglmul_op # NORM x NORM
14236        short           fsglmul_zero            - tbl_fsglmul_op # NORM x ZERO
14237        short           fsglmul_inf_src         - tbl_fsglmul_op # NORM x INF
14238        short           fsglmul_res_qnan        - tbl_fsglmul_op # NORM x QNAN
14239        short           fsglmul_norm            - tbl_fsglmul_op # NORM x DENORM
14240        short           fsglmul_res_snan        - tbl_fsglmul_op # NORM x SNAN
14241        short           tbl_fsglmul_op          - tbl_fsglmul_op #
14242        short           tbl_fsglmul_op          - tbl_fsglmul_op #
14243
14244        short           fsglmul_res_snan        - tbl_fsglmul_op # SNAN x NORM
14245        short           fsglmul_res_snan        - tbl_fsglmul_op # SNAN x ZERO
14246        short           fsglmul_res_snan        - tbl_fsglmul_op # SNAN x INF
14247        short           fsglmul_res_snan        - tbl_fsglmul_op # SNAN x QNAN
14248        short           fsglmul_res_snan        - tbl_fsglmul_op # SNAN x DENORM
14249        short           fsglmul_res_snan        - tbl_fsglmul_op # SNAN x SNAN
14250        short           tbl_fsglmul_op          - tbl_fsglmul_op #
14251        short           tbl_fsglmul_op          - tbl_fsglmul_op #
14252
14253fsglmul_res_operr:
14254        bra.l           res_operr
14255fsglmul_res_snan:
14256        bra.l           res_snan
14257fsglmul_res_qnan:
14258        bra.l           res_qnan
14259fsglmul_zero:
14260        bra.l           fmul_zero
14261fsglmul_inf_src:
14262        bra.l           fmul_inf_src
14263fsglmul_inf_dst:
14264        bra.l           fmul_inf_dst
14265
14266#########################################################################
14267# XDEF **************************************************************** #
14268#       fsgldiv(): emulates the fsgldiv instruction                     #
14269#                                                                       #
14270# XREF **************************************************************** #
14271#       scale_to_zero_src() - scale src exponent to zero                #
14272#       scale_to_zero_dst() - scale dst exponent to zero                #
14273#       unf_res4() - return default underflow result for sglop          #
14274#       ovf_res() - return default overflow result                      #
14275#       res_qnan() - return QNAN result                                 #
14276#       res_snan() - return SNAN result                                 #
14277#                                                                       #
14278# INPUT *************************************************************** #
14279#       a0 = pointer to extended precision source operand               #
14280#       a1 = pointer to extended precision destination operand          #
14281#       d0  rnd prec,mode                                               #
14282#                                                                       #
14283# OUTPUT ************************************************************** #
14284#       fp0 = result                                                    #
14285#       fp1 = EXOP (if exception occurred)                              #
14286#                                                                       #
14287# ALGORITHM *********************************************************** #
14288#       Handle NANs, infinities, and zeroes as special cases. Divide    #
14289# norms/denorms into ext/sgl/dbl precision.                             #
14290#       For norms/denorms, scale the exponents such that a divide       #
14291# instruction won't cause an exception. Use the regular fsgldiv to      #
14292# compute a result. Check if the regular operands would have taken      #
14293# an exception. If so, return the default overflow/underflow result     #
14294# and return the EXOP if exceptions are enabled. Else, scale the        #
14295# result operand to the proper exponent.                                #
14296#                                                                       #
14297#########################################################################
14298
14299        global          fsgldiv
14300fsgldiv:
14301        mov.l           %d0,L_SCR3(%a6)         # store rnd info
14302
14303        clr.w           %d1
14304        mov.b           DTAG(%a6),%d1
14305        lsl.b           &0x3,%d1
14306        or.b            STAG(%a6),%d1           # combine src tags
14307
14308        bne.w           fsgldiv_not_norm        # optimize on non-norm input
14309
14310#
14311# DIVIDE: NORMs and DENORMs ONLY!
14312#
14313fsgldiv_norm:
14314        mov.w           DST_EX(%a1),FP_SCR1_EX(%a6)
14315        mov.l           DST_HI(%a1),FP_SCR1_HI(%a6)
14316        mov.l           DST_LO(%a1),FP_SCR1_LO(%a6)
14317
14318        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
14319        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
14320        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
14321
14322        bsr.l           scale_to_zero_src       # calculate scale factor 1
14323        mov.l           %d0,-(%sp)              # save scale factor 1
14324
14325        bsr.l           scale_to_zero_dst       # calculate scale factor 2
14326
14327        neg.l           (%sp)                   # S.F. = scale1 - scale2
14328        add.l           %d0,(%sp)
14329
14330        mov.w           2+L_SCR3(%a6),%d1       # fetch precision,mode
14331        lsr.b           &0x6,%d1
14332        mov.l           (%sp)+,%d0
14333        cmpi.l          %d0,&0x3fff-0x7ffe
14334        ble.w           fsgldiv_may_ovfl
14335
14336        cmpi.l          %d0,&0x3fff-0x0000      # will result underflow?
14337        beq.w           fsgldiv_may_unfl        # maybe
14338        bgt.w           fsgldiv_unfl            # yes; go handle underflow
14339
14340fsgldiv_normal:
14341        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
14342
14343        fmov.l          L_SCR3(%a6),%fpcr       # save FPCR
14344        fmov.l          &0x0,%fpsr              # clear FPSR
14345
14346        fsgldiv.x       FP_SCR0(%a6),%fp0       # perform sgl divide
14347
14348        fmov.l          %fpsr,%d1               # save FPSR
14349        fmov.l          &0x0,%fpcr              # clear FPCR
14350
14351        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
14352
14353fsgldiv_normal_exit:
14354        fmovm.x         &0x80,FP_SCR0(%a6)      # store result on stack
14355        mov.l           %d2,-(%sp)              # save d2
14356        mov.w           FP_SCR0_EX(%a6),%d1     # load {sgn,exp}
14357        mov.l           %d1,%d2                 # make a copy
14358        andi.l          &0x7fff,%d1             # strip sign
14359        andi.w          &0x8000,%d2             # keep old sign
14360        sub.l           %d0,%d1                 # add scale factor
14361        or.w            %d2,%d1                 # concat old sign,new exp
14362        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
14363        mov.l           (%sp)+,%d2              # restore d2
14364        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
14365        rts
14366
14367fsgldiv_may_ovfl:
14368        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
14369
14370        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
14371        fmov.l          &0x0,%fpsr              # set FPSR
14372
14373        fsgldiv.x       FP_SCR0(%a6),%fp0       # execute divide
14374
14375        fmov.l          %fpsr,%d1
14376        fmov.l          &0x0,%fpcr
14377
14378        or.l            %d1,USER_FPSR(%a6)      # save INEX,N
14379
14380        fmovm.x         &0x01,-(%sp)            # save result to stack
14381        mov.w           (%sp),%d1               # fetch new exponent
14382        add.l           &0xc,%sp                # clear result
14383        andi.l          &0x7fff,%d1             # strip sign
14384        sub.l           %d0,%d1                 # add scale factor
14385        cmp.l           %d1,&0x7fff             # did divide overflow?
14386        blt.b           fsgldiv_normal_exit
14387
14388fsgldiv_ovfl_tst:
14389        or.w            &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex
14390
14391        mov.b           FPCR_ENABLE(%a6),%d1
14392        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
14393        bne.b           fsgldiv_ovfl_ena        # yes
14394
14395fsgldiv_ovfl_dis:
14396        btst            &neg_bit,FPSR_CC(%a6)   # is result negative
14397        sne             %d1                     # set sign param accordingly
14398        mov.l           L_SCR3(%a6),%d0         # pass prec:rnd
14399        andi.b          &0x30,%d0               # kill precision
14400        bsr.l           ovf_res                 # calculate default result
14401        or.b            %d0,FPSR_CC(%a6)        # set INF if applicable
14402        fmovm.x         (%a0),&0x80             # return default result in fp0
14403        rts
14404
14405fsgldiv_ovfl_ena:
14406        fmovm.x         &0x80,FP_SCR0(%a6)      # move result to stack
14407
14408        mov.l           %d2,-(%sp)              # save d2
14409        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
14410        mov.l           %d1,%d2                 # make a copy
14411        andi.l          &0x7fff,%d1             # strip sign
14412        andi.w          &0x8000,%d2             # keep old sign
14413        sub.l           %d0,%d1                 # add scale factor
14414        subi.l          &0x6000,%d1             # subtract new bias
14415        andi.w          &0x7fff,%d1             # clear ms bit
14416        or.w            %d2,%d1                 # concat old sign,new exp
14417        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
14418        mov.l           (%sp)+,%d2              # restore d2
14419        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
14420        bra.b           fsgldiv_ovfl_dis
14421
14422fsgldiv_unfl:
14423        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
14424
14425        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
14426
14427        fmov.l          &rz_mode*0x10,%fpcr     # set FPCR
14428        fmov.l          &0x0,%fpsr              # clear FPSR
14429
14430        fsgldiv.x       FP_SCR0(%a6),%fp0       # execute sgl divide
14431
14432        fmov.l          %fpsr,%d1               # save status
14433        fmov.l          &0x0,%fpcr              # clear FPCR
14434
14435        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
14436
14437        mov.b           FPCR_ENABLE(%a6),%d1
14438        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
14439        bne.b           fsgldiv_unfl_ena        # yes
14440
14441fsgldiv_unfl_dis:
14442        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
14443
14444        lea             FP_SCR0(%a6),%a0        # pass: result addr
14445        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
14446        bsr.l           unf_res4                # calculate default result
14447        or.b            %d0,FPSR_CC(%a6)        # 'Z' bit may have been set
14448        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
14449        rts
14450
14451#
14452# UNFL is enabled.
14453#
14454fsgldiv_unfl_ena:
14455        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op
14456
14457        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
14458        fmov.l          &0x0,%fpsr              # clear FPSR
14459
14460        fsgldiv.x       FP_SCR0(%a6),%fp1       # execute sgl divide
14461
14462        fmov.l          &0x0,%fpcr              # clear FPCR
14463
14464        fmovm.x         &0x40,FP_SCR0(%a6)      # save result to stack
14465        mov.l           %d2,-(%sp)              # save d2
14466        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
14467        mov.l           %d1,%d2                 # make a copy
14468        andi.l          &0x7fff,%d1             # strip sign
14469        andi.w          &0x8000,%d2             # keep old sign
14470        sub.l           %d0,%d1                 # add scale factor
14471        addi.l          &0x6000,%d1             # add bias
14472        andi.w          &0x7fff,%d1             # clear top bit
14473        or.w            %d2,%d1                 # concat old sign, new exp
14474        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
14475        mov.l           (%sp)+,%d2              # restore d2
14476        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
14477        bra.b           fsgldiv_unfl_dis
14478
14479#
14480# the divide operation MAY underflow:
14481#
14482fsgldiv_may_unfl:
14483        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
14484
14485        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
14486        fmov.l          &0x0,%fpsr              # clear FPSR
14487
14488        fsgldiv.x       FP_SCR0(%a6),%fp0       # execute sgl divide
14489
14490        fmov.l          %fpsr,%d1               # save status
14491        fmov.l          &0x0,%fpcr              # clear FPCR
14492
14493        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
14494
14495        fabs.x          %fp0,%fp1               # make a copy of result
14496        fcmp.b          %fp1,&0x1               # is |result| > 1.b?
14497        fbgt.w          fsgldiv_normal_exit     # no; no underflow occurred
14498        fblt.w          fsgldiv_unfl            # yes; underflow occurred
14499
14500#
14501# we still don't know if underflow occurred. result is ~ equal to 1. but,
14502# we don't know if the result was an underflow that rounded up to a 1
14503# or a normalized number that rounded down to a 1. so, redo the entire
14504# operation using RZ as the rounding mode to see what the pre-rounded
14505# result is. this case should be relatively rare.
14506#
14507        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op into %fp1
14508
14509        clr.l           %d1                     # clear scratch register
14510        ori.b           &rz_mode*0x10,%d1       # force RZ rnd mode
14511
14512        fmov.l          %d1,%fpcr               # set FPCR
14513        fmov.l          &0x0,%fpsr              # clear FPSR
14514
14515        fsgldiv.x       FP_SCR0(%a6),%fp1       # execute sgl divide
14516
14517        fmov.l          &0x0,%fpcr              # clear FPCR
14518        fabs.x          %fp1                    # make absolute value
14519        fcmp.b          %fp1,&0x1               # is |result| < 1.b?
14520        fbge.w          fsgldiv_normal_exit     # no; no underflow occurred
14521        bra.w           fsgldiv_unfl            # yes; underflow occurred
14522
14523############################################################################
14524
14525#
14526# Divide: inputs are not both normalized; what are they?
14527#
14528fsgldiv_not_norm:
14529        mov.w           (tbl_fsgldiv_op.b,%pc,%d1.w*2),%d1
14530        jmp             (tbl_fsgldiv_op.b,%pc,%d1.w*1)
14531
14532        swbeg           &48
14533tbl_fsgldiv_op:
14534        short           fsgldiv_norm            - tbl_fsgldiv_op # NORM / NORM
14535        short           fsgldiv_inf_load        - tbl_fsgldiv_op # NORM / ZERO
14536        short           fsgldiv_zero_load       - tbl_fsgldiv_op # NORM / INF
14537        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # NORM / QNAN
14538        short           fsgldiv_norm            - tbl_fsgldiv_op # NORM / DENORM
14539        short           fsgldiv_res_snan        - tbl_fsgldiv_op # NORM / SNAN
14540        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
14541        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
14542
14543        short           fsgldiv_zero_load       - tbl_fsgldiv_op # ZERO / NORM
14544        short           fsgldiv_res_operr       - tbl_fsgldiv_op # ZERO / ZERO
14545        short           fsgldiv_zero_load       - tbl_fsgldiv_op # ZERO / INF
14546        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # ZERO / QNAN
14547        short           fsgldiv_zero_load       - tbl_fsgldiv_op # ZERO / DENORM
14548        short           fsgldiv_res_snan        - tbl_fsgldiv_op # ZERO / SNAN
14549        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
14550        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
14551
14552        short           fsgldiv_inf_dst         - tbl_fsgldiv_op # INF / NORM
14553        short           fsgldiv_inf_dst         - tbl_fsgldiv_op # INF / ZERO
14554        short           fsgldiv_res_operr       - tbl_fsgldiv_op # INF / INF
14555        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # INF / QNAN
14556        short           fsgldiv_inf_dst         - tbl_fsgldiv_op # INF / DENORM
14557        short           fsgldiv_res_snan        - tbl_fsgldiv_op # INF / SNAN
14558        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
14559        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
14560
14561        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # QNAN / NORM
14562        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # QNAN / ZERO
14563        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # QNAN / INF
14564        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # QNAN / QNAN
14565        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # QNAN / DENORM
14566        short           fsgldiv_res_snan        - tbl_fsgldiv_op # QNAN / SNAN
14567        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
14568        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
14569
14570        short           fsgldiv_norm            - tbl_fsgldiv_op # DENORM / NORM
14571        short           fsgldiv_inf_load        - tbl_fsgldiv_op # DENORM / ZERO
14572        short           fsgldiv_zero_load       - tbl_fsgldiv_op # DENORM / INF
14573        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # DENORM / QNAN
14574        short           fsgldiv_norm            - tbl_fsgldiv_op # DENORM / DENORM
14575        short           fsgldiv_res_snan        - tbl_fsgldiv_op # DENORM / SNAN
14576        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
14577        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
14578
14579        short           fsgldiv_res_snan        - tbl_fsgldiv_op # SNAN / NORM
14580        short           fsgldiv_res_snan        - tbl_fsgldiv_op # SNAN / ZERO
14581        short           fsgldiv_res_snan        - tbl_fsgldiv_op # SNAN / INF
14582        short           fsgldiv_res_snan        - tbl_fsgldiv_op # SNAN / QNAN
14583        short           fsgldiv_res_snan        - tbl_fsgldiv_op # SNAN / DENORM
14584        short           fsgldiv_res_snan        - tbl_fsgldiv_op # SNAN / SNAN
14585        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
14586        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
14587
14588fsgldiv_res_qnan:
14589        bra.l           res_qnan
14590fsgldiv_res_snan:
14591        bra.l           res_snan
14592fsgldiv_res_operr:
14593        bra.l           res_operr
14594fsgldiv_inf_load:
14595        bra.l           fdiv_inf_load
14596fsgldiv_zero_load:
14597        bra.l           fdiv_zero_load
14598fsgldiv_inf_dst:
14599        bra.l           fdiv_inf_dst
14600
14601#########################################################################
14602# XDEF **************************************************************** #
14603#       fadd(): emulates the fadd instruction                           #
14604#       fsadd(): emulates the fadd instruction                          #
14605#       fdadd(): emulates the fdadd instruction                         #
14606#                                                                       #
14607# XREF **************************************************************** #
14608#       addsub_scaler2() - scale the operands so they won't take exc    #
14609#       ovf_res() - return default overflow result                      #
14610#       unf_res() - return default underflow result                     #
14611#       res_qnan() - set QNAN result                                    #
14612#       res_snan() - set SNAN result                                    #
14613#       res_operr() - set OPERR result                                  #
14614#       scale_to_zero_src() - set src operand exponent equal to zero    #
14615#       scale_to_zero_dst() - set dst operand exponent equal to zero    #
14616#                                                                       #
14617# INPUT *************************************************************** #
14618#       a0 = pointer to extended precision source operand               #
14619#       a1 = pointer to extended precision destination operand          #
14620#                                                                       #
14621# OUTPUT ************************************************************** #
14622#       fp0 = result                                                    #
14623#       fp1 = EXOP (if exception occurred)                              #
14624#                                                                       #
14625# ALGORITHM *********************************************************** #
14626#       Handle NANs, infinities, and zeroes as special cases. Divide    #
14627# norms into extended, single, and double precision.                    #
14628#       Do addition after scaling exponents such that exception won't   #
14629# occur. Then, check result exponent to see if exception would have     #
14630# occurred. If so, return default result and maybe EXOP. Else, insert   #
14631# the correct result exponent and return. Set FPSR bits as appropriate. #
14632#                                                                       #
14633#########################################################################
14634
14635        global          fsadd
14636fsadd:
14637        andi.b          &0x30,%d0               # clear rnd prec
14638        ori.b           &s_mode*0x10,%d0        # insert sgl prec
14639        bra.b           fadd
14640
14641        global          fdadd
14642fdadd:
14643        andi.b          &0x30,%d0               # clear rnd prec
14644        ori.b           &d_mode*0x10,%d0        # insert dbl prec
14645
14646        global          fadd
14647fadd:
14648        mov.l           %d0,L_SCR3(%a6)         # store rnd info
14649
14650        clr.w           %d1
14651        mov.b           DTAG(%a6),%d1
14652        lsl.b           &0x3,%d1
14653        or.b            STAG(%a6),%d1           # combine src tags
14654
14655        bne.w           fadd_not_norm           # optimize on non-norm input
14656
14657#
14658# ADD: norms and denorms
14659#
14660fadd_norm:
14661        bsr.l           addsub_scaler2          # scale exponents
14662
14663fadd_zero_entry:
14664        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
14665
14666        fmov.l          &0x0,%fpsr              # clear FPSR
14667        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
14668
14669        fadd.x          FP_SCR0(%a6),%fp0       # execute add
14670
14671        fmov.l          &0x0,%fpcr              # clear FPCR
14672        fmov.l          %fpsr,%d1               # fetch INEX2,N,Z
14673
14674        or.l            %d1,USER_FPSR(%a6)      # save exc and ccode bits
14675
14676        fbeq.w          fadd_zero_exit          # if result is zero, end now
14677
14678        mov.l           %d2,-(%sp)              # save d2
14679
14680        fmovm.x         &0x01,-(%sp)            # save result to stack
14681
14682        mov.w           2+L_SCR3(%a6),%d1
14683        lsr.b           &0x6,%d1
14684
14685        mov.w           (%sp),%d2               # fetch new sign, exp
14686        andi.l          &0x7fff,%d2             # strip sign
14687        sub.l           %d0,%d2                 # add scale factor
14688
14689        cmp.l           %d2,(tbl_fadd_ovfl.b,%pc,%d1.w*4) # is it an overflow?
14690        bge.b           fadd_ovfl               # yes
14691
14692        cmp.l           %d2,(tbl_fadd_unfl.b,%pc,%d1.w*4) # is it an underflow?
14693        blt.w           fadd_unfl               # yes
14694        beq.w           fadd_may_unfl           # maybe; go find out
14695
14696fadd_normal:
14697        mov.w           (%sp),%d1
14698        andi.w          &0x8000,%d1             # keep sign
14699        or.w            %d2,%d1                 # concat sign,new exp
14700        mov.w           %d1,(%sp)               # insert new exponent
14701
14702        fmovm.x         (%sp)+,&0x80            # return result in fp0
14703
14704        mov.l           (%sp)+,%d2              # restore d2
14705        rts
14706
14707fadd_zero_exit:
14708#       fmov.s          &0x00000000,%fp0        # return zero in fp0
14709        rts
14710
14711tbl_fadd_ovfl:
14712        long            0x7fff                  # ext ovfl
14713        long            0x407f                  # sgl ovfl
14714        long            0x43ff                  # dbl ovfl
14715
14716tbl_fadd_unfl:
14717        long            0x0000                  # ext unfl
14718        long            0x3f81                  # sgl unfl
14719        long            0x3c01                  # dbl unfl
14720
14721fadd_ovfl:
14722        or.l            &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
14723
14724        mov.b           FPCR_ENABLE(%a6),%d1
14725        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
14726        bne.b           fadd_ovfl_ena           # yes
14727
14728        add.l           &0xc,%sp
14729fadd_ovfl_dis:
14730        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
14731        sne             %d1                     # set sign param accordingly
14732        mov.l           L_SCR3(%a6),%d0         # pass prec:rnd
14733        bsr.l           ovf_res                 # calculate default result
14734        or.b            %d0,FPSR_CC(%a6)        # set INF,N if applicable
14735        fmovm.x         (%a0),&0x80             # return default result in fp0
14736        mov.l           (%sp)+,%d2              # restore d2
14737        rts
14738
14739fadd_ovfl_ena:
14740        mov.b           L_SCR3(%a6),%d1
14741        andi.b          &0xc0,%d1               # is precision extended?
14742        bne.b           fadd_ovfl_ena_sd        # no; prec = sgl or dbl
14743
14744fadd_ovfl_ena_cont:
14745        mov.w           (%sp),%d1
14746        andi.w          &0x8000,%d1             # keep sign
14747        subi.l          &0x6000,%d2             # add extra bias
14748        andi.w          &0x7fff,%d2
14749        or.w            %d2,%d1                 # concat sign,new exp
14750        mov.w           %d1,(%sp)               # insert new exponent
14751
14752        fmovm.x         (%sp)+,&0x40            # return EXOP in fp1
14753        bra.b           fadd_ovfl_dis
14754
14755fadd_ovfl_ena_sd:
14756        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
14757
14758        mov.l           L_SCR3(%a6),%d1
14759        andi.b          &0x30,%d1               # keep rnd mode
14760        fmov.l          %d1,%fpcr               # set FPCR
14761
14762        fadd.x          FP_SCR0(%a6),%fp0       # execute add
14763
14764        fmov.l          &0x0,%fpcr              # clear FPCR
14765
14766        add.l           &0xc,%sp
14767        fmovm.x         &0x01,-(%sp)
14768        bra.b           fadd_ovfl_ena_cont
14769
14770fadd_unfl:
14771        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
14772
14773        add.l           &0xc,%sp
14774
14775        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
14776
14777        fmov.l          &rz_mode*0x10,%fpcr     # set FPCR
14778        fmov.l          &0x0,%fpsr              # clear FPSR
14779
14780        fadd.x          FP_SCR0(%a6),%fp0       # execute add
14781
14782        fmov.l          &0x0,%fpcr              # clear FPCR
14783        fmov.l          %fpsr,%d1               # save status
14784
14785        or.l            %d1,USER_FPSR(%a6)      # save INEX,N
14786
14787        mov.b           FPCR_ENABLE(%a6),%d1
14788        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
14789        bne.b           fadd_unfl_ena           # yes
14790
14791fadd_unfl_dis:
14792        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
14793
14794        lea             FP_SCR0(%a6),%a0        # pass: result addr
14795        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
14796        bsr.l           unf_res                 # calculate default result
14797        or.b            %d0,FPSR_CC(%a6)        # 'Z' bit may have been set
14798        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
14799        mov.l           (%sp)+,%d2              # restore d2
14800        rts
14801
14802fadd_unfl_ena:
14803        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op
14804
14805        mov.l           L_SCR3(%a6),%d1
14806        andi.b          &0xc0,%d1               # is precision extended?
14807        bne.b           fadd_unfl_ena_sd        # no; sgl or dbl
14808
14809        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
14810
14811fadd_unfl_ena_cont:
14812        fmov.l          &0x0,%fpsr              # clear FPSR
14813
14814        fadd.x          FP_SCR0(%a6),%fp1       # execute multiply
14815
14816        fmov.l          &0x0,%fpcr              # clear FPCR
14817
14818        fmovm.x         &0x40,FP_SCR0(%a6)      # save result to stack
14819        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
14820        mov.l           %d1,%d2                 # make a copy
14821        andi.l          &0x7fff,%d1             # strip sign
14822        andi.w          &0x8000,%d2             # keep old sign
14823        sub.l           %d0,%d1                 # add scale factor
14824        addi.l          &0x6000,%d1             # add new bias
14825        andi.w          &0x7fff,%d1             # clear top bit
14826        or.w            %d2,%d1                 # concat sign,new exp
14827        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
14828        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
14829        bra.w           fadd_unfl_dis
14830
14831fadd_unfl_ena_sd:
14832        mov.l           L_SCR3(%a6),%d1
14833        andi.b          &0x30,%d1               # use only rnd mode
14834        fmov.l          %d1,%fpcr               # set FPCR
14835
14836        bra.b           fadd_unfl_ena_cont
14837
14838#
14839# result is equal to the smallest normalized number in the selected precision
14840# if the precision is extended, this result could not have come from an
14841# underflow that rounded up.
14842#
14843fadd_may_unfl:
14844        mov.l           L_SCR3(%a6),%d1
14845        andi.b          &0xc0,%d1
14846        beq.w           fadd_normal             # yes; no underflow occurred
14847
14848        mov.l           0x4(%sp),%d1            # extract hi(man)
14849        cmpi.l          %d1,&0x80000000         # is hi(man) = 0x80000000?
14850        bne.w           fadd_normal             # no; no underflow occurred
14851
14852        tst.l           0x8(%sp)                # is lo(man) = 0x0?
14853        bne.w           fadd_normal             # no; no underflow occurred
14854
14855        btst            &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
14856        beq.w           fadd_normal             # no; no underflow occurred
14857
14858#
14859# ok, so now the result has a exponent equal to the smallest normalized
14860# exponent for the selected precision. also, the mantissa is equal to
14861# 0x8000000000000000 and this mantissa is the result of rounding non-zero
14862# g,r,s.
14863# now, we must determine whether the pre-rounded result was an underflow
14864# rounded "up" or a normalized number rounded "down".
14865# so, we do this be re-executing the add using RZ as the rounding mode and
14866# seeing if the new result is smaller or equal to the current result.
14867#
14868        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op into fp1
14869
14870        mov.l           L_SCR3(%a6),%d1
14871        andi.b          &0xc0,%d1               # keep rnd prec
14872        ori.b           &rz_mode*0x10,%d1       # insert rnd mode
14873        fmov.l          %d1,%fpcr               # set FPCR
14874        fmov.l          &0x0,%fpsr              # clear FPSR
14875
14876        fadd.x          FP_SCR0(%a6),%fp1       # execute add
14877
14878        fmov.l          &0x0,%fpcr              # clear FPCR
14879
14880        fabs.x          %fp0                    # compare absolute values
14881        fabs.x          %fp1
14882        fcmp.x          %fp0,%fp1               # is first result > second?
14883
14884        fbgt.w          fadd_unfl               # yes; it's an underflow
14885        bra.w           fadd_normal             # no; it's not an underflow
14886
14887##########################################################################
14888
14889#
14890# Add: inputs are not both normalized; what are they?
14891#
14892fadd_not_norm:
14893        mov.w           (tbl_fadd_op.b,%pc,%d1.w*2),%d1
14894        jmp             (tbl_fadd_op.b,%pc,%d1.w*1)
14895
14896        swbeg           &48
14897tbl_fadd_op:
14898        short           fadd_norm       - tbl_fadd_op # NORM + NORM
14899        short           fadd_zero_src   - tbl_fadd_op # NORM + ZERO
14900        short           fadd_inf_src    - tbl_fadd_op # NORM + INF
14901        short           fadd_res_qnan   - tbl_fadd_op # NORM + QNAN
14902        short           fadd_norm       - tbl_fadd_op # NORM + DENORM
14903        short           fadd_res_snan   - tbl_fadd_op # NORM + SNAN
14904        short           tbl_fadd_op     - tbl_fadd_op #
14905        short           tbl_fadd_op     - tbl_fadd_op #
14906
14907        short           fadd_zero_dst   - tbl_fadd_op # ZERO + NORM
14908        short           fadd_zero_2     - tbl_fadd_op # ZERO + ZERO
14909        short           fadd_inf_src    - tbl_fadd_op # ZERO + INF
14910        short           fadd_res_qnan   - tbl_fadd_op # NORM + QNAN
14911        short           fadd_zero_dst   - tbl_fadd_op # ZERO + DENORM
14912        short           fadd_res_snan   - tbl_fadd_op # NORM + SNAN
14913        short           tbl_fadd_op     - tbl_fadd_op #
14914        short           tbl_fadd_op     - tbl_fadd_op #
14915
14916        short           fadd_inf_dst    - tbl_fadd_op # INF + NORM
14917        short           fadd_inf_dst    - tbl_fadd_op # INF + ZERO
14918        short           fadd_inf_2      - tbl_fadd_op # INF + INF
14919        short           fadd_res_qnan   - tbl_fadd_op # NORM + QNAN
14920        short           fadd_inf_dst    - tbl_fadd_op # INF + DENORM
14921        short           fadd_res_snan   - tbl_fadd_op # NORM + SNAN
14922        short           tbl_fadd_op     - tbl_fadd_op #
14923        short           tbl_fadd_op     - tbl_fadd_op #
14924
14925        short           fadd_res_qnan   - tbl_fadd_op # QNAN + NORM
14926        short           fadd_res_qnan   - tbl_fadd_op # QNAN + ZERO
14927        short           fadd_res_qnan   - tbl_fadd_op # QNAN + INF
14928        short           fadd_res_qnan   - tbl_fadd_op # QNAN + QNAN
14929        short           fadd_res_qnan   - tbl_fadd_op # QNAN + DENORM
14930        short           fadd_res_snan   - tbl_fadd_op # QNAN + SNAN
14931        short           tbl_fadd_op     - tbl_fadd_op #
14932        short           tbl_fadd_op     - tbl_fadd_op #
14933
14934        short           fadd_norm       - tbl_fadd_op # DENORM + NORM
14935        short           fadd_zero_src   - tbl_fadd_op # DENORM + ZERO
14936        short           fadd_inf_src    - tbl_fadd_op # DENORM + INF
14937        short           fadd_res_qnan   - tbl_fadd_op # NORM + QNAN
14938        short           fadd_norm       - tbl_fadd_op # DENORM + DENORM
14939        short           fadd_res_snan   - tbl_fadd_op # NORM + SNAN
14940        short           tbl_fadd_op     - tbl_fadd_op #
14941        short           tbl_fadd_op     - tbl_fadd_op #
14942
14943        short           fadd_res_snan   - tbl_fadd_op # SNAN + NORM
14944        short           fadd_res_snan   - tbl_fadd_op # SNAN + ZERO
14945        short           fadd_res_snan   - tbl_fadd_op # SNAN + INF
14946        short           fadd_res_snan   - tbl_fadd_op # SNAN + QNAN
14947        short           fadd_res_snan   - tbl_fadd_op # SNAN + DENORM
14948        short           fadd_res_snan   - tbl_fadd_op # SNAN + SNAN
14949        short           tbl_fadd_op     - tbl_fadd_op #
14950        short           tbl_fadd_op     - tbl_fadd_op #
14951
14952fadd_res_qnan:
14953        bra.l           res_qnan
14954fadd_res_snan:
14955        bra.l           res_snan
14956
14957#
14958# both operands are ZEROes
14959#
14960fadd_zero_2:
14961        mov.b           SRC_EX(%a0),%d0         # are the signs opposite
14962        mov.b           DST_EX(%a1),%d1
14963        eor.b           %d0,%d1
14964        bmi.w           fadd_zero_2_chk_rm      # weed out (-ZERO)+(+ZERO)
14965
14966# the signs are the same. so determine whether they are positive or negative
14967# and return the appropriately signed zero.
14968        tst.b           %d0                     # are ZEROes positive or negative?
14969        bmi.b           fadd_zero_rm            # negative
14970        fmov.s          &0x00000000,%fp0        # return +ZERO
14971        mov.b           &z_bmask,FPSR_CC(%a6)   # set Z
14972        rts
14973
14974#
14975# the ZEROes have opposite signs:
14976# - Therefore, we return +ZERO if the rounding modes are RN,RZ, or RP.
14977# - -ZERO is returned in the case of RM.
14978#
14979fadd_zero_2_chk_rm:
14980        mov.b           3+L_SCR3(%a6),%d1
14981        andi.b          &0x30,%d1               # extract rnd mode
14982        cmpi.b          %d1,&rm_mode*0x10       # is rnd mode == RM?
14983        beq.b           fadd_zero_rm            # yes
14984        fmov.s          &0x00000000,%fp0        # return +ZERO
14985        mov.b           &z_bmask,FPSR_CC(%a6)   # set Z
14986        rts
14987
14988fadd_zero_rm:
14989        fmov.s          &0x80000000,%fp0        # return -ZERO
14990        mov.b           &neg_bmask+z_bmask,FPSR_CC(%a6) # set NEG/Z
14991        rts
14992
14993#
14994# one operand is a ZERO and the other is a DENORM or NORM. scale
14995# the DENORM or NORM and jump to the regular fadd routine.
14996#
14997fadd_zero_dst:
14998        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
14999        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
15000        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
15001        bsr.l           scale_to_zero_src       # scale the operand
15002        clr.w           FP_SCR1_EX(%a6)
15003        clr.l           FP_SCR1_HI(%a6)
15004        clr.l           FP_SCR1_LO(%a6)
15005        bra.w           fadd_zero_entry         # go execute fadd
15006
15007fadd_zero_src:
15008        mov.w           DST_EX(%a1),FP_SCR1_EX(%a6)
15009        mov.l           DST_HI(%a1),FP_SCR1_HI(%a6)
15010        mov.l           DST_LO(%a1),FP_SCR1_LO(%a6)
15011        bsr.l           scale_to_zero_dst       # scale the operand
15012        clr.w           FP_SCR0_EX(%a6)
15013        clr.l           FP_SCR0_HI(%a6)
15014        clr.l           FP_SCR0_LO(%a6)
15015        bra.w           fadd_zero_entry         # go execute fadd
15016
15017#
15018# both operands are INFs. an OPERR will result if the INFs have
15019# different signs. else, an INF of the same sign is returned
15020#
15021fadd_inf_2:
15022        mov.b           SRC_EX(%a0),%d0         # exclusive or the signs
15023        mov.b           DST_EX(%a1),%d1
15024        eor.b           %d1,%d0
15025        bmi.l           res_operr               # weed out (-INF)+(+INF)
15026
15027# ok, so it's not an OPERR. but, we do have to remember to return the
15028# src INF since that's where the 881/882 gets the j-bit from...
15029
15030#
15031# operands are INF and one of {ZERO, INF, DENORM, NORM}
15032#
15033fadd_inf_src:
15034        fmovm.x         SRC(%a0),&0x80          # return src INF
15035        tst.b           SRC_EX(%a0)             # is INF positive?
15036        bpl.b           fadd_inf_done           # yes; we're done
15037        mov.b           &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
15038        rts
15039
15040#
15041# operands are INF and one of {ZERO, INF, DENORM, NORM}
15042#
15043fadd_inf_dst:
15044        fmovm.x         DST(%a1),&0x80          # return dst INF
15045        tst.b           DST_EX(%a1)             # is INF positive?
15046        bpl.b           fadd_inf_done           # yes; we're done
15047        mov.b           &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
15048        rts
15049
15050fadd_inf_done:
15051        mov.b           &inf_bmask,FPSR_CC(%a6) # set INF
15052        rts
15053
15054#########################################################################
15055# XDEF **************************************************************** #
15056#       fsub(): emulates the fsub instruction                           #
15057#       fssub(): emulates the fssub instruction                         #
15058#       fdsub(): emulates the fdsub instruction                         #
15059#                                                                       #
15060# XREF **************************************************************** #
15061#       addsub_scaler2() - scale the operands so they won't take exc    #
15062#       ovf_res() - return default overflow result                      #
15063#       unf_res() - return default underflow result                     #
15064#       res_qnan() - set QNAN result                                    #
15065#       res_snan() - set SNAN result                                    #
15066#       res_operr() - set OPERR result                                  #
15067#       scale_to_zero_src() - set src operand exponent equal to zero    #
15068#       scale_to_zero_dst() - set dst operand exponent equal to zero    #
15069#                                                                       #
15070# INPUT *************************************************************** #
15071#       a0 = pointer to extended precision source operand               #
15072#       a1 = pointer to extended precision destination operand          #
15073#                                                                       #
15074# OUTPUT ************************************************************** #
15075#       fp0 = result                                                    #
15076#       fp1 = EXOP (if exception occurred)                              #
15077#                                                                       #
15078# ALGORITHM *********************************************************** #
15079#       Handle NANs, infinities, and zeroes as special cases. Divide    #
15080# norms into extended, single, and double precision.                    #
15081#       Do subtraction after scaling exponents such that exception won't#
15082# occur. Then, check result exponent to see if exception would have     #
15083# occurred. If so, return default result and maybe EXOP. Else, insert   #
15084# the correct result exponent and return. Set FPSR bits as appropriate. #
15085#                                                                       #
15086#########################################################################
15087
15088        global          fssub
15089fssub:
15090        andi.b          &0x30,%d0               # clear rnd prec
15091        ori.b           &s_mode*0x10,%d0        # insert sgl prec
15092        bra.b           fsub
15093
15094        global          fdsub
15095fdsub:
15096        andi.b          &0x30,%d0               # clear rnd prec
15097        ori.b           &d_mode*0x10,%d0        # insert dbl prec
15098
15099        global          fsub
15100fsub:
15101        mov.l           %d0,L_SCR3(%a6)         # store rnd info
15102
15103        clr.w           %d1
15104        mov.b           DTAG(%a6),%d1
15105        lsl.b           &0x3,%d1
15106        or.b            STAG(%a6),%d1           # combine src tags
15107
15108        bne.w           fsub_not_norm           # optimize on non-norm input
15109
15110#
15111# SUB: norms and denorms
15112#
15113fsub_norm:
15114        bsr.l           addsub_scaler2          # scale exponents
15115
15116fsub_zero_entry:
15117        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
15118
15119        fmov.l          &0x0,%fpsr              # clear FPSR
15120        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
15121
15122        fsub.x          FP_SCR0(%a6),%fp0       # execute subtract
15123
15124        fmov.l          &0x0,%fpcr              # clear FPCR
15125        fmov.l          %fpsr,%d1               # fetch INEX2, N, Z
15126
15127        or.l            %d1,USER_FPSR(%a6)      # save exc and ccode bits
15128
15129        fbeq.w          fsub_zero_exit          # if result zero, end now
15130
15131        mov.l           %d2,-(%sp)              # save d2
15132
15133        fmovm.x         &0x01,-(%sp)            # save result to stack
15134
15135        mov.w           2+L_SCR3(%a6),%d1
15136        lsr.b           &0x6,%d1
15137
15138        mov.w           (%sp),%d2               # fetch new exponent
15139        andi.l          &0x7fff,%d2             # strip sign
15140        sub.l           %d0,%d2                 # add scale factor
15141
15142        cmp.l           %d2,(tbl_fsub_ovfl.b,%pc,%d1.w*4) # is it an overflow?
15143        bge.b           fsub_ovfl               # yes
15144
15145        cmp.l           %d2,(tbl_fsub_unfl.b,%pc,%d1.w*4) # is it an underflow?
15146        blt.w           fsub_unfl               # yes
15147        beq.w           fsub_may_unfl           # maybe; go find out
15148
15149fsub_normal:
15150        mov.w           (%sp),%d1
15151        andi.w          &0x8000,%d1             # keep sign
15152        or.w            %d2,%d1                 # insert new exponent
15153        mov.w           %d1,(%sp)               # insert new exponent
15154
15155        fmovm.x         (%sp)+,&0x80            # return result in fp0
15156
15157        mov.l           (%sp)+,%d2              # restore d2
15158        rts
15159
15160fsub_zero_exit:
15161#       fmov.s          &0x00000000,%fp0        # return zero in fp0
15162        rts
15163
15164tbl_fsub_ovfl:
15165        long            0x7fff                  # ext ovfl
15166        long            0x407f                  # sgl ovfl
15167        long            0x43ff                  # dbl ovfl
15168
15169tbl_fsub_unfl:
15170        long            0x0000                  # ext unfl
15171        long            0x3f81                  # sgl unfl
15172        long            0x3c01                  # dbl unfl
15173
15174fsub_ovfl:
15175        or.l            &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
15176
15177        mov.b           FPCR_ENABLE(%a6),%d1
15178        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
15179        bne.b           fsub_ovfl_ena           # yes
15180
15181        add.l           &0xc,%sp
15182fsub_ovfl_dis:
15183        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
15184        sne             %d1                     # set sign param accordingly
15185        mov.l           L_SCR3(%a6),%d0         # pass prec:rnd
15186        bsr.l           ovf_res                 # calculate default result
15187        or.b            %d0,FPSR_CC(%a6)        # set INF,N if applicable
15188        fmovm.x         (%a0),&0x80             # return default result in fp0
15189        mov.l           (%sp)+,%d2              # restore d2
15190        rts
15191
15192fsub_ovfl_ena:
15193        mov.b           L_SCR3(%a6),%d1
15194        andi.b          &0xc0,%d1               # is precision extended?
15195        bne.b           fsub_ovfl_ena_sd        # no
15196
15197fsub_ovfl_ena_cont:
15198        mov.w           (%sp),%d1               # fetch {sgn,exp}
15199        andi.w          &0x8000,%d1             # keep sign
15200        subi.l          &0x6000,%d2             # subtract new bias
15201        andi.w          &0x7fff,%d2             # clear top bit
15202        or.w            %d2,%d1                 # concat sign,exp
15203        mov.w           %d1,(%sp)               # insert new exponent
15204
15205        fmovm.x         (%sp)+,&0x40            # return EXOP in fp1
15206        bra.b           fsub_ovfl_dis
15207
15208fsub_ovfl_ena_sd:
15209        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
15210
15211        mov.l           L_SCR3(%a6),%d1
15212        andi.b          &0x30,%d1               # clear rnd prec
15213        fmov.l          %d1,%fpcr               # set FPCR
15214
15215        fsub.x          FP_SCR0(%a6),%fp0       # execute subtract
15216
15217        fmov.l          &0x0,%fpcr              # clear FPCR
15218
15219        add.l           &0xc,%sp
15220        fmovm.x         &0x01,-(%sp)
15221        bra.b           fsub_ovfl_ena_cont
15222
15223fsub_unfl:
15224        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
15225
15226        add.l           &0xc,%sp
15227
15228        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
15229
15230        fmov.l          &rz_mode*0x10,%fpcr     # set FPCR
15231        fmov.l          &0x0,%fpsr              # clear FPSR
15232
15233        fsub.x          FP_SCR0(%a6),%fp0       # execute subtract
15234
15235        fmov.l          &0x0,%fpcr              # clear FPCR
15236        fmov.l          %fpsr,%d1               # save status
15237
15238        or.l            %d1,USER_FPSR(%a6)
15239
15240        mov.b           FPCR_ENABLE(%a6),%d1
15241        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
15242        bne.b           fsub_unfl_ena           # yes
15243
15244fsub_unfl_dis:
15245        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
15246
15247        lea             FP_SCR0(%a6),%a0        # pass: result addr
15248        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
15249        bsr.l           unf_res                 # calculate default result
15250        or.b            %d0,FPSR_CC(%a6)        # 'Z' may have been set
15251        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
15252        mov.l           (%sp)+,%d2              # restore d2
15253        rts
15254
15255fsub_unfl_ena:
15256        fmovm.x         FP_SCR1(%a6),&0x40
15257
15258        mov.l           L_SCR3(%a6),%d1
15259        andi.b          &0xc0,%d1               # is precision extended?
15260        bne.b           fsub_unfl_ena_sd        # no
15261
15262        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
15263
15264fsub_unfl_ena_cont:
15265        fmov.l          &0x0,%fpsr              # clear FPSR
15266
15267        fsub.x          FP_SCR0(%a6),%fp1       # execute subtract
15268
15269        fmov.l          &0x0,%fpcr              # clear FPCR
15270
15271        fmovm.x         &0x40,FP_SCR0(%a6)      # store result to stack
15272        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
15273        mov.l           %d1,%d2                 # make a copy
15274        andi.l          &0x7fff,%d1             # strip sign
15275        andi.w          &0x8000,%d2             # keep old sign
15276        sub.l           %d0,%d1                 # add scale factor
15277        addi.l          &0x6000,%d1             # subtract new bias
15278        andi.w          &0x7fff,%d1             # clear top bit
15279        or.w            %d2,%d1                 # concat sgn,exp
15280        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
15281        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
15282        bra.w           fsub_unfl_dis
15283
15284fsub_unfl_ena_sd:
15285        mov.l           L_SCR3(%a6),%d1
15286        andi.b          &0x30,%d1               # clear rnd prec
15287        fmov.l          %d1,%fpcr               # set FPCR
15288
15289        bra.b           fsub_unfl_ena_cont
15290
15291#
15292# result is equal to the smallest normalized number in the selected precision
15293# if the precision is extended, this result could not have come from an
15294# underflow that rounded up.
15295#
15296fsub_may_unfl:
15297        mov.l           L_SCR3(%a6),%d1
15298        andi.b          &0xc0,%d1               # fetch rnd prec
15299        beq.w           fsub_normal             # yes; no underflow occurred
15300
15301        mov.l           0x4(%sp),%d1
15302        cmpi.l          %d1,&0x80000000         # is hi(man) = 0x80000000?
15303        bne.w           fsub_normal             # no; no underflow occurred
15304
15305        tst.l           0x8(%sp)                # is lo(man) = 0x0?
15306        bne.w           fsub_normal             # no; no underflow occurred
15307
15308        btst            &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
15309        beq.w           fsub_normal             # no; no underflow occurred
15310
15311#
15312# ok, so now the result has a exponent equal to the smallest normalized
15313# exponent for the selected precision. also, the mantissa is equal to
15314# 0x8000000000000000 and this mantissa is the result of rounding non-zero
15315# g,r,s.
15316# now, we must determine whether the pre-rounded result was an underflow
15317# rounded "up" or a normalized number rounded "down".
15318# so, we do this be re-executing the add using RZ as the rounding mode and
15319# seeing if the new result is smaller or equal to the current result.
15320#
15321        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op into fp1
15322
15323        mov.l           L_SCR3(%a6),%d1
15324        andi.b          &0xc0,%d1               # keep rnd prec
15325        ori.b           &rz_mode*0x10,%d1       # insert rnd mode
15326        fmov.l          %d1,%fpcr               # set FPCR
15327        fmov.l          &0x0,%fpsr              # clear FPSR
15328
15329        fsub.x          FP_SCR0(%a6),%fp1       # execute subtract
15330
15331        fmov.l          &0x0,%fpcr              # clear FPCR
15332
15333        fabs.x          %fp0                    # compare absolute values
15334        fabs.x          %fp1
15335        fcmp.x          %fp0,%fp1               # is first result > second?
15336
15337        fbgt.w          fsub_unfl               # yes; it's an underflow
15338        bra.w           fsub_normal             # no; it's not an underflow
15339
15340##########################################################################
15341
15342#
15343# Sub: inputs are not both normalized; what are they?
15344#
15345fsub_not_norm:
15346        mov.w           (tbl_fsub_op.b,%pc,%d1.w*2),%d1
15347        jmp             (tbl_fsub_op.b,%pc,%d1.w*1)
15348
15349        swbeg           &48
15350tbl_fsub_op:
15351        short           fsub_norm       - tbl_fsub_op # NORM - NORM
15352        short           fsub_zero_src   - tbl_fsub_op # NORM - ZERO
15353        short           fsub_inf_src    - tbl_fsub_op # NORM - INF
15354        short           fsub_res_qnan   - tbl_fsub_op # NORM - QNAN
15355        short           fsub_norm       - tbl_fsub_op # NORM - DENORM
15356        short           fsub_res_snan   - tbl_fsub_op # NORM - SNAN
15357        short           tbl_fsub_op     - tbl_fsub_op #
15358        short           tbl_fsub_op     - tbl_fsub_op #
15359
15360        short           fsub_zero_dst   - tbl_fsub_op # ZERO - NORM
15361        short           fsub_zero_2     - tbl_fsub_op # ZERO - ZERO
15362        short           fsub_inf_src    - tbl_fsub_op # ZERO - INF
15363        short           fsub_res_qnan   - tbl_fsub_op # NORM - QNAN
15364        short           fsub_zero_dst   - tbl_fsub_op # ZERO - DENORM
15365        short           fsub_res_snan   - tbl_fsub_op # NORM - SNAN
15366        short           tbl_fsub_op     - tbl_fsub_op #
15367        short           tbl_fsub_op     - tbl_fsub_op #
15368
15369        short           fsub_inf_dst    - tbl_fsub_op # INF - NORM
15370        short           fsub_inf_dst    - tbl_fsub_op # INF - ZERO
15371        short           fsub_inf_2      - tbl_fsub_op # INF - INF
15372        short           fsub_res_qnan   - tbl_fsub_op # NORM - QNAN
15373        short           fsub_inf_dst    - tbl_fsub_op # INF - DENORM
15374        short           fsub_res_snan   - tbl_fsub_op # NORM - SNAN
15375        short           tbl_fsub_op     - tbl_fsub_op #
15376        short           tbl_fsub_op     - tbl_fsub_op #
15377
15378        short           fsub_res_qnan   - tbl_fsub_op # QNAN - NORM
15379        short           fsub_res_qnan   - tbl_fsub_op # QNAN - ZERO
15380        short           fsub_res_qnan   - tbl_fsub_op # QNAN - INF
15381        short           fsub_res_qnan   - tbl_fsub_op # QNAN - QNAN
15382        short           fsub_res_qnan   - tbl_fsub_op # QNAN - DENORM
15383        short           fsub_res_snan   - tbl_fsub_op # QNAN - SNAN
15384        short           tbl_fsub_op     - tbl_fsub_op #
15385        short           tbl_fsub_op     - tbl_fsub_op #
15386
15387        short           fsub_norm       - tbl_fsub_op # DENORM - NORM
15388        short           fsub_zero_src   - tbl_fsub_op # DENORM - ZERO
15389        short           fsub_inf_src    - tbl_fsub_op # DENORM - INF
15390        short           fsub_res_qnan   - tbl_fsub_op # NORM - QNAN
15391        short           fsub_norm       - tbl_fsub_op # DENORM - DENORM
15392        short           fsub_res_snan   - tbl_fsub_op # NORM - SNAN
15393        short           tbl_fsub_op     - tbl_fsub_op #
15394        short           tbl_fsub_op     - tbl_fsub_op #
15395
15396        short           fsub_res_snan   - tbl_fsub_op # SNAN - NORM
15397        short           fsub_res_snan   - tbl_fsub_op # SNAN - ZERO
15398        short           fsub_res_snan   - tbl_fsub_op # SNAN - INF
15399        short           fsub_res_snan   - tbl_fsub_op # SNAN - QNAN
15400        short           fsub_res_snan   - tbl_fsub_op # SNAN - DENORM
15401        short           fsub_res_snan   - tbl_fsub_op # SNAN - SNAN
15402        short           tbl_fsub_op     - tbl_fsub_op #
15403        short           tbl_fsub_op     - tbl_fsub_op #
15404
15405fsub_res_qnan:
15406        bra.l           res_qnan
15407fsub_res_snan:
15408        bra.l           res_snan
15409
15410#
15411# both operands are ZEROes
15412#
15413fsub_zero_2:
15414        mov.b           SRC_EX(%a0),%d0
15415        mov.b           DST_EX(%a1),%d1
15416        eor.b           %d1,%d0
15417        bpl.b           fsub_zero_2_chk_rm
15418
15419# the signs are opposite, so, return a ZERO w/ the sign of the dst ZERO
15420        tst.b           %d0                     # is dst negative?
15421        bmi.b           fsub_zero_2_rm          # yes
15422        fmov.s          &0x00000000,%fp0        # no; return +ZERO
15423        mov.b           &z_bmask,FPSR_CC(%a6)   # set Z
15424        rts
15425
15426#
15427# the ZEROes have the same signs:
15428# - Therefore, we return +ZERO if the rounding mode is RN,RZ, or RP
15429# - -ZERO is returned in the case of RM.
15430#
15431fsub_zero_2_chk_rm:
15432        mov.b           3+L_SCR3(%a6),%d1
15433        andi.b          &0x30,%d1               # extract rnd mode
15434        cmpi.b          %d1,&rm_mode*0x10       # is rnd mode = RM?
15435        beq.b           fsub_zero_2_rm          # yes
15436        fmov.s          &0x00000000,%fp0        # no; return +ZERO
15437        mov.b           &z_bmask,FPSR_CC(%a6)   # set Z
15438        rts
15439
15440fsub_zero_2_rm:
15441        fmov.s          &0x80000000,%fp0        # return -ZERO
15442        mov.b           &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/NEG
15443        rts
15444
15445#
15446# one operand is a ZERO and the other is a DENORM or a NORM.
15447# scale the DENORM or NORM and jump to the regular fsub routine.
15448#
15449fsub_zero_dst:
15450        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
15451        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
15452        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
15453        bsr.l           scale_to_zero_src       # scale the operand
15454        clr.w           FP_SCR1_EX(%a6)
15455        clr.l           FP_SCR1_HI(%a6)
15456        clr.l           FP_SCR1_LO(%a6)
15457        bra.w           fsub_zero_entry         # go execute fsub
15458
15459fsub_zero_src:
15460        mov.w           DST_EX(%a1),FP_SCR1_EX(%a6)
15461        mov.l           DST_HI(%a1),FP_SCR1_HI(%a6)
15462        mov.l           DST_LO(%a1),FP_SCR1_LO(%a6)
15463        bsr.l           scale_to_zero_dst       # scale the operand
15464        clr.w           FP_SCR0_EX(%a6)
15465        clr.l           FP_SCR0_HI(%a6)
15466        clr.l           FP_SCR0_LO(%a6)
15467        bra.w           fsub_zero_entry         # go execute fsub
15468
15469#
15470# both operands are INFs. an OPERR will result if the INFs have the
15471# same signs. else,
15472#
15473fsub_inf_2:
15474        mov.b           SRC_EX(%a0),%d0         # exclusive or the signs
15475        mov.b           DST_EX(%a1),%d1
15476        eor.b           %d1,%d0
15477        bpl.l           res_operr               # weed out (-INF)+(+INF)
15478
15479# ok, so it's not an OPERR. but we do have to remember to return
15480# the src INF since that's where the 881/882 gets the j-bit.
15481
15482fsub_inf_src:
15483        fmovm.x         SRC(%a0),&0x80          # return src INF
15484        fneg.x          %fp0                    # invert sign
15485        fbge.w          fsub_inf_done           # sign is now positive
15486        mov.b           &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
15487        rts
15488
15489fsub_inf_dst:
15490        fmovm.x         DST(%a1),&0x80          # return dst INF
15491        tst.b           DST_EX(%a1)             # is INF negative?
15492        bpl.b           fsub_inf_done           # no
15493        mov.b           &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
15494        rts
15495
15496fsub_inf_done:
15497        mov.b           &inf_bmask,FPSR_CC(%a6) # set INF
15498        rts
15499
15500#########################################################################
15501# XDEF **************************************************************** #
15502#       fsqrt(): emulates the fsqrt instruction                         #
15503#       fssqrt(): emulates the fssqrt instruction                       #
15504#       fdsqrt(): emulates the fdsqrt instruction                       #
15505#                                                                       #
15506# XREF **************************************************************** #
15507#       scale_sqrt() - scale the source operand                         #
15508#       unf_res() - return default underflow result                     #
15509#       ovf_res() - return default overflow result                      #
15510#       res_qnan_1op() - return QNAN result                             #
15511#       res_snan_1op() - return SNAN result                             #
15512#                                                                       #
15513# INPUT *************************************************************** #
15514#       a0 = pointer to extended precision source operand               #
15515#       d0  rnd prec,mode                                               #
15516#                                                                       #
15517# OUTPUT ************************************************************** #
15518#       fp0 = result                                                    #
15519#       fp1 = EXOP (if exception occurred)                              #
15520#                                                                       #
15521# ALGORITHM *********************************************************** #
15522#       Handle NANs, infinities, and zeroes as special cases. Divide    #
15523# norms/denorms into ext/sgl/dbl precision.                             #
15524#       For norms/denorms, scale the exponents such that a sqrt         #
15525# instruction won't cause an exception. Use the regular fsqrt to        #
15526# compute a result. Check if the regular operands would have taken      #
15527# an exception. If so, return the default overflow/underflow result     #
15528# and return the EXOP if exceptions are enabled. Else, scale the        #
15529# result operand to the proper exponent.                                #
15530#                                                                       #
15531#########################################################################
15532
15533        global          fssqrt
15534fssqrt:
15535        andi.b          &0x30,%d0               # clear rnd prec
15536        ori.b           &s_mode*0x10,%d0        # insert sgl precision
15537        bra.b           fsqrt
15538
15539        global          fdsqrt
15540fdsqrt:
15541        andi.b          &0x30,%d0               # clear rnd prec
15542        ori.b           &d_mode*0x10,%d0        # insert dbl precision
15543
15544        global          fsqrt
15545fsqrt:
15546        mov.l           %d0,L_SCR3(%a6)         # store rnd info
15547        clr.w           %d1
15548        mov.b           STAG(%a6),%d1
15549        bne.w           fsqrt_not_norm          # optimize on non-norm input
15550
15551#
15552# SQUARE ROOT: norms and denorms ONLY!
15553#
15554fsqrt_norm:
15555        tst.b           SRC_EX(%a0)             # is operand negative?
15556        bmi.l           res_operr               # yes
15557
15558        andi.b          &0xc0,%d0               # is precision extended?
15559        bne.b           fsqrt_not_ext           # no; go handle sgl or dbl
15560
15561        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
15562        fmov.l          &0x0,%fpsr              # clear FPSR
15563
15564        fsqrt.x         (%a0),%fp0              # execute square root
15565
15566        fmov.l          %fpsr,%d1
15567        or.l            %d1,USER_FPSR(%a6)      # set N,INEX
15568
15569        rts
15570
15571fsqrt_denorm:
15572        tst.b           SRC_EX(%a0)             # is operand negative?
15573        bmi.l           res_operr               # yes
15574
15575        andi.b          &0xc0,%d0               # is precision extended?
15576        bne.b           fsqrt_not_ext           # no; go handle sgl or dbl
15577
15578        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
15579        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
15580        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
15581
15582        bsr.l           scale_sqrt              # calculate scale factor
15583
15584        bra.w           fsqrt_sd_normal
15585
15586#
15587# operand is either single or double
15588#
15589fsqrt_not_ext:
15590        cmpi.b          %d0,&s_mode*0x10        # separate sgl/dbl prec
15591        bne.w           fsqrt_dbl
15592
15593#
15594# operand is to be rounded to single precision
15595#
15596fsqrt_sgl:
15597        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
15598        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
15599        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
15600
15601        bsr.l           scale_sqrt              # calculate scale factor
15602
15603        cmpi.l          %d0,&0x3fff-0x3f81      # will move in underflow?
15604        beq.w           fsqrt_sd_may_unfl
15605        bgt.w           fsqrt_sd_unfl           # yes; go handle underflow
15606        cmpi.l          %d0,&0x3fff-0x407f      # will move in overflow?
15607        beq.w           fsqrt_sd_may_ovfl       # maybe; go check
15608        blt.w           fsqrt_sd_ovfl           # yes; go handle overflow
15609
15610#
15611# operand will NOT overflow or underflow when moved in to the fp reg file
15612#
15613fsqrt_sd_normal:
15614        fmov.l          &0x0,%fpsr              # clear FPSR
15615        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
15616
15617        fsqrt.x         FP_SCR0(%a6),%fp0       # perform absolute
15618
15619        fmov.l          %fpsr,%d1               # save FPSR
15620        fmov.l          &0x0,%fpcr              # clear FPCR
15621
15622        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
15623
15624fsqrt_sd_normal_exit:
15625        mov.l           %d2,-(%sp)              # save d2
15626        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
15627        mov.w           FP_SCR0_EX(%a6),%d1     # load sgn,exp
15628        mov.l           %d1,%d2                 # make a copy
15629        andi.l          &0x7fff,%d1             # strip sign
15630        sub.l           %d0,%d1                 # add scale factor
15631        andi.w          &0x8000,%d2             # keep old sign
15632        or.w            %d1,%d2                 # concat old sign,new exp
15633        mov.w           %d2,FP_SCR0_EX(%a6)     # insert new exponent
15634        mov.l           (%sp)+,%d2              # restore d2
15635        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
15636        rts
15637
15638#
15639# operand is to be rounded to double precision
15640#
15641fsqrt_dbl:
15642        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
15643        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
15644        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
15645
15646        bsr.l           scale_sqrt              # calculate scale factor
15647
15648        cmpi.l          %d0,&0x3fff-0x3c01      # will move in underflow?
15649        beq.w           fsqrt_sd_may_unfl
15650        bgt.b           fsqrt_sd_unfl           # yes; go handle underflow
15651        cmpi.l          %d0,&0x3fff-0x43ff      # will move in overflow?
15652        beq.w           fsqrt_sd_may_ovfl       # maybe; go check
15653        blt.w           fsqrt_sd_ovfl           # yes; go handle overflow
15654        bra.w           fsqrt_sd_normal         # no; ho handle normalized op
15655
15656# we're on the line here and the distinguising characteristic is whether
15657# the exponent is 3fff or 3ffe. if it's 3ffe, then it's a safe number
15658# elsewise fall through to underflow.
15659fsqrt_sd_may_unfl:
15660        btst            &0x0,1+FP_SCR0_EX(%a6)  # is exponent 0x3fff?
15661        bne.w           fsqrt_sd_normal         # yes, so no underflow
15662
15663#
15664# operand WILL underflow when moved in to the fp register file
15665#
15666fsqrt_sd_unfl:
15667        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
15668
15669        fmov.l          &rz_mode*0x10,%fpcr     # set FPCR
15670        fmov.l          &0x0,%fpsr              # clear FPSR
15671
15672        fsqrt.x         FP_SCR0(%a6),%fp0       # execute square root
15673
15674        fmov.l          %fpsr,%d1               # save status
15675        fmov.l          &0x0,%fpcr              # clear FPCR
15676
15677        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
15678
15679# if underflow or inexact is enabled, go calculate EXOP first.
15680        mov.b           FPCR_ENABLE(%a6),%d1
15681        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
15682        bne.b           fsqrt_sd_unfl_ena       # yes
15683
15684fsqrt_sd_unfl_dis:
15685        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
15686
15687        lea             FP_SCR0(%a6),%a0        # pass: result addr
15688        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
15689        bsr.l           unf_res                 # calculate default result
15690        or.b            %d0,FPSR_CC(%a6)        # set possible 'Z' ccode
15691        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
15692        rts
15693
15694#
15695# operand will underflow AND underflow is enabled.
15696# Therefore, we must return the result rounded to extended precision.
15697#
15698fsqrt_sd_unfl_ena:
15699        mov.l           FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
15700        mov.l           FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
15701        mov.w           FP_SCR0_EX(%a6),%d1     # load current exponent
15702
15703        mov.l           %d2,-(%sp)              # save d2
15704        mov.l           %d1,%d2                 # make a copy
15705        andi.l          &0x7fff,%d1             # strip sign
15706        andi.w          &0x8000,%d2             # keep old sign
15707        sub.l           %d0,%d1                 # subtract scale factor
15708        addi.l          &0x6000,%d1             # add new bias
15709        andi.w          &0x7fff,%d1
15710        or.w            %d2,%d1                 # concat new sign,new exp
15711        mov.w           %d1,FP_SCR1_EX(%a6)     # insert new exp
15712        fmovm.x         FP_SCR1(%a6),&0x40      # return EXOP in fp1
15713        mov.l           (%sp)+,%d2              # restore d2
15714        bra.b           fsqrt_sd_unfl_dis
15715
15716#
15717# operand WILL overflow.
15718#
15719fsqrt_sd_ovfl:
15720        fmov.l          &0x0,%fpsr              # clear FPSR
15721        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
15722
15723        fsqrt.x         FP_SCR0(%a6),%fp0       # perform square root
15724
15725        fmov.l          &0x0,%fpcr              # clear FPCR
15726        fmov.l          %fpsr,%d1               # save FPSR
15727
15728        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
15729
15730fsqrt_sd_ovfl_tst:
15731        or.l            &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
15732
15733        mov.b           FPCR_ENABLE(%a6),%d1
15734        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
15735        bne.b           fsqrt_sd_ovfl_ena       # yes
15736
15737#
15738# OVFL is not enabled; therefore, we must create the default result by
15739# calling ovf_res().
15740#
15741fsqrt_sd_ovfl_dis:
15742        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
15743        sne             %d1                     # set sign param accordingly
15744        mov.l           L_SCR3(%a6),%d0         # pass: prec,mode
15745        bsr.l           ovf_res                 # calculate default result
15746        or.b            %d0,FPSR_CC(%a6)        # set INF,N if applicable
15747        fmovm.x         (%a0),&0x80             # return default result in fp0
15748        rts
15749
15750#
15751# OVFL is enabled.
15752# the INEX2 bit has already been updated by the round to the correct precision.
15753# now, round to extended(and don't alter the FPSR).
15754#
15755fsqrt_sd_ovfl_ena:
15756        mov.l           %d2,-(%sp)              # save d2
15757        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
15758        mov.l           %d1,%d2                 # make a copy
15759        andi.l          &0x7fff,%d1             # strip sign
15760        andi.w          &0x8000,%d2             # keep old sign
15761        sub.l           %d0,%d1                 # add scale factor
15762        subi.l          &0x6000,%d1             # subtract bias
15763        andi.w          &0x7fff,%d1
15764        or.w            %d2,%d1                 # concat sign,exp
15765        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
15766        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
15767        mov.l           (%sp)+,%d2              # restore d2
15768        bra.b           fsqrt_sd_ovfl_dis
15769
15770#
15771# the move in MAY underflow. so...
15772#
15773fsqrt_sd_may_ovfl:
15774        btst            &0x0,1+FP_SCR0_EX(%a6)  # is exponent 0x3fff?
15775        bne.w           fsqrt_sd_ovfl           # yes, so overflow
15776
15777        fmov.l          &0x0,%fpsr              # clear FPSR
15778        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
15779
15780        fsqrt.x         FP_SCR0(%a6),%fp0       # perform absolute
15781
15782        fmov.l          %fpsr,%d1               # save status
15783        fmov.l          &0x0,%fpcr              # clear FPCR
15784
15785        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
15786
15787        fmov.x          %fp0,%fp1               # make a copy of result
15788        fcmp.b          %fp1,&0x1               # is |result| >= 1.b?
15789        fbge.w          fsqrt_sd_ovfl_tst       # yes; overflow has occurred
15790
15791# no, it didn't overflow; we have correct result
15792        bra.w           fsqrt_sd_normal_exit
15793
15794##########################################################################
15795
15796#
15797# input is not normalized; what is it?
15798#
15799fsqrt_not_norm:
15800        cmpi.b          %d1,&DENORM             # weed out DENORM
15801        beq.w           fsqrt_denorm
15802        cmpi.b          %d1,&ZERO               # weed out ZERO
15803        beq.b           fsqrt_zero
15804        cmpi.b          %d1,&INF                # weed out INF
15805        beq.b           fsqrt_inf
15806        cmpi.b          %d1,&SNAN               # weed out SNAN
15807        beq.l           res_snan_1op
15808        bra.l           res_qnan_1op
15809
15810#
15811#       fsqrt(+0) = +0
15812#       fsqrt(-0) = -0
15813#       fsqrt(+INF) = +INF
15814#       fsqrt(-INF) = OPERR
15815#
15816fsqrt_zero:
15817        tst.b           SRC_EX(%a0)             # is ZERO positive or negative?
15818        bmi.b           fsqrt_zero_m            # negative
15819fsqrt_zero_p:
15820        fmov.s          &0x00000000,%fp0        # return +ZERO
15821        mov.b           &z_bmask,FPSR_CC(%a6)   # set 'Z' ccode bit
15822        rts
15823fsqrt_zero_m:
15824        fmov.s          &0x80000000,%fp0        # return -ZERO
15825        mov.b           &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
15826        rts
15827
15828fsqrt_inf:
15829        tst.b           SRC_EX(%a0)             # is INF positive or negative?
15830        bmi.l           res_operr               # negative
15831fsqrt_inf_p:
15832        fmovm.x         SRC(%a0),&0x80          # return +INF in fp0
15833        mov.b           &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
15834        rts
15835
15836##########################################################################
15837
15838#########################################################################
15839# XDEF **************************************************************** #
15840#       addsub_scaler2(): scale inputs to fadd/fsub such that no        #
15841#                         OVFL/UNFL exceptions will result              #
15842#                                                                       #
15843# XREF **************************************************************** #
15844#       norm() - normalize mantissa after adjusting exponent            #
15845#                                                                       #
15846# INPUT *************************************************************** #
15847#       FP_SRC(a6) = fp op1(src)                                        #
15848#       FP_DST(a6) = fp op2(dst)                                        #
15849#                                                                       #
15850# OUTPUT ************************************************************** #
15851#       FP_SRC(a6) = fp op1 scaled(src)                                 #
15852#       FP_DST(a6) = fp op2 scaled(dst)                                 #
15853#       d0         = scale amount                                       #
15854#                                                                       #
15855# ALGORITHM *********************************************************** #
15856#       If the DST exponent is > the SRC exponent, set the DST exponent #
15857# equal to 0x3fff and scale the SRC exponent by the value that the      #
15858# DST exponent was scaled by. If the SRC exponent is greater or equal,  #
15859# do the opposite. Return this scale factor in d0.                      #
15860#       If the two exponents differ by > the number of mantissa bits    #
15861# plus two, then set the smallest exponent to a very small value as a   #
15862# quick shortcut.                                                       #
15863#                                                                       #
15864#########################################################################
15865
15866        global          addsub_scaler2
15867addsub_scaler2:
15868        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
15869        mov.l           DST_HI(%a1),FP_SCR1_HI(%a6)
15870        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
15871        mov.l           DST_LO(%a1),FP_SCR1_LO(%a6)
15872        mov.w           SRC_EX(%a0),%d0
15873        mov.w           DST_EX(%a1),%d1
15874        mov.w           %d0,FP_SCR0_EX(%a6)
15875        mov.w           %d1,FP_SCR1_EX(%a6)
15876
15877        andi.w          &0x7fff,%d0
15878        andi.w          &0x7fff,%d1
15879        mov.w           %d0,L_SCR1(%a6)         # store src exponent
15880        mov.w           %d1,2+L_SCR1(%a6)       # store dst exponent
15881
15882        cmp.w           %d0, %d1                # is src exp >= dst exp?
15883        bge.l           src_exp_ge2
15884
15885# dst exp is >  src exp; scale dst to exp = 0x3fff
15886dst_exp_gt2:
15887        bsr.l           scale_to_zero_dst
15888        mov.l           %d0,-(%sp)              # save scale factor
15889
15890        cmpi.b          STAG(%a6),&DENORM       # is dst denormalized?
15891        bne.b           cmpexp12
15892
15893        lea             FP_SCR0(%a6),%a0
15894        bsr.l           norm                    # normalize the denorm; result is new exp
15895        neg.w           %d0                     # new exp = -(shft val)
15896        mov.w           %d0,L_SCR1(%a6)         # inset new exp
15897
15898cmpexp12:
15899        mov.w           2+L_SCR1(%a6),%d0
15900        subi.w          &mantissalen+2,%d0      # subtract mantissalen+2 from larger exp
15901
15902        cmp.w           %d0,L_SCR1(%a6)         # is difference >= len(mantissa)+2?
15903        bge.b           quick_scale12
15904
15905        mov.w           L_SCR1(%a6),%d0
15906        add.w           0x2(%sp),%d0            # scale src exponent by scale factor
15907        mov.w           FP_SCR0_EX(%a6),%d1
15908        and.w           &0x8000,%d1
15909        or.w            %d1,%d0                 # concat {sgn,new exp}
15910        mov.w           %d0,FP_SCR0_EX(%a6)     # insert new dst exponent
15911
15912        mov.l           (%sp)+,%d0              # return SCALE factor
15913        rts
15914
15915quick_scale12:
15916        andi.w          &0x8000,FP_SCR0_EX(%a6) # zero src exponent
15917        bset            &0x0,1+FP_SCR0_EX(%a6)  # set exp = 1
15918
15919        mov.l           (%sp)+,%d0              # return SCALE factor
15920        rts
15921
15922# src exp is >= dst exp; scale src to exp = 0x3fff
15923src_exp_ge2:
15924        bsr.l           scale_to_zero_src
15925        mov.l           %d0,-(%sp)              # save scale factor
15926
15927        cmpi.b          DTAG(%a6),&DENORM       # is dst denormalized?
15928        bne.b           cmpexp22
15929        lea             FP_SCR1(%a6),%a0
15930        bsr.l           norm                    # normalize the denorm; result is new exp
15931        neg.w           %d0                     # new exp = -(shft val)
15932        mov.w           %d0,2+L_SCR1(%a6)       # inset new exp
15933
15934cmpexp22:
15935        mov.w           L_SCR1(%a6),%d0
15936        subi.w          &mantissalen+2,%d0      # subtract mantissalen+2 from larger exp
15937
15938        cmp.w           %d0,2+L_SCR1(%a6)       # is difference >= len(mantissa)+2?
15939        bge.b           quick_scale22
15940
15941        mov.w           2+L_SCR1(%a6),%d0
15942        add.w           0x2(%sp),%d0            # scale dst exponent by scale factor
15943        mov.w           FP_SCR1_EX(%a6),%d1
15944        andi.w          &0x8000,%d1
15945        or.w            %d1,%d0                 # concat {sgn,new exp}
15946        mov.w           %d0,FP_SCR1_EX(%a6)     # insert new dst exponent
15947
15948        mov.l           (%sp)+,%d0              # return SCALE factor
15949        rts
15950
15951quick_scale22:
15952        andi.w          &0x8000,FP_SCR1_EX(%a6) # zero dst exponent
15953        bset            &0x0,1+FP_SCR1_EX(%a6)  # set exp = 1
15954
15955        mov.l           (%sp)+,%d0              # return SCALE factor
15956        rts
15957
15958##########################################################################
15959
15960#########################################################################
15961# XDEF **************************************************************** #
15962#       scale_to_zero_src(): scale the exponent of extended precision   #
15963#                            value at FP_SCR0(a6).                      #
15964#                                                                       #
15965# XREF **************************************************************** #
15966#       norm() - normalize the mantissa if the operand was a DENORM     #
15967#                                                                       #
15968# INPUT *************************************************************** #
15969#       FP_SCR0(a6) = extended precision operand to be scaled           #
15970#                                                                       #
15971# OUTPUT ************************************************************** #
15972#       FP_SCR0(a6) = scaled extended precision operand                 #
15973#       d0          = scale value                                       #
15974#                                                                       #
15975# ALGORITHM *********************************************************** #
15976#       Set the exponent of the input operand to 0x3fff. Save the value #
15977# of the difference between the original and new exponent. Then,        #
15978# normalize the operand if it was a DENORM. Add this normalization      #
15979# value to the previous value. Return the result.                       #
15980#                                                                       #
15981#########################################################################
15982
15983        global          scale_to_zero_src
15984scale_to_zero_src:
15985        mov.w           FP_SCR0_EX(%a6),%d1     # extract operand's {sgn,exp}
15986        mov.w           %d1,%d0                 # make a copy
15987
15988        andi.l          &0x7fff,%d1             # extract operand's exponent
15989
15990        andi.w          &0x8000,%d0             # extract operand's sgn
15991        or.w            &0x3fff,%d0             # insert new operand's exponent(=0)
15992
15993        mov.w           %d0,FP_SCR0_EX(%a6)     # insert biased exponent
15994
15995        cmpi.b          STAG(%a6),&DENORM       # is operand normalized?
15996        beq.b           stzs_denorm             # normalize the DENORM
15997
15998stzs_norm:
15999        mov.l           &0x3fff,%d0
16000        sub.l           %d1,%d0                 # scale = BIAS + (-exp)
16001
16002        rts
16003
16004stzs_denorm:
16005        lea             FP_SCR0(%a6),%a0        # pass ptr to src op
16006        bsr.l           norm                    # normalize denorm
16007        neg.l           %d0                     # new exponent = -(shft val)
16008        mov.l           %d0,%d1                 # prepare for op_norm call
16009        bra.b           stzs_norm               # finish scaling
16010
16011###
16012
16013#########################################################################
16014# XDEF **************************************************************** #
16015#       scale_sqrt(): scale the input operand exponent so a subsequent  #
16016#                     fsqrt operation won't take an exception.          #
16017#                                                                       #
16018# XREF **************************************************************** #
16019#       norm() - normalize the mantissa if the operand was a DENORM     #
16020#                                                                       #
16021# INPUT *************************************************************** #
16022#       FP_SCR0(a6) = extended precision operand to be scaled           #
16023#                                                                       #
16024# OUTPUT ************************************************************** #
16025#       FP_SCR0(a6) = scaled extended precision operand                 #
16026#       d0          = scale value                                       #
16027#                                                                       #
16028# ALGORITHM *********************************************************** #
16029#       If the input operand is a DENORM, normalize it.                 #
16030#       If the exponent of the input operand is even, set the exponent  #
16031# to 0x3ffe and return a scale factor of "(exp-0x3ffe)/2". If the       #
16032# exponent of the input operand is off, set the exponent to ox3fff and  #
16033# return a scale factor of "(exp-0x3fff)/2".                            #
16034#                                                                       #
16035#########################################################################
16036
16037        global          scale_sqrt
16038scale_sqrt:
16039        cmpi.b          STAG(%a6),&DENORM       # is operand normalized?
16040        beq.b           ss_denorm               # normalize the DENORM
16041
16042        mov.w           FP_SCR0_EX(%a6),%d1     # extract operand's {sgn,exp}
16043        andi.l          &0x7fff,%d1             # extract operand's exponent
16044
16045        andi.w          &0x8000,FP_SCR0_EX(%a6) # extract operand's sgn
16046
16047        btst            &0x0,%d1                # is exp even or odd?
16048        beq.b           ss_norm_even
16049
16050        ori.w           &0x3fff,FP_SCR0_EX(%a6) # insert new operand's exponent(=0)
16051
16052        mov.l           &0x3fff,%d0
16053        sub.l           %d1,%d0                 # scale = BIAS + (-exp)
16054        asr.l           &0x1,%d0                # divide scale factor by 2
16055        rts
16056
16057ss_norm_even:
16058        ori.w           &0x3ffe,FP_SCR0_EX(%a6) # insert new operand's exponent(=0)
16059
16060        mov.l           &0x3ffe,%d0
16061        sub.l           %d1,%d0                 # scale = BIAS + (-exp)
16062        asr.l           &0x1,%d0                # divide scale factor by 2
16063        rts
16064
16065ss_denorm:
16066        lea             FP_SCR0(%a6),%a0        # pass ptr to src op
16067        bsr.l           norm                    # normalize denorm
16068
16069        btst            &0x0,%d0                # is exp even or odd?
16070        beq.b           ss_denorm_even
16071
16072        ori.w           &0x3fff,FP_SCR0_EX(%a6) # insert new operand's exponent(=0)
16073
16074        add.l           &0x3fff,%d0
16075        asr.l           &0x1,%d0                # divide scale factor by 2
16076        rts
16077
16078ss_denorm_even:
16079        ori.w           &0x3ffe,FP_SCR0_EX(%a6) # insert new operand's exponent(=0)
16080
16081        add.l           &0x3ffe,%d0
16082        asr.l           &0x1,%d0                # divide scale factor by 2
16083        rts
16084
16085###
16086
16087#########################################################################
16088# XDEF **************************************************************** #
16089#       scale_to_zero_dst(): scale the exponent of extended precision   #
16090#                            value at FP_SCR1(a6).                      #
16091#                                                                       #
16092# XREF **************************************************************** #
16093#       norm() - normalize the mantissa if the operand was a DENORM     #
16094#                                                                       #
16095# INPUT *************************************************************** #
16096#       FP_SCR1(a6) = extended precision operand to be scaled           #
16097#                                                                       #
16098# OUTPUT ************************************************************** #
16099#       FP_SCR1(a6) = scaled extended precision operand                 #
16100#       d0          = scale value                                       #
16101#                                                                       #
16102# ALGORITHM *********************************************************** #
16103#       Set the exponent of the input operand to 0x3fff. Save the value #
16104# of the difference between the original and new exponent. Then,        #
16105# normalize the operand if it was a DENORM. Add this normalization      #
16106# value to the previous value. Return the result.                       #
16107#                                                                       #
16108#########################################################################
16109
16110        global          scale_to_zero_dst
16111scale_to_zero_dst:
16112        mov.w           FP_SCR1_EX(%a6),%d1     # extract operand's {sgn,exp}
16113        mov.w           %d1,%d0                 # make a copy
16114
16115        andi.l          &0x7fff,%d1             # extract operand's exponent
16116
16117        andi.w          &0x8000,%d0             # extract operand's sgn
16118        or.w            &0x3fff,%d0             # insert new operand's exponent(=0)
16119
16120        mov.w           %d0,FP_SCR1_EX(%a6)     # insert biased exponent
16121
16122        cmpi.b          DTAG(%a6),&DENORM       # is operand normalized?
16123        beq.b           stzd_denorm             # normalize the DENORM
16124
16125stzd_norm:
16126        mov.l           &0x3fff,%d0
16127        sub.l           %d1,%d0                 # scale = BIAS + (-exp)
16128        rts
16129
16130stzd_denorm:
16131        lea             FP_SCR1(%a6),%a0        # pass ptr to dst op
16132        bsr.l           norm                    # normalize denorm
16133        neg.l           %d0                     # new exponent = -(shft val)
16134        mov.l           %d0,%d1                 # prepare for op_norm call
16135        bra.b           stzd_norm               # finish scaling
16136
16137##########################################################################
16138
16139#########################################################################
16140# XDEF **************************************************************** #
16141#       res_qnan(): return default result w/ QNAN operand for dyadic    #
16142#       res_snan(): return default result w/ SNAN operand for dyadic    #
16143#       res_qnan_1op(): return dflt result w/ QNAN operand for monadic  #
16144#       res_snan_1op(): return dflt result w/ SNAN operand for monadic  #
16145#                                                                       #
16146# XREF **************************************************************** #
16147#       None                                                            #
16148#                                                                       #
16149# INPUT *************************************************************** #
16150#       FP_SRC(a6) = pointer to extended precision src operand          #
16151#       FP_DST(a6) = pointer to extended precision dst operand          #
16152#                                                                       #
16153# OUTPUT ************************************************************** #
16154#       fp0 = default result                                            #
16155#                                                                       #
16156# ALGORITHM *********************************************************** #
16157#       If either operand (but not both operands) of an operation is a  #
16158# nonsignalling NAN, then that NAN is returned as the result. If both   #
16159# operands are nonsignalling NANs, then the destination operand         #
16160# nonsignalling NAN is returned as the result.                          #
16161#       If either operand to an operation is a signalling NAN (SNAN),   #
16162# then, the SNAN bit is set in the FPSR EXC byte. If the SNAN trap      #
16163# enable bit is set in the FPCR, then the trap is taken and the         #
16164# destination is not modified. If the SNAN trap enable bit is not set,  #
16165# then the SNAN is converted to a nonsignalling NAN (by setting the     #
16166# SNAN bit in the operand to one), and the operation continues as       #
16167# described in the preceding paragraph, for nonsignalling NANs.         #
16168#       Make sure the appropriate FPSR bits are set before exiting.     #
16169#                                                                       #
16170#########################################################################
16171
16172        global          res_qnan
16173        global          res_snan
16174res_qnan:
16175res_snan:
16176        cmp.b           DTAG(%a6), &SNAN        # is the dst an SNAN?
16177        beq.b           dst_snan2
16178        cmp.b           DTAG(%a6), &QNAN        # is the dst a  QNAN?
16179        beq.b           dst_qnan2
16180src_nan:
16181        cmp.b           STAG(%a6), &QNAN
16182        beq.b           src_qnan2
16183        global          res_snan_1op
16184res_snan_1op:
16185src_snan2:
16186        bset            &0x6, FP_SRC_HI(%a6)    # set SNAN bit
16187        or.l            &nan_mask+aiop_mask+snan_mask, USER_FPSR(%a6)
16188        lea             FP_SRC(%a6), %a0
16189        bra.b           nan_comp
16190        global          res_qnan_1op
16191res_qnan_1op:
16192src_qnan2:
16193        or.l            &nan_mask, USER_FPSR(%a6)
16194        lea             FP_SRC(%a6), %a0
16195        bra.b           nan_comp
16196dst_snan2:
16197        or.l            &nan_mask+aiop_mask+snan_mask, USER_FPSR(%a6)
16198        bset            &0x6, FP_DST_HI(%a6)    # set SNAN bit
16199        lea             FP_DST(%a6), %a0
16200        bra.b           nan_comp
16201dst_qnan2:
16202        lea             FP_DST(%a6), %a0
16203        cmp.b           STAG(%a6), &SNAN
16204        bne             nan_done
16205        or.l            &aiop_mask+snan_mask, USER_FPSR(%a6)
16206nan_done:
16207        or.l            &nan_mask, USER_FPSR(%a6)
16208nan_comp:
16209        btst            &0x7, FTEMP_EX(%a0)     # is NAN neg?
16210        beq.b           nan_not_neg
16211        or.l            &neg_mask, USER_FPSR(%a6)
16212nan_not_neg:
16213        fmovm.x         (%a0), &0x80
16214        rts
16215
16216#########################################################################
16217# XDEF **************************************************************** #
16218#       res_operr(): return default result during operand error         #
16219#                                                                       #
16220# XREF **************************************************************** #
16221#       None                                                            #
16222#                                                                       #
16223# INPUT *************************************************************** #
16224#       None                                                            #
16225#                                                                       #
16226# OUTPUT ************************************************************** #
16227#       fp0 = default operand error result                              #
16228#                                                                       #
16229# ALGORITHM *********************************************************** #
16230#       An nonsignalling NAN is returned as the default result when     #
16231# an operand error occurs for the following cases:                      #
16232#                                                                       #
16233#       Multiply: (Infinity x Zero)                                     #
16234#       Divide  : (Zero / Zero) || (Infinity / Infinity)                #
16235#                                                                       #
16236#########################################################################
16237
16238        global          res_operr
16239res_operr:
16240        or.l            &nan_mask+operr_mask+aiop_mask, USER_FPSR(%a6)
16241        fmovm.x         nan_return(%pc), &0x80
16242        rts
16243
16244nan_return:
16245        long            0x7fff0000, 0xffffffff, 0xffffffff
16246
16247#########################################################################
16248# fdbcc(): routine to emulate the fdbcc instruction                     #
16249#                                                                       #
16250# XDEF **************************************************************** #
16251#       _fdbcc()                                                        #
16252#                                                                       #
16253# XREF **************************************************************** #
16254#       fetch_dreg() - fetch Dn value                                   #
16255#       store_dreg_l() - store updated Dn value                         #
16256#                                                                       #
16257# INPUT *************************************************************** #
16258#       d0 = displacement                                               #
16259#                                                                       #
16260# OUTPUT ************************************************************** #
16261#       none                                                            #
16262#                                                                       #
16263# ALGORITHM *********************************************************** #
16264#       This routine checks which conditional predicate is specified by #
16265# the stacked fdbcc instruction opcode and then branches to a routine   #
16266# for that predicate. The corresponding fbcc instruction is then used   #
16267# to see whether the condition (specified by the stacked FPSR) is true  #
16268# or false.                                                             #
16269#       If a BSUN exception should be indicated, the BSUN and ABSUN     #
16270# bits are set in the stacked FPSR. If the BSUN exception is enabled,   #
16271# the fbsun_flg is set in the SPCOND_FLG location on the stack. If an   #
16272# enabled BSUN should not be flagged and the predicate is true, then    #
16273# Dn is fetched and decremented by one. If Dn is not equal to -1, add   #
16274# the displacement value to the stacked PC so that when an "rte" is     #
16275# finally executed, the branch occurs.                                  #
16276#                                                                       #
16277#########################################################################
16278        global          _fdbcc
16279_fdbcc:
16280        mov.l           %d0,L_SCR1(%a6)         # save displacement
16281
16282        mov.w           EXC_CMDREG(%a6),%d0     # fetch predicate
16283
16284        clr.l           %d1                     # clear scratch reg
16285        mov.b           FPSR_CC(%a6),%d1        # fetch fp ccodes
16286        ror.l           &0x8,%d1                # rotate to top byte
16287        fmov.l          %d1,%fpsr               # insert into FPSR
16288
16289        mov.w           (tbl_fdbcc.b,%pc,%d0.w*2),%d1 # load table
16290        jmp             (tbl_fdbcc.b,%pc,%d1.w) # jump to fdbcc routine
16291
16292tbl_fdbcc:
16293        short           fdbcc_f         -       tbl_fdbcc       # 00
16294        short           fdbcc_eq        -       tbl_fdbcc       # 01
16295        short           fdbcc_ogt       -       tbl_fdbcc       # 02
16296        short           fdbcc_oge       -       tbl_fdbcc       # 03
16297        short           fdbcc_olt       -       tbl_fdbcc       # 04
16298        short           fdbcc_ole       -       tbl_fdbcc       # 05
16299        short           fdbcc_ogl       -       tbl_fdbcc       # 06
16300        short           fdbcc_or        -       tbl_fdbcc       # 07
16301        short           fdbcc_un        -       tbl_fdbcc       # 08
16302        short           fdbcc_ueq       -       tbl_fdbcc       # 09
16303        short           fdbcc_ugt       -       tbl_fdbcc       # 10
16304        short           fdbcc_uge       -       tbl_fdbcc       # 11
16305        short           fdbcc_ult       -       tbl_fdbcc       # 12
16306        short           fdbcc_ule       -       tbl_fdbcc       # 13
16307        short           fdbcc_neq       -       tbl_fdbcc       # 14
16308        short           fdbcc_t         -       tbl_fdbcc       # 15
16309        short           fdbcc_sf        -       tbl_fdbcc       # 16
16310        short           fdbcc_seq       -       tbl_fdbcc       # 17
16311        short           fdbcc_gt        -       tbl_fdbcc       # 18
16312        short           fdbcc_ge        -       tbl_fdbcc       # 19
16313        short           fdbcc_lt        -       tbl_fdbcc       # 20
16314        short           fdbcc_le        -       tbl_fdbcc       # 21
16315        short           fdbcc_gl        -       tbl_fdbcc       # 22
16316        short           fdbcc_gle       -       tbl_fdbcc       # 23
16317        short           fdbcc_ngle      -       tbl_fdbcc       # 24
16318        short           fdbcc_ngl       -       tbl_fdbcc       # 25
16319        short           fdbcc_nle       -       tbl_fdbcc       # 26
16320        short           fdbcc_nlt       -       tbl_fdbcc       # 27
16321        short           fdbcc_nge       -       tbl_fdbcc       # 28
16322        short           fdbcc_ngt       -       tbl_fdbcc       # 29
16323        short           fdbcc_sneq      -       tbl_fdbcc       # 30
16324        short           fdbcc_st        -       tbl_fdbcc       # 31
16325
16326#########################################################################
16327#                                                                       #
16328# IEEE Nonaware tests                                                   #
16329#                                                                       #
16330# For the IEEE nonaware tests, only the false branch changes the        #
16331# counter. However, the true branch may set bsun so we check to see     #
16332# if the NAN bit is set, in which case BSUN and AIOP will be set.       #
16333#                                                                       #
16334# The cases EQ and NE are shared by the Aware and Nonaware groups       #
16335# and are incapable of setting the BSUN exception bit.                  #
16336#                                                                       #
16337# Typically, only one of the two possible branch directions could       #
16338# have the NAN bit set.                                                 #
16339# (This is assuming the mutual exclusiveness of FPSR cc bit groupings   #
16340#  is preserved.)                                                       #
16341#                                                                       #
16342#########################################################################
16343
16344#
16345# equal:
16346#
16347#       Z
16348#
16349fdbcc_eq:
16350        fbeq.w          fdbcc_eq_yes            # equal?
16351fdbcc_eq_no:
16352        bra.w           fdbcc_false             # no; go handle counter
16353fdbcc_eq_yes:
16354        rts
16355
16356#
16357# not equal:
16358#       _
16359#       Z
16360#
16361fdbcc_neq:
16362        fbneq.w         fdbcc_neq_yes           # not equal?
16363fdbcc_neq_no:
16364        bra.w           fdbcc_false             # no; go handle counter
16365fdbcc_neq_yes:
16366        rts
16367
16368#
16369# greater than:
16370#       _______
16371#       NANvZvN
16372#
16373fdbcc_gt:
16374        fbgt.w          fdbcc_gt_yes            # greater than?
16375        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
16376        beq.w           fdbcc_false             # no;go handle counter
16377        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16378        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16379        bne.w           fdbcc_bsun              # yes; we have an exception
16380        bra.w           fdbcc_false             # no; go handle counter
16381fdbcc_gt_yes:
16382        rts                                     # do nothing
16383
16384#
16385# not greater than:
16386#
16387#       NANvZvN
16388#
16389fdbcc_ngt:
16390        fbngt.w         fdbcc_ngt_yes           # not greater than?
16391fdbcc_ngt_no:
16392        bra.w           fdbcc_false             # no; go handle counter
16393fdbcc_ngt_yes:
16394        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
16395        beq.b           fdbcc_ngt_done          # no;go finish
16396        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16397        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16398        bne.w           fdbcc_bsun              # yes; we have an exception
16399fdbcc_ngt_done:
16400        rts                                     # no; do nothing
16401
16402#
16403# greater than or equal:
16404#          _____
16405#       Zv(NANvN)
16406#
16407fdbcc_ge:
16408        fbge.w          fdbcc_ge_yes            # greater than or equal?
16409fdbcc_ge_no:
16410        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
16411        beq.w           fdbcc_false             # no;go handle counter
16412        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16413        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16414        bne.w           fdbcc_bsun              # yes; we have an exception
16415        bra.w           fdbcc_false             # no; go handle counter
16416fdbcc_ge_yes:
16417        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
16418        beq.b           fdbcc_ge_yes_done       # no;go do nothing
16419        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16420        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16421        bne.w           fdbcc_bsun              # yes; we have an exception
16422fdbcc_ge_yes_done:
16423        rts                                     # do nothing
16424
16425#
16426# not (greater than or equal):
16427#              _
16428#       NANv(N^Z)
16429#
16430fdbcc_nge:
16431        fbnge.w         fdbcc_nge_yes           # not (greater than or equal)?
16432fdbcc_nge_no:
16433        bra.w           fdbcc_false             # no; go handle counter
16434fdbcc_nge_yes:
16435        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
16436        beq.b           fdbcc_nge_done          # no;go finish
16437        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16438        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16439        bne.w           fdbcc_bsun              # yes; we have an exception
16440fdbcc_nge_done:
16441        rts                                     # no; do nothing
16442
16443#
16444# less than:
16445#          _____
16446#       N^(NANvZ)
16447#
16448fdbcc_lt:
16449        fblt.w          fdbcc_lt_yes            # less than?
16450fdbcc_lt_no:
16451        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
16452        beq.w           fdbcc_false             # no; go handle counter
16453        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16454        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16455        bne.w           fdbcc_bsun              # yes; we have an exception
16456        bra.w           fdbcc_false             # no; go handle counter
16457fdbcc_lt_yes:
16458        rts                                     # do nothing
16459
16460#
16461# not less than:
16462#              _
16463#       NANv(ZvN)
16464#
16465fdbcc_nlt:
16466        fbnlt.w         fdbcc_nlt_yes           # not less than?
16467fdbcc_nlt_no:
16468        bra.w           fdbcc_false             # no; go handle counter
16469fdbcc_nlt_yes:
16470        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
16471        beq.b           fdbcc_nlt_done          # no;go finish
16472        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16473        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16474        bne.w           fdbcc_bsun              # yes; we have an exception
16475fdbcc_nlt_done:
16476        rts                                     # no; do nothing
16477
16478#
16479# less than or equal:
16480#            ___
16481#       Zv(N^NAN)
16482#
16483fdbcc_le:
16484        fble.w          fdbcc_le_yes            # less than or equal?
16485fdbcc_le_no:
16486        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
16487        beq.w           fdbcc_false             # no; go handle counter
16488        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16489        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16490        bne.w           fdbcc_bsun              # yes; we have an exception
16491        bra.w           fdbcc_false             # no; go handle counter
16492fdbcc_le_yes:
16493        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
16494        beq.b           fdbcc_le_yes_done       # no; go do nothing
16495        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16496        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16497        bne.w           fdbcc_bsun              # yes; we have an exception
16498fdbcc_le_yes_done:
16499        rts                                     # do nothing
16500
16501#
16502# not (less than or equal):
16503#            ___
16504#       NANv(NvZ)
16505#
16506fdbcc_nle:
16507        fbnle.w         fdbcc_nle_yes           # not (less than or equal)?
16508fdbcc_nle_no:
16509        bra.w           fdbcc_false             # no; go handle counter
16510fdbcc_nle_yes:
16511        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
16512        beq.w           fdbcc_nle_done          # no; go finish
16513        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16514        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16515        bne.w           fdbcc_bsun              # yes; we have an exception
16516fdbcc_nle_done:
16517        rts                                     # no; do nothing
16518
16519#
16520# greater or less than:
16521#       _____
16522#       NANvZ
16523#
16524fdbcc_gl:
16525        fbgl.w          fdbcc_gl_yes            # greater or less than?
16526fdbcc_gl_no:
16527        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
16528        beq.w           fdbcc_false             # no; handle counter
16529        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16530        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16531        bne.w           fdbcc_bsun              # yes; we have an exception
16532        bra.w           fdbcc_false             # no; go handle counter
16533fdbcc_gl_yes:
16534        rts                                     # do nothing
16535
16536#
16537# not (greater or less than):
16538#
16539#       NANvZ
16540#
16541fdbcc_ngl:
16542        fbngl.w         fdbcc_ngl_yes           # not (greater or less than)?
16543fdbcc_ngl_no:
16544        bra.w           fdbcc_false             # no; go handle counter
16545fdbcc_ngl_yes:
16546        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
16547        beq.b           fdbcc_ngl_done          # no; go finish
16548        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16549        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16550        bne.w           fdbcc_bsun              # yes; we have an exception
16551fdbcc_ngl_done:
16552        rts                                     # no; do nothing
16553
16554#
16555# greater, less, or equal:
16556#       ___
16557#       NAN
16558#
16559fdbcc_gle:
16560        fbgle.w         fdbcc_gle_yes           # greater, less, or equal?
16561fdbcc_gle_no:
16562        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16563        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16564        bne.w           fdbcc_bsun              # yes; we have an exception
16565        bra.w           fdbcc_false             # no; go handle counter
16566fdbcc_gle_yes:
16567        rts                                     # do nothing
16568
16569#
16570# not (greater, less, or equal):
16571#
16572#       NAN
16573#
16574fdbcc_ngle:
16575        fbngle.w        fdbcc_ngle_yes          # not (greater, less, or equal)?
16576fdbcc_ngle_no:
16577        bra.w           fdbcc_false             # no; go handle counter
16578fdbcc_ngle_yes:
16579        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16580        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16581        bne.w           fdbcc_bsun              # yes; we have an exception
16582        rts                                     # no; do nothing
16583
16584#########################################################################
16585#                                                                       #
16586# Miscellaneous tests                                                   #
16587#                                                                       #
16588# For the IEEE miscellaneous tests, all but fdbf and fdbt can set bsun. #
16589#                                                                       #
16590#########################################################################
16591
16592#
16593# false:
16594#
16595#       False
16596#
16597fdbcc_f:                                        # no bsun possible
16598        bra.w           fdbcc_false             # go handle counter
16599
16600#
16601# true:
16602#
16603#       True
16604#
16605fdbcc_t:                                        # no bsun possible
16606        rts                                     # do nothing
16607
16608#
16609# signalling false:
16610#
16611#       False
16612#
16613fdbcc_sf:
16614        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set?
16615        beq.w           fdbcc_false             # no;go handle counter
16616        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16617        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16618        bne.w           fdbcc_bsun              # yes; we have an exception
16619        bra.w           fdbcc_false             # go handle counter
16620
16621#
16622# signalling true:
16623#
16624#       True
16625#
16626fdbcc_st:
16627        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set?
16628        beq.b           fdbcc_st_done           # no;go finish
16629        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16630        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16631        bne.w           fdbcc_bsun              # yes; we have an exception
16632fdbcc_st_done:
16633        rts
16634
16635#
16636# signalling equal:
16637#
16638#       Z
16639#
16640fdbcc_seq:
16641        fbseq.w         fdbcc_seq_yes           # signalling equal?
16642fdbcc_seq_no:
16643        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set?
16644        beq.w           fdbcc_false             # no;go handle counter
16645        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16646        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16647        bne.w           fdbcc_bsun              # yes; we have an exception
16648        bra.w           fdbcc_false             # go handle counter
16649fdbcc_seq_yes:
16650        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set?
16651        beq.b           fdbcc_seq_yes_done      # no;go do nothing
16652        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16653        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16654        bne.w           fdbcc_bsun              # yes; we have an exception
16655fdbcc_seq_yes_done:
16656        rts                                     # yes; do nothing
16657
16658#
16659# signalling not equal:
16660#       _
16661#       Z
16662#
16663fdbcc_sneq:
16664        fbsneq.w        fdbcc_sneq_yes          # signalling not equal?
16665fdbcc_sneq_no:
16666        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set?
16667        beq.w           fdbcc_false             # no;go handle counter
16668        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16669        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16670        bne.w           fdbcc_bsun              # yes; we have an exception
16671        bra.w           fdbcc_false             # go handle counter
16672fdbcc_sneq_yes:
16673        btst            &nan_bit, FPSR_CC(%a6)  # set BSUN exc bit
16674        beq.w           fdbcc_sneq_done         # no;go finish
16675        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
16676        btst            &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled?
16677        bne.w           fdbcc_bsun              # yes; we have an exception
16678fdbcc_sneq_done:
16679        rts
16680
16681#########################################################################
16682#                                                                       #
16683# IEEE Aware tests                                                      #
16684#                                                                       #
16685# For the IEEE aware tests, action is only taken if the result is false.#
16686# Therefore, the opposite branch type is used to jump to the decrement  #
16687# routine.                                                              #
16688# The BSUN exception will not be set for any of these tests.            #
16689#                                                                       #
16690#########################################################################
16691
16692#
16693# ordered greater than:
16694#       _______
16695#       NANvZvN
16696#
16697fdbcc_ogt:
16698        fbogt.w         fdbcc_ogt_yes           # ordered greater than?
16699fdbcc_ogt_no:
16700        bra.w           fdbcc_false             # no; go handle counter
16701fdbcc_ogt_yes:
16702        rts                                     # yes; do nothing
16703
16704#
16705# unordered or less or equal:
16706#       _______
16707#       NANvZvN
16708#
16709fdbcc_ule:
16710        fbule.w         fdbcc_ule_yes           # unordered or less or equal?
16711fdbcc_ule_no:
16712        bra.w           fdbcc_false             # no; go handle counter
16713fdbcc_ule_yes:
16714        rts                                     # yes; do nothing
16715
16716#
16717# ordered greater than or equal:
16718#          _____
16719#       Zv(NANvN)
16720#
16721fdbcc_oge:
16722        fboge.w         fdbcc_oge_yes           # ordered greater than or equal?
16723fdbcc_oge_no:
16724        bra.w           fdbcc_false             # no; go handle counter
16725fdbcc_oge_yes:
16726        rts                                     # yes; do nothing
16727
16728#
16729# unordered or less than:
16730#              _
16731#       NANv(N^Z)
16732#
16733fdbcc_ult:
16734        fbult.w         fdbcc_ult_yes           # unordered or less than?
16735fdbcc_ult_no:
16736        bra.w           fdbcc_false             # no; go handle counter
16737fdbcc_ult_yes:
16738        rts                                     # yes; do nothing
16739
16740#
16741# ordered less than:
16742#          _____
16743#       N^(NANvZ)
16744#
16745fdbcc_olt:
16746        fbolt.w         fdbcc_olt_yes           # ordered less than?
16747fdbcc_olt_no:
16748        bra.w           fdbcc_false             # no; go handle counter
16749fdbcc_olt_yes:
16750        rts                                     # yes; do nothing
16751
16752#
16753# unordered or greater or equal:
16754#
16755#       NANvZvN
16756#
16757fdbcc_uge:
16758        fbuge.w         fdbcc_uge_yes           # unordered or greater than?
16759fdbcc_uge_no:
16760        bra.w           fdbcc_false             # no; go handle counter
16761fdbcc_uge_yes:
16762        rts                                     # yes; do nothing
16763
16764#
16765# ordered less than or equal:
16766#            ___
16767#       Zv(N^NAN)
16768#
16769fdbcc_ole:
16770        fbole.w         fdbcc_ole_yes           # ordered greater or less than?
16771fdbcc_ole_no:
16772        bra.w           fdbcc_false             # no; go handle counter
16773fdbcc_ole_yes:
16774        rts                                     # yes; do nothing
16775
16776#
16777# unordered or greater than:
16778#            ___
16779#       NANv(NvZ)
16780#
16781fdbcc_ugt:
16782        fbugt.w         fdbcc_ugt_yes           # unordered or greater than?
16783fdbcc_ugt_no:
16784        bra.w           fdbcc_false             # no; go handle counter
16785fdbcc_ugt_yes:
16786        rts                                     # yes; do nothing
16787
16788#
16789# ordered greater or less than:
16790#       _____
16791#       NANvZ
16792#
16793fdbcc_ogl:
16794        fbogl.w         fdbcc_ogl_yes           # ordered greater or less than?
16795fdbcc_ogl_no:
16796        bra.w           fdbcc_false             # no; go handle counter
16797fdbcc_ogl_yes:
16798        rts                                     # yes; do nothing
16799
16800#
16801# unordered or equal:
16802#
16803#       NANvZ
16804#
16805fdbcc_ueq:
16806        fbueq.w         fdbcc_ueq_yes           # unordered or equal?
16807fdbcc_ueq_no:
16808        bra.w           fdbcc_false             # no; go handle counter
16809fdbcc_ueq_yes:
16810        rts                                     # yes; do nothing
16811
16812#
16813# ordered:
16814#       ___
16815#       NAN
16816#
16817fdbcc_or:
16818        fbor.w          fdbcc_or_yes            # ordered?
16819fdbcc_or_no:
16820        bra.w           fdbcc_false             # no; go handle counter
16821fdbcc_or_yes:
16822        rts                                     # yes; do nothing
16823
16824#
16825# unordered:
16826#
16827#       NAN
16828#
16829fdbcc_un:
16830        fbun.w          fdbcc_un_yes            # unordered?
16831fdbcc_un_no:
16832        bra.w           fdbcc_false             # no; go handle counter
16833fdbcc_un_yes:
16834        rts                                     # yes; do nothing
16835
16836#######################################################################
16837
16838#
16839# the bsun exception bit was not set.
16840#
16841# (1) subtract 1 from the count register
16842# (2) if (cr == -1) then
16843#       pc = pc of next instruction
16844#     else
16845#       pc += sign_ext(16-bit displacement)
16846#
16847fdbcc_false:
16848        mov.b           1+EXC_OPWORD(%a6), %d1  # fetch lo opword
16849        andi.w          &0x7, %d1               # extract count register
16850
16851        bsr.l           fetch_dreg              # fetch count value
16852# make sure that d0 isn't corrupted between calls...
16853
16854        subq.w          &0x1, %d0               # Dn - 1 -> Dn
16855
16856        bsr.l           store_dreg_l            # store new count value
16857
16858        cmpi.w          %d0, &-0x1              # is (Dn == -1)?
16859        bne.b           fdbcc_false_cont        # no;
16860        rts
16861
16862fdbcc_false_cont:
16863        mov.l           L_SCR1(%a6),%d0         # fetch displacement
16864        add.l           USER_FPIAR(%a6),%d0     # add instruction PC
16865        addq.l          &0x4,%d0                # add instruction length
16866        mov.l           %d0,EXC_PC(%a6)         # set new PC
16867        rts
16868
16869# the emulation routine set bsun and BSUN was enabled. have to
16870# fix stack and jump to the bsun handler.
16871# let the caller of this routine shift the stack frame up to
16872# eliminate the effective address field.
16873fdbcc_bsun:
16874        mov.b           &fbsun_flg,SPCOND_FLG(%a6)
16875        rts
16876
16877#########################################################################
16878# ftrapcc(): routine to emulate the ftrapcc instruction                 #
16879#                                                                       #
16880# XDEF **************************************************************** #
16881#       _ftrapcc()                                                      #
16882#                                                                       #
16883# XREF **************************************************************** #
16884#       none                                                            #
16885#                                                                       #
16886# INPUT *************************************************************** #
16887#       none                                                            #
16888#                                                                       #
16889# OUTPUT ************************************************************** #
16890#       none                                                            #
16891#                                                                       #
16892# ALGORITHM *********************************************************** #
16893#       This routine checks which conditional predicate is specified by #
16894# the stacked ftrapcc instruction opcode and then branches to a routine #
16895# for that predicate. The corresponding fbcc instruction is then used   #
16896# to see whether the condition (specified by the stacked FPSR) is true  #
16897# or false.                                                             #
16898#       If a BSUN exception should be indicated, the BSUN and ABSUN     #
16899# bits are set in the stacked FPSR. If the BSUN exception is enabled,   #
16900# the fbsun_flg is set in the SPCOND_FLG location on the stack. If an   #
16901# enabled BSUN should not be flagged and the predicate is true, then    #
16902# the ftrapcc_flg is set in the SPCOND_FLG location. These special      #
16903# flags indicate to the calling routine to emulate the exceptional      #
16904# condition.                                                            #
16905#                                                                       #
16906#########################################################################
16907
16908        global          _ftrapcc
16909_ftrapcc:
16910        mov.w           EXC_CMDREG(%a6),%d0     # fetch predicate
16911
16912        clr.l           %d1                     # clear scratch reg
16913        mov.b           FPSR_CC(%a6),%d1        # fetch fp ccodes
16914        ror.l           &0x8,%d1                # rotate to top byte
16915        fmov.l          %d1,%fpsr               # insert into FPSR
16916
16917        mov.w           (tbl_ftrapcc.b,%pc,%d0.w*2), %d1 # load table
16918        jmp             (tbl_ftrapcc.b,%pc,%d1.w) # jump to ftrapcc routine
16919
16920tbl_ftrapcc:
16921        short           ftrapcc_f       -       tbl_ftrapcc     # 00
16922        short           ftrapcc_eq      -       tbl_ftrapcc     # 01
16923        short           ftrapcc_ogt     -       tbl_ftrapcc     # 02
16924        short           ftrapcc_oge     -       tbl_ftrapcc     # 03
16925        short           ftrapcc_olt     -       tbl_ftrapcc     # 04
16926        short           ftrapcc_ole     -       tbl_ftrapcc     # 05
16927        short           ftrapcc_ogl     -       tbl_ftrapcc     # 06
16928        short           ftrapcc_or      -       tbl_ftrapcc     # 07
16929        short           ftrapcc_un      -       tbl_ftrapcc     # 08
16930        short           ftrapcc_ueq     -       tbl_ftrapcc     # 09
16931        short           ftrapcc_ugt     -       tbl_ftrapcc     # 10
16932        short           ftrapcc_uge     -       tbl_ftrapcc     # 11
16933        short           ftrapcc_ult     -       tbl_ftrapcc     # 12
16934        short           ftrapcc_ule     -       tbl_ftrapcc     # 13
16935        short           ftrapcc_neq     -       tbl_ftrapcc     # 14
16936        short           ftrapcc_t       -       tbl_ftrapcc     # 15
16937        short           ftrapcc_sf      -       tbl_ftrapcc     # 16
16938        short           ftrapcc_seq     -       tbl_ftrapcc     # 17
16939        short           ftrapcc_gt      -       tbl_ftrapcc     # 18
16940        short           ftrapcc_ge      -       tbl_ftrapcc     # 19
16941        short           ftrapcc_lt      -       tbl_ftrapcc     # 20
16942        short           ftrapcc_le      -       tbl_ftrapcc     # 21
16943        short           ftrapcc_gl      -       tbl_ftrapcc     # 22
16944        short           ftrapcc_gle     -       tbl_ftrapcc     # 23
16945        short           ftrapcc_ngle    -       tbl_ftrapcc     # 24
16946        short           ftrapcc_ngl     -       tbl_ftrapcc     # 25
16947        short           ftrapcc_nle     -       tbl_ftrapcc     # 26
16948        short           ftrapcc_nlt     -       tbl_ftrapcc     # 27
16949        short           ftrapcc_nge     -       tbl_ftrapcc     # 28
16950        short           ftrapcc_ngt     -       tbl_ftrapcc     # 29
16951        short           ftrapcc_sneq    -       tbl_ftrapcc     # 30
16952        short           ftrapcc_st      -       tbl_ftrapcc     # 31
16953
16954#########################################################################
16955#                                                                       #
16956# IEEE Nonaware tests                                                   #
16957#                                                                       #
16958# For the IEEE nonaware tests, we set the result based on the           #
16959# floating point condition codes. In addition, we check to see          #
16960# if the NAN bit is set, in which case BSUN and AIOP will be set.       #
16961#                                                                       #
16962# The cases EQ and NE are shared by the Aware and Nonaware groups       #
16963# and are incapable of setting the BSUN exception bit.                  #
16964#                                                                       #
16965# Typically, only one of the two possible branch directions could       #
16966# have the NAN bit set.                                                 #
16967#                                                                       #
16968#########################################################################
16969
16970#
16971# equal:
16972#
16973#       Z
16974#
16975ftrapcc_eq:
16976        fbeq.w          ftrapcc_trap            # equal?
16977ftrapcc_eq_no:
16978        rts                                     # do nothing
16979
16980#
16981# not equal:
16982#       _
16983#       Z
16984#
16985ftrapcc_neq:
16986        fbneq.w         ftrapcc_trap            # not equal?
16987ftrapcc_neq_no:
16988        rts                                     # do nothing
16989
16990#
16991# greater than:
16992#       _______
16993#       NANvZvN
16994#
16995ftrapcc_gt:
16996        fbgt.w          ftrapcc_trap            # greater than?
16997ftrapcc_gt_no:
16998        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
16999        beq.b           ftrapcc_gt_done         # no
17000        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17001        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17002        bne.w           ftrapcc_bsun            # yes
17003ftrapcc_gt_done:
17004        rts                                     # no; do nothing
17005
17006#
17007# not greater than:
17008#
17009#       NANvZvN
17010#
17011ftrapcc_ngt:
17012        fbngt.w         ftrapcc_ngt_yes         # not greater than?
17013ftrapcc_ngt_no:
17014        rts                                     # do nothing
17015ftrapcc_ngt_yes:
17016        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17017        beq.w           ftrapcc_trap            # no; go take trap
17018        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17019        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17020        bne.w           ftrapcc_bsun            # yes
17021        bra.w           ftrapcc_trap            # no; go take trap
17022
17023#
17024# greater than or equal:
17025#          _____
17026#       Zv(NANvN)
17027#
17028ftrapcc_ge:
17029        fbge.w          ftrapcc_ge_yes          # greater than or equal?
17030ftrapcc_ge_no:
17031        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17032        beq.b           ftrapcc_ge_done         # no; go finish
17033        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17034        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17035        bne.w           ftrapcc_bsun            # yes
17036ftrapcc_ge_done:
17037        rts                                     # no; do nothing
17038ftrapcc_ge_yes:
17039        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17040        beq.w           ftrapcc_trap            # no; go take trap
17041        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17042        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17043        bne.w           ftrapcc_bsun            # yes
17044        bra.w           ftrapcc_trap            # no; go take trap
17045
17046#
17047# not (greater than or equal):
17048#              _
17049#       NANv(N^Z)
17050#
17051ftrapcc_nge:
17052        fbnge.w         ftrapcc_nge_yes         # not (greater than or equal)?
17053ftrapcc_nge_no:
17054        rts                                     # do nothing
17055ftrapcc_nge_yes:
17056        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17057        beq.w           ftrapcc_trap            # no; go take trap
17058        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17059        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17060        bne.w           ftrapcc_bsun            # yes
17061        bra.w           ftrapcc_trap            # no; go take trap
17062
17063#
17064# less than:
17065#          _____
17066#       N^(NANvZ)
17067#
17068ftrapcc_lt:
17069        fblt.w          ftrapcc_trap            # less than?
17070ftrapcc_lt_no:
17071        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17072        beq.b           ftrapcc_lt_done         # no; go finish
17073        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17074        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17075        bne.w           ftrapcc_bsun            # yes
17076ftrapcc_lt_done:
17077        rts                                     # no; do nothing
17078
17079#
17080# not less than:
17081#              _
17082#       NANv(ZvN)
17083#
17084ftrapcc_nlt:
17085        fbnlt.w         ftrapcc_nlt_yes         # not less than?
17086ftrapcc_nlt_no:
17087        rts                                     # do nothing
17088ftrapcc_nlt_yes:
17089        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17090        beq.w           ftrapcc_trap            # no; go take trap
17091        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17092        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17093        bne.w           ftrapcc_bsun            # yes
17094        bra.w           ftrapcc_trap            # no; go take trap
17095
17096#
17097# less than or equal:
17098#            ___
17099#       Zv(N^NAN)
17100#
17101ftrapcc_le:
17102        fble.w          ftrapcc_le_yes          # less than or equal?
17103ftrapcc_le_no:
17104        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17105        beq.b           ftrapcc_le_done         # no; go finish
17106        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17107        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17108        bne.w           ftrapcc_bsun            # yes
17109ftrapcc_le_done:
17110        rts                                     # no; do nothing
17111ftrapcc_le_yes:
17112        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17113        beq.w           ftrapcc_trap            # no; go take trap
17114        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17115        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17116        bne.w           ftrapcc_bsun            # yes
17117        bra.w           ftrapcc_trap            # no; go take trap
17118
17119#
17120# not (less than or equal):
17121#            ___
17122#       NANv(NvZ)
17123#
17124ftrapcc_nle:
17125        fbnle.w         ftrapcc_nle_yes         # not (less than or equal)?
17126ftrapcc_nle_no:
17127        rts                                     # do nothing
17128ftrapcc_nle_yes:
17129        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17130        beq.w           ftrapcc_trap            # no; go take trap
17131        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17132        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17133        bne.w           ftrapcc_bsun            # yes
17134        bra.w           ftrapcc_trap            # no; go take trap
17135
17136#
17137# greater or less than:
17138#       _____
17139#       NANvZ
17140#
17141ftrapcc_gl:
17142        fbgl.w          ftrapcc_trap            # greater or less than?
17143ftrapcc_gl_no:
17144        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17145        beq.b           ftrapcc_gl_done         # no; go finish
17146        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17147        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17148        bne.w           ftrapcc_bsun            # yes
17149ftrapcc_gl_done:
17150        rts                                     # no; do nothing
17151
17152#
17153# not (greater or less than):
17154#
17155#       NANvZ
17156#
17157ftrapcc_ngl:
17158        fbngl.w         ftrapcc_ngl_yes         # not (greater or less than)?
17159ftrapcc_ngl_no:
17160        rts                                     # do nothing
17161ftrapcc_ngl_yes:
17162        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17163        beq.w           ftrapcc_trap            # no; go take trap
17164        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17165        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17166        bne.w           ftrapcc_bsun            # yes
17167        bra.w           ftrapcc_trap            # no; go take trap
17168
17169#
17170# greater, less, or equal:
17171#       ___
17172#       NAN
17173#
17174ftrapcc_gle:
17175        fbgle.w         ftrapcc_trap            # greater, less, or equal?
17176ftrapcc_gle_no:
17177        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17178        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17179        bne.w           ftrapcc_bsun            # yes
17180        rts                                     # no; do nothing
17181
17182#
17183# not (greater, less, or equal):
17184#
17185#       NAN
17186#
17187ftrapcc_ngle:
17188        fbngle.w        ftrapcc_ngle_yes        # not (greater, less, or equal)?
17189ftrapcc_ngle_no:
17190        rts                                     # do nothing
17191ftrapcc_ngle_yes:
17192        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17193        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17194        bne.w           ftrapcc_bsun            # yes
17195        bra.w           ftrapcc_trap            # no; go take trap
17196
17197#########################################################################
17198#                                                                       #
17199# Miscellaneous tests                                                   #
17200#                                                                       #
17201# For the IEEE aware tests, we only have to set the result based on the #
17202# floating point condition codes. The BSUN exception will not be        #
17203# set for any of these tests.                                           #
17204#                                                                       #
17205#########################################################################
17206
17207#
17208# false:
17209#
17210#       False
17211#
17212ftrapcc_f:
17213        rts                                     # do nothing
17214
17215#
17216# true:
17217#
17218#       True
17219#
17220ftrapcc_t:
17221        bra.w           ftrapcc_trap            # go take trap
17222
17223#
17224# signalling false:
17225#
17226#       False
17227#
17228ftrapcc_sf:
17229        btst            &nan_bit, FPSR_CC(%a6)  # set BSUN exc bit
17230        beq.b           ftrapcc_sf_done         # no; go finish
17231        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17232        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17233        bne.w           ftrapcc_bsun            # yes
17234ftrapcc_sf_done:
17235        rts                                     # no; do nothing
17236
17237#
17238# signalling true:
17239#
17240#       True
17241#
17242ftrapcc_st:
17243        btst            &nan_bit, FPSR_CC(%a6)  # set BSUN exc bit
17244        beq.w           ftrapcc_trap            # no; go take trap
17245        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17246        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17247        bne.w           ftrapcc_bsun            # yes
17248        bra.w           ftrapcc_trap            # no; go take trap
17249
17250#
17251# signalling equal:
17252#
17253#       Z
17254#
17255ftrapcc_seq:
17256        fbseq.w         ftrapcc_seq_yes         # signalling equal?
17257ftrapcc_seq_no:
17258        btst            &nan_bit, FPSR_CC(%a6)  # set BSUN exc bit
17259        beq.w           ftrapcc_seq_done        # no; go finish
17260        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17261        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17262        bne.w           ftrapcc_bsun            # yes
17263ftrapcc_seq_done:
17264        rts                                     # no; do nothing
17265ftrapcc_seq_yes:
17266        btst            &nan_bit, FPSR_CC(%a6)  # set BSUN exc bit
17267        beq.w           ftrapcc_trap            # no; go take trap
17268        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17269        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17270        bne.w           ftrapcc_bsun            # yes
17271        bra.w           ftrapcc_trap            # no; go take trap
17272
17273#
17274# signalling not equal:
17275#       _
17276#       Z
17277#
17278ftrapcc_sneq:
17279        fbsneq.w        ftrapcc_sneq_yes        # signalling equal?
17280ftrapcc_sneq_no:
17281        btst            &nan_bit, FPSR_CC(%a6)  # set BSUN exc bit
17282        beq.w           ftrapcc_sneq_no_done    # no; go finish
17283        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17284        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17285        bne.w           ftrapcc_bsun            # yes
17286ftrapcc_sneq_no_done:
17287        rts                                     # do nothing
17288ftrapcc_sneq_yes:
17289        btst            &nan_bit, FPSR_CC(%a6)  # set BSUN exc bit
17290        beq.w           ftrapcc_trap            # no; go take trap
17291        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17292        btst            &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set?
17293        bne.w           ftrapcc_bsun            # yes
17294        bra.w           ftrapcc_trap            # no; go take trap
17295
17296#########################################################################
17297#                                                                       #
17298# IEEE Aware tests                                                      #
17299#                                                                       #
17300# For the IEEE aware tests, we only have to set the result based on the #
17301# floating point condition codes. The BSUN exception will not be        #
17302# set for any of these tests.                                           #
17303#                                                                       #
17304#########################################################################
17305
17306#
17307# ordered greater than:
17308#       _______
17309#       NANvZvN
17310#
17311ftrapcc_ogt:
17312        fbogt.w         ftrapcc_trap            # ordered greater than?
17313ftrapcc_ogt_no:
17314        rts                                     # do nothing
17315
17316#
17317# unordered or less or equal:
17318#       _______
17319#       NANvZvN
17320#
17321ftrapcc_ule:
17322        fbule.w         ftrapcc_trap            # unordered or less or equal?
17323ftrapcc_ule_no:
17324        rts                                     # do nothing
17325
17326#
17327# ordered greater than or equal:
17328#          _____
17329#       Zv(NANvN)
17330#
17331ftrapcc_oge:
17332        fboge.w         ftrapcc_trap            # ordered greater than or equal?
17333ftrapcc_oge_no:
17334        rts                                     # do nothing
17335
17336#
17337# unordered or less than:
17338#              _
17339#       NANv(N^Z)
17340#
17341ftrapcc_ult:
17342        fbult.w         ftrapcc_trap            # unordered or less than?
17343ftrapcc_ult_no:
17344        rts                                     # do nothing
17345
17346#
17347# ordered less than:
17348#          _____
17349#       N^(NANvZ)
17350#
17351ftrapcc_olt:
17352        fbolt.w         ftrapcc_trap            # ordered less than?
17353ftrapcc_olt_no:
17354        rts                                     # do nothing
17355
17356#
17357# unordered or greater or equal:
17358#
17359#       NANvZvN
17360#
17361ftrapcc_uge:
17362        fbuge.w         ftrapcc_trap            # unordered or greater than?
17363ftrapcc_uge_no:
17364        rts                                     # do nothing
17365
17366#
17367# ordered less than or equal:
17368#            ___
17369#       Zv(N^NAN)
17370#
17371ftrapcc_ole:
17372        fbole.w         ftrapcc_trap            # ordered greater or less than?
17373ftrapcc_ole_no:
17374        rts                                     # do nothing
17375
17376#
17377# unordered or greater than:
17378#            ___
17379#       NANv(NvZ)
17380#
17381ftrapcc_ugt:
17382        fbugt.w         ftrapcc_trap            # unordered or greater than?
17383ftrapcc_ugt_no:
17384        rts                                     # do nothing
17385
17386#
17387# ordered greater or less than:
17388#       _____
17389#       NANvZ
17390#
17391ftrapcc_ogl:
17392        fbogl.w         ftrapcc_trap            # ordered greater or less than?
17393ftrapcc_ogl_no:
17394        rts                                     # do nothing
17395
17396#
17397# unordered or equal:
17398#
17399#       NANvZ
17400#
17401ftrapcc_ueq:
17402        fbueq.w         ftrapcc_trap            # unordered or equal?
17403ftrapcc_ueq_no:
17404        rts                                     # do nothing
17405
17406#
17407# ordered:
17408#       ___
17409#       NAN
17410#
17411ftrapcc_or:
17412        fbor.w          ftrapcc_trap            # ordered?
17413ftrapcc_or_no:
17414        rts                                     # do nothing
17415
17416#
17417# unordered:
17418#
17419#       NAN
17420#
17421ftrapcc_un:
17422        fbun.w          ftrapcc_trap            # unordered?
17423ftrapcc_un_no:
17424        rts                                     # do nothing
17425
17426#######################################################################
17427
17428# the bsun exception bit was not set.
17429# we will need to jump to the ftrapcc vector. the stack frame
17430# is the same size as that of the fp unimp instruction. the
17431# only difference is that the <ea> field should hold the PC
17432# of the ftrapcc instruction and the vector offset field
17433# should denote the ftrapcc trap.
17434ftrapcc_trap:
17435        mov.b           &ftrapcc_flg,SPCOND_FLG(%a6)
17436        rts
17437
17438# the emulation routine set bsun and BSUN was enabled. have to
17439# fix stack and jump to the bsun handler.
17440# let the caller of this routine shift the stack frame up to
17441# eliminate the effective address field.
17442ftrapcc_bsun:
17443        mov.b           &fbsun_flg,SPCOND_FLG(%a6)
17444        rts
17445
17446#########################################################################
17447# fscc(): routine to emulate the fscc instruction                       #
17448#                                                                       #
17449# XDEF **************************************************************** #
17450#       _fscc()                                                         #
17451#                                                                       #
17452# XREF **************************************************************** #
17453#       store_dreg_b() - store result to data register file             #
17454#       dec_areg() - decrement an areg for -(an) mode                   #
17455#       inc_areg() - increment an areg for (an)+ mode                   #
17456#       _dmem_write_byte() - store result to memory                     #
17457#                                                                       #
17458# INPUT *************************************************************** #
17459#       none                                                            #
17460#                                                                       #
17461# OUTPUT ************************************************************** #
17462#       none                                                            #
17463#                                                                       #
17464# ALGORITHM *********************************************************** #
17465#       This routine checks which conditional predicate is specified by #
17466# the stacked fscc instruction opcode and then branches to a routine    #
17467# for that predicate. The corresponding fbcc instruction is then used   #
17468# to see whether the condition (specified by the stacked FPSR) is true  #
17469# or false.                                                             #
17470#       If a BSUN exception should be indicated, the BSUN and ABSUN     #
17471# bits are set in the stacked FPSR. If the BSUN exception is enabled,   #
17472# the fbsun_flg is set in the SPCOND_FLG location on the stack. If an   #
17473# enabled BSUN should not be flagged and the predicate is true, then    #
17474# the result is stored to the data register file or memory              #
17475#                                                                       #
17476#########################################################################
17477
17478        global          _fscc
17479_fscc:
17480        mov.w           EXC_CMDREG(%a6),%d0     # fetch predicate
17481
17482        clr.l           %d1                     # clear scratch reg
17483        mov.b           FPSR_CC(%a6),%d1        # fetch fp ccodes
17484        ror.l           &0x8,%d1                # rotate to top byte
17485        fmov.l          %d1,%fpsr               # insert into FPSR
17486
17487        mov.w           (tbl_fscc.b,%pc,%d0.w*2),%d1 # load table
17488        jmp             (tbl_fscc.b,%pc,%d1.w)  # jump to fscc routine
17489
17490tbl_fscc:
17491        short           fscc_f          -       tbl_fscc        # 00
17492        short           fscc_eq         -       tbl_fscc        # 01
17493        short           fscc_ogt        -       tbl_fscc        # 02
17494        short           fscc_oge        -       tbl_fscc        # 03
17495        short           fscc_olt        -       tbl_fscc        # 04
17496        short           fscc_ole        -       tbl_fscc        # 05
17497        short           fscc_ogl        -       tbl_fscc        # 06
17498        short           fscc_or         -       tbl_fscc        # 07
17499        short           fscc_un         -       tbl_fscc        # 08
17500        short           fscc_ueq        -       tbl_fscc        # 09
17501        short           fscc_ugt        -       tbl_fscc        # 10
17502        short           fscc_uge        -       tbl_fscc        # 11
17503        short           fscc_ult        -       tbl_fscc        # 12
17504        short           fscc_ule        -       tbl_fscc        # 13
17505        short           fscc_neq        -       tbl_fscc        # 14
17506        short           fscc_t          -       tbl_fscc        # 15
17507        short           fscc_sf         -       tbl_fscc        # 16
17508        short           fscc_seq        -       tbl_fscc        # 17
17509        short           fscc_gt         -       tbl_fscc        # 18
17510        short           fscc_ge         -       tbl_fscc        # 19
17511        short           fscc_lt         -       tbl_fscc        # 20
17512        short           fscc_le         -       tbl_fscc        # 21
17513        short           fscc_gl         -       tbl_fscc        # 22
17514        short           fscc_gle        -       tbl_fscc        # 23
17515        short           fscc_ngle       -       tbl_fscc        # 24
17516        short           fscc_ngl        -       tbl_fscc        # 25
17517        short           fscc_nle        -       tbl_fscc        # 26
17518        short           fscc_nlt        -       tbl_fscc        # 27
17519        short           fscc_nge        -       tbl_fscc        # 28
17520        short           fscc_ngt        -       tbl_fscc        # 29
17521        short           fscc_sneq       -       tbl_fscc        # 30
17522        short           fscc_st         -       tbl_fscc        # 31
17523
17524#########################################################################
17525#                                                                       #
17526# IEEE Nonaware tests                                                   #
17527#                                                                       #
17528# For the IEEE nonaware tests, we set the result based on the           #
17529# floating point condition codes. In addition, we check to see          #
17530# if the NAN bit is set, in which case BSUN and AIOP will be set.       #
17531#                                                                       #
17532# The cases EQ and NE are shared by the Aware and Nonaware groups       #
17533# and are incapable of setting the BSUN exception bit.                  #
17534#                                                                       #
17535# Typically, only one of the two possible branch directions could       #
17536# have the NAN bit set.                                                 #
17537#                                                                       #
17538#########################################################################
17539
17540#
17541# equal:
17542#
17543#       Z
17544#
17545fscc_eq:
17546        fbeq.w          fscc_eq_yes             # equal?
17547fscc_eq_no:
17548        clr.b           %d0                     # set false
17549        bra.w           fscc_done               # go finish
17550fscc_eq_yes:
17551        st              %d0                     # set true
17552        bra.w           fscc_done               # go finish
17553
17554#
17555# not equal:
17556#       _
17557#       Z
17558#
17559fscc_neq:
17560        fbneq.w         fscc_neq_yes            # not equal?
17561fscc_neq_no:
17562        clr.b           %d0                     # set false
17563        bra.w           fscc_done               # go finish
17564fscc_neq_yes:
17565        st              %d0                     # set true
17566        bra.w           fscc_done               # go finish
17567
17568#
17569# greater than:
17570#       _______
17571#       NANvZvN
17572#
17573fscc_gt:
17574        fbgt.w          fscc_gt_yes             # greater than?
17575fscc_gt_no:
17576        clr.b           %d0                     # set false
17577        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17578        beq.w           fscc_done               # no;go finish
17579        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17580        bra.w           fscc_chk_bsun           # go finish
17581fscc_gt_yes:
17582        st              %d0                     # set true
17583        bra.w           fscc_done               # go finish
17584
17585#
17586# not greater than:
17587#
17588#       NANvZvN
17589#
17590fscc_ngt:
17591        fbngt.w         fscc_ngt_yes            # not greater than?
17592fscc_ngt_no:
17593        clr.b           %d0                     # set false
17594        bra.w           fscc_done               # go finish
17595fscc_ngt_yes:
17596        st              %d0                     # set true
17597        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17598        beq.w           fscc_done               # no;go finish
17599        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17600        bra.w           fscc_chk_bsun           # go finish
17601
17602#
17603# greater than or equal:
17604#          _____
17605#       Zv(NANvN)
17606#
17607fscc_ge:
17608        fbge.w          fscc_ge_yes             # greater than or equal?
17609fscc_ge_no:
17610        clr.b           %d0                     # set false
17611        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17612        beq.w           fscc_done               # no;go finish
17613        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17614        bra.w           fscc_chk_bsun           # go finish
17615fscc_ge_yes:
17616        st              %d0                     # set true
17617        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17618        beq.w           fscc_done               # no;go finish
17619        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17620        bra.w           fscc_chk_bsun           # go finish
17621
17622#
17623# not (greater than or equal):
17624#              _
17625#       NANv(N^Z)
17626#
17627fscc_nge:
17628        fbnge.w         fscc_nge_yes            # not (greater than or equal)?
17629fscc_nge_no:
17630        clr.b           %d0                     # set false
17631        bra.w           fscc_done               # go finish
17632fscc_nge_yes:
17633        st              %d0                     # set true
17634        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17635        beq.w           fscc_done               # no;go finish
17636        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17637        bra.w           fscc_chk_bsun           # go finish
17638
17639#
17640# less than:
17641#          _____
17642#       N^(NANvZ)
17643#
17644fscc_lt:
17645        fblt.w          fscc_lt_yes             # less than?
17646fscc_lt_no:
17647        clr.b           %d0                     # set false
17648        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17649        beq.w           fscc_done               # no;go finish
17650        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17651        bra.w           fscc_chk_bsun           # go finish
17652fscc_lt_yes:
17653        st              %d0                     # set true
17654        bra.w           fscc_done               # go finish
17655
17656#
17657# not less than:
17658#              _
17659#       NANv(ZvN)
17660#
17661fscc_nlt:
17662        fbnlt.w         fscc_nlt_yes            # not less than?
17663fscc_nlt_no:
17664        clr.b           %d0                     # set false
17665        bra.w           fscc_done               # go finish
17666fscc_nlt_yes:
17667        st              %d0                     # set true
17668        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17669        beq.w           fscc_done               # no;go finish
17670        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17671        bra.w           fscc_chk_bsun           # go finish
17672
17673#
17674# less than or equal:
17675#            ___
17676#       Zv(N^NAN)
17677#
17678fscc_le:
17679        fble.w          fscc_le_yes             # less than or equal?
17680fscc_le_no:
17681        clr.b           %d0                     # set false
17682        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17683        beq.w           fscc_done               # no;go finish
17684        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17685        bra.w           fscc_chk_bsun           # go finish
17686fscc_le_yes:
17687        st              %d0                     # set true
17688        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17689        beq.w           fscc_done               # no;go finish
17690        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17691        bra.w           fscc_chk_bsun           # go finish
17692
17693#
17694# not (less than or equal):
17695#            ___
17696#       NANv(NvZ)
17697#
17698fscc_nle:
17699        fbnle.w         fscc_nle_yes            # not (less than or equal)?
17700fscc_nle_no:
17701        clr.b           %d0                     # set false
17702        bra.w           fscc_done               # go finish
17703fscc_nle_yes:
17704        st              %d0                     # set true
17705        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17706        beq.w           fscc_done               # no;go finish
17707        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17708        bra.w           fscc_chk_bsun           # go finish
17709
17710#
17711# greater or less than:
17712#       _____
17713#       NANvZ
17714#
17715fscc_gl:
17716        fbgl.w          fscc_gl_yes             # greater or less than?
17717fscc_gl_no:
17718        clr.b           %d0                     # set false
17719        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17720        beq.w           fscc_done               # no;go finish
17721        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17722        bra.w           fscc_chk_bsun           # go finish
17723fscc_gl_yes:
17724        st              %d0                     # set true
17725        bra.w           fscc_done               # go finish
17726
17727#
17728# not (greater or less than):
17729#
17730#       NANvZ
17731#
17732fscc_ngl:
17733        fbngl.w         fscc_ngl_yes            # not (greater or less than)?
17734fscc_ngl_no:
17735        clr.b           %d0                     # set false
17736        bra.w           fscc_done               # go finish
17737fscc_ngl_yes:
17738        st              %d0                     # set true
17739        btst            &nan_bit, FPSR_CC(%a6)  # is NAN set in cc?
17740        beq.w           fscc_done               # no;go finish
17741        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17742        bra.w           fscc_chk_bsun           # go finish
17743
17744#
17745# greater, less, or equal:
17746#       ___
17747#       NAN
17748#
17749fscc_gle:
17750        fbgle.w         fscc_gle_yes            # greater, less, or equal?
17751fscc_gle_no:
17752        clr.b           %d0                     # set false
17753        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17754        bra.w           fscc_chk_bsun           # go finish
17755fscc_gle_yes:
17756        st              %d0                     # set true
17757        bra.w           fscc_done               # go finish
17758
17759#
17760# not (greater, less, or equal):
17761#
17762#       NAN
17763#
17764fscc_ngle:
17765        fbngle.w                fscc_ngle_yes   # not (greater, less, or equal)?
17766fscc_ngle_no:
17767        clr.b           %d0                     # set false
17768        bra.w           fscc_done               # go finish
17769fscc_ngle_yes:
17770        st              %d0                     # set true
17771        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17772        bra.w           fscc_chk_bsun           # go finish
17773
17774#########################################################################
17775#                                                                       #
17776# Miscellaneous tests                                                   #
17777#                                                                       #
17778# For the IEEE aware tests, we only have to set the result based on the #
17779# floating point condition codes. The BSUN exception will not be        #
17780# set for any of these tests.                                           #
17781#                                                                       #
17782#########################################################################
17783
17784#
17785# false:
17786#
17787#       False
17788#
17789fscc_f:
17790        clr.b           %d0                     # set false
17791        bra.w           fscc_done               # go finish
17792
17793#
17794# true:
17795#
17796#       True
17797#
17798fscc_t:
17799        st              %d0                     # set true
17800        bra.w           fscc_done               # go finish
17801
17802#
17803# signalling false:
17804#
17805#       False
17806#
17807fscc_sf:
17808        clr.b           %d0                     # set false
17809        btst            &nan_bit, FPSR_CC(%a6)  # set BSUN exc bit
17810        beq.w           fscc_done               # no;go finish
17811        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17812        bra.w           fscc_chk_bsun           # go finish
17813
17814#
17815# signalling true:
17816#
17817#       True
17818#
17819fscc_st:
17820        st              %d0                     # set false
17821        btst            &nan_bit, FPSR_CC(%a6)  # set BSUN exc bit
17822        beq.w           fscc_done               # no;go finish
17823        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17824        bra.w           fscc_chk_bsun           # go finish
17825
17826#
17827# signalling equal:
17828#
17829#       Z
17830#
17831fscc_seq:
17832        fbseq.w         fscc_seq_yes            # signalling equal?
17833fscc_seq_no:
17834        clr.b           %d0                     # set false
17835        btst            &nan_bit, FPSR_CC(%a6)  # set BSUN exc bit
17836        beq.w           fscc_done               # no;go finish
17837        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17838        bra.w           fscc_chk_bsun           # go finish
17839fscc_seq_yes:
17840        st              %d0                     # set true
17841        btst            &nan_bit, FPSR_CC(%a6)  # set BSUN exc bit
17842        beq.w           fscc_done               # no;go finish
17843        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17844        bra.w           fscc_chk_bsun           # go finish
17845
17846#
17847# signalling not equal:
17848#       _
17849#       Z
17850#
17851fscc_sneq:
17852        fbsneq.w        fscc_sneq_yes           # signalling equal?
17853fscc_sneq_no:
17854        clr.b           %d0                     # set false
17855        btst            &nan_bit, FPSR_CC(%a6)  # set BSUN exc bit
17856        beq.w           fscc_done               # no;go finish
17857        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17858        bra.w           fscc_chk_bsun           # go finish
17859fscc_sneq_yes:
17860        st              %d0                     # set true
17861        btst            &nan_bit, FPSR_CC(%a6)  # set BSUN exc bit
17862        beq.w           fscc_done               # no;go finish
17863        ori.l           &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit
17864        bra.w           fscc_chk_bsun           # go finish
17865
17866#########################################################################
17867#                                                                       #
17868# IEEE Aware tests                                                      #
17869#                                                                       #
17870# For the IEEE aware tests, we only have to set the result based on the #
17871# floating point condition codes. The BSUN exception will not be        #
17872# set for any of these tests.                                           #
17873#                                                                       #
17874#########################################################################
17875
17876#
17877# ordered greater than:
17878#       _______
17879#       NANvZvN
17880#
17881fscc_ogt:
17882        fbogt.w         fscc_ogt_yes            # ordered greater than?
17883fscc_ogt_no:
17884        clr.b           %d0                     # set false
17885        bra.w           fscc_done               # go finish
17886fscc_ogt_yes:
17887        st              %d0                     # set true
17888        bra.w           fscc_done               # go finish
17889
17890#
17891# unordered or less or equal:
17892#       _______
17893#       NANvZvN
17894#
17895fscc_ule:
17896        fbule.w         fscc_ule_yes            # unordered or less or equal?
17897fscc_ule_no:
17898        clr.b           %d0                     # set false
17899        bra.w           fscc_done               # go finish
17900fscc_ule_yes:
17901        st              %d0                     # set true
17902        bra.w           fscc_done               # go finish
17903
17904#
17905# ordered greater than or equal:
17906#          _____
17907#       Zv(NANvN)
17908#
17909fscc_oge:
17910        fboge.w         fscc_oge_yes            # ordered greater than or equal?
17911fscc_oge_no:
17912        clr.b           %d0                     # set false
17913        bra.w           fscc_done               # go finish
17914fscc_oge_yes:
17915        st              %d0                     # set true
17916        bra.w           fscc_done               # go finish
17917
17918#
17919# unordered or less than:
17920#              _
17921#       NANv(N^Z)
17922#
17923fscc_ult:
17924        fbult.w         fscc_ult_yes            # unordered or less than?
17925fscc_ult_no:
17926        clr.b           %d0                     # set false
17927        bra.w           fscc_done               # go finish
17928fscc_ult_yes:
17929        st              %d0                     # set true
17930        bra.w           fscc_done               # go finish
17931
17932#
17933# ordered less than:
17934#          _____
17935#       N^(NANvZ)
17936#
17937fscc_olt:
17938        fbolt.w         fscc_olt_yes            # ordered less than?
17939fscc_olt_no:
17940        clr.b           %d0                     # set false
17941        bra.w           fscc_done               # go finish
17942fscc_olt_yes:
17943        st              %d0                     # set true
17944        bra.w           fscc_done               # go finish
17945
17946#
17947# unordered or greater or equal:
17948#
17949#       NANvZvN
17950#
17951fscc_uge:
17952        fbuge.w         fscc_uge_yes            # unordered or greater than?
17953fscc_uge_no:
17954        clr.b           %d0                     # set false
17955        bra.w           fscc_done               # go finish
17956fscc_uge_yes:
17957        st              %d0                     # set true
17958        bra.w           fscc_done               # go finish
17959
17960#
17961# ordered less than or equal:
17962#            ___
17963#       Zv(N^NAN)
17964#
17965fscc_ole:
17966        fbole.w         fscc_ole_yes            # ordered greater or less than?
17967fscc_ole_no:
17968        clr.b           %d0                     # set false
17969        bra.w           fscc_done               # go finish
17970fscc_ole_yes:
17971        st              %d0                     # set true
17972        bra.w           fscc_done               # go finish
17973
17974#
17975# unordered or greater than:
17976#            ___
17977#       NANv(NvZ)
17978#
17979fscc_ugt:
17980        fbugt.w         fscc_ugt_yes            # unordered or greater than?
17981fscc_ugt_no:
17982        clr.b           %d0                     # set false
17983        bra.w           fscc_done               # go finish
17984fscc_ugt_yes:
17985        st              %d0                     # set true
17986        bra.w           fscc_done               # go finish
17987
17988#
17989# ordered greater or less than:
17990#       _____
17991#       NANvZ
17992#
17993fscc_ogl:
17994        fbogl.w         fscc_ogl_yes            # ordered greater or less than?
17995fscc_ogl_no:
17996        clr.b           %d0                     # set false
17997        bra.w           fscc_done               # go finish
17998fscc_ogl_yes:
17999        st              %d0                     # set true
18000        bra.w           fscc_done               # go finish
18001
18002#
18003# unordered or equal:
18004#
18005#       NANvZ
18006#
18007fscc_ueq:
18008        fbueq.w         fscc_ueq_yes            # unordered or equal?
18009fscc_ueq_no:
18010        clr.b           %d0                     # set false
18011        bra.w           fscc_done               # go finish
18012fscc_ueq_yes:
18013        st              %d0                     # set true
18014        bra.w           fscc_done               # go finish
18015
18016#
18017# ordered:
18018#       ___
18019#       NAN
18020#
18021fscc_or:
18022        fbor.w          fscc_or_yes             # ordered?
18023fscc_or_no:
18024        clr.b           %d0                     # set false
18025        bra.w           fscc_done               # go finish
18026fscc_or_yes:
18027        st              %d0                     # set true
18028        bra.w           fscc_done               # go finish
18029
18030#
18031# unordered:
18032#
18033#       NAN
18034#
18035fscc_un:
18036        fbun.w          fscc_un_yes             # unordered?
18037fscc_un_no:
18038        clr.b           %d0                     # set false
18039        bra.w           fscc_done               # go finish
18040fscc_un_yes:
18041        st              %d0                     # set true
18042        bra.w           fscc_done               # go finish
18043
18044#######################################################################
18045
18046#
18047# the bsun exception bit was set. now, check to see is BSUN
18048# is enabled. if so, don't store result and correct stack frame
18049# for a bsun exception.
18050#
18051fscc_chk_bsun:
18052        btst            &bsun_bit,FPCR_ENABLE(%a6) # was BSUN set?
18053        bne.w           fscc_bsun
18054
18055#
18056# the bsun exception bit was not set.
18057# the result has been selected.
18058# now, check to see if the result is to be stored in the data register
18059# file or in memory.
18060#
18061fscc_done:
18062        mov.l           %d0,%a0                 # save result for a moment
18063
18064        mov.b           1+EXC_OPWORD(%a6),%d1   # fetch lo opword
18065        mov.l           %d1,%d0                 # make a copy
18066        andi.b          &0x38,%d1               # extract src mode
18067
18068        bne.b           fscc_mem_op             # it's a memory operation
18069
18070        mov.l           %d0,%d1
18071        andi.w          &0x7,%d1                # pass index in d1
18072        mov.l           %a0,%d0                 # pass result in d0
18073        bsr.l           store_dreg_b            # save result in regfile
18074        rts
18075
18076#
18077# the stacked <ea> is correct with the exception of:
18078#       -> Dn : <ea> is garbage
18079#
18080# if the addressing mode is post-increment or pre-decrement,
18081# then the address registers have not been updated.
18082#
18083fscc_mem_op:
18084        cmpi.b          %d1,&0x18               # is <ea> (An)+ ?
18085        beq.b           fscc_mem_inc            # yes
18086        cmpi.b          %d1,&0x20               # is <ea> -(An) ?
18087        beq.b           fscc_mem_dec            # yes
18088
18089        mov.l           %a0,%d0                 # pass result in d0
18090        mov.l           EXC_EA(%a6),%a0         # fetch <ea>
18091        bsr.l           _dmem_write_byte        # write result byte
18092
18093        tst.l           %d1                     # did dstore fail?
18094        bne.w           fscc_err                # yes
18095
18096        rts
18097
18098# addressing mode is post-increment. write the result byte. if the write
18099# fails then don't update the address register. if write passes then
18100# call inc_areg() to update the address register.
18101fscc_mem_inc:
18102        mov.l           %a0,%d0                 # pass result in d0
18103        mov.l           EXC_EA(%a6),%a0         # fetch <ea>
18104        bsr.l           _dmem_write_byte        # write result byte
18105
18106        tst.l           %d1                     # did dstore fail?
18107        bne.w           fscc_err                # yes
18108
18109        mov.b           0x1+EXC_OPWORD(%a6),%d1 # fetch opword
18110        andi.w          &0x7,%d1                # pass index in d1
18111        movq.l          &0x1,%d0                # pass amt to inc by
18112        bsr.l           inc_areg                # increment address register
18113
18114        rts
18115
18116# addressing mode is pre-decrement. write the result byte. if the write
18117# fails then don't update the address register. if the write passes then
18118# call dec_areg() to update the address register.
18119fscc_mem_dec:
18120        mov.l           %a0,%d0                 # pass result in d0
18121        mov.l           EXC_EA(%a6),%a0         # fetch <ea>
18122        bsr.l           _dmem_write_byte        # write result byte
18123
18124        tst.l           %d1                     # did dstore fail?
18125        bne.w           fscc_err                # yes
18126
18127        mov.b           0x1+EXC_OPWORD(%a6),%d1 # fetch opword
18128        andi.w          &0x7,%d1                # pass index in d1
18129        movq.l          &0x1,%d0                # pass amt to dec by
18130        bsr.l           dec_areg                # decrement address register
18131
18132        rts
18133
18134# the emulation routine set bsun and BSUN was enabled. have to
18135# fix stack and jump to the bsun handler.
18136# let the caller of this routine shift the stack frame up to
18137# eliminate the effective address field.
18138fscc_bsun:
18139        mov.b           &fbsun_flg,SPCOND_FLG(%a6)
18140        rts
18141
18142# the byte write to memory has failed. pass the failing effective address
18143# and a FSLW to funimp_dacc().
18144fscc_err:
18145        mov.w           &0x00a1,EXC_VOFF(%a6)
18146        bra.l           facc_finish
18147
18148#########################################################################
18149# XDEF **************************************************************** #
18150#       fmovm_dynamic(): emulate "fmovm" dynamic instruction            #
18151#                                                                       #
18152# XREF **************************************************************** #
18153#       fetch_dreg() - fetch data register                              #
18154#       {i,d,}mem_read() - fetch data from memory                       #
18155#       _mem_write() - write data to memory                             #
18156#       iea_iacc() - instruction memory access error occurred           #
18157#       iea_dacc() - data memory access error occurred                  #
18158#       restore() - restore An index regs if access error occurred      #
18159#                                                                       #
18160# INPUT *************************************************************** #
18161#       None                                                            #
18162#                                                                       #
18163# OUTPUT ************************************************************** #
18164#       If instr is "fmovm Dn,-(A7)" from supervisor mode,              #
18165#               d0 = size of dump                                       #
18166#               d1 = Dn                                                 #
18167#       Else if instruction access error,                               #
18168#               d0 = FSLW                                               #
18169#       Else if data access error,                                      #
18170#               d0 = FSLW                                               #
18171#               a0 = address of fault                                   #
18172#       Else                                                            #
18173#               none.                                                   #
18174#                                                                       #
18175# ALGORITHM *********************************************************** #
18176#       The effective address must be calculated since this is entered  #
18177# from an "Unimplemented Effective Address" exception handler. So, we   #
18178# have our own fcalc_ea() routine here. If an access error is flagged   #
18179# by a _{i,d,}mem_read() call, we must exit through the special         #
18180# handler.                                                              #
18181#       The data register is determined and its value loaded to get the #
18182# string of FP registers affected. This value is used as an index into  #
18183# a lookup table such that we can determine the number of bytes         #
18184# involved.                                                             #
18185#       If the instruction is "fmovm.x <ea>,Dn", a _mem_read() is used  #
18186# to read in all FP values. Again, _mem_read() may fail and require a   #
18187# special exit.                                                         #
18188#       If the instruction is "fmovm.x DN,<ea>", a _mem_write() is used #
18189# to write all FP values. _mem_write() may also fail.                   #
18190#       If the instruction is "fmovm.x DN,-(a7)" from supervisor mode,  #
18191# then we return the size of the dump and the string to the caller      #
18192# so that the move can occur outside of this routine. This special      #
18193# case is required so that moves to the system stack are handled        #
18194# correctly.                                                            #
18195#                                                                       #
18196# DYNAMIC:                                                              #
18197#       fmovm.x dn, <ea>                                                #
18198#       fmovm.x <ea>, dn                                                #
18199#                                                                       #
18200#             <WORD 1>                <WORD2>                           #
18201#       1111 0010 00 |<ea>|     11@& 1000 0$$$ 0000                     #
18202#                                                                       #
18203#       & = (0): predecrement addressing mode                           #
18204#           (1): postincrement or control addressing mode               #
18205#       @ = (0): move listed regs from memory to the FPU                #
18206#           (1): move listed regs from the FPU to memory                #
18207#       $$$    : index of data register holding reg select mask         #
18208#                                                                       #
18209# NOTES:                                                                #
18210#       If the data register holds a zero, then the                     #
18211#       instruction is a nop.                                           #
18212#                                                                       #
18213#########################################################################
18214
18215        global          fmovm_dynamic
18216fmovm_dynamic:
18217
18218# extract the data register in which the bit string resides...
18219        mov.b           1+EXC_EXTWORD(%a6),%d1  # fetch extword
18220        andi.w          &0x70,%d1               # extract reg bits
18221        lsr.b           &0x4,%d1                # shift into lo bits
18222
18223# fetch the bit string into d0...
18224        bsr.l           fetch_dreg              # fetch reg string
18225
18226        andi.l          &0x000000ff,%d0         # keep only lo byte
18227
18228        mov.l           %d0,-(%sp)              # save strg
18229        mov.b           (tbl_fmovm_size.w,%pc,%d0),%d0
18230        mov.l           %d0,-(%sp)              # save size
18231        bsr.l           fmovm_calc_ea           # calculate <ea>
18232        mov.l           (%sp)+,%d0              # restore size
18233        mov.l           (%sp)+,%d1              # restore strg
18234
18235# if the bit string is a zero, then the operation is a no-op
18236# but, make sure that we've calculated ea and advanced the opword pointer
18237        beq.w           fmovm_data_done
18238
18239# separate move ins from move outs...
18240        btst            &0x5,EXC_EXTWORD(%a6)   # is it a move in or out?
18241        beq.w           fmovm_data_in           # it's a move out
18242
18243#############
18244# MOVE OUT: #
18245#############
18246fmovm_data_out:
18247        btst            &0x4,EXC_EXTWORD(%a6)   # control or predecrement?
18248        bne.w           fmovm_out_ctrl          # control
18249
18250############################
18251fmovm_out_predec:
18252# for predecrement mode, the bit string is the opposite of both control
18253# operations and postincrement mode. (bit7 = FP7 ... bit0 = FP0)
18254# here, we convert it to be just like the others...
18255        mov.b           (tbl_fmovm_convert.w,%pc,%d1.w*1),%d1
18256
18257        btst            &0x5,EXC_SR(%a6)        # user or supervisor mode?
18258        beq.b           fmovm_out_ctrl          # user
18259
18260fmovm_out_predec_s:
18261        cmpi.b          SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)?
18262        bne.b           fmovm_out_ctrl
18263
18264# the operation was unfortunately an: fmovm.x dn,-(sp)
18265# called from supervisor mode.
18266# we're also passing "size" and "strg" back to the calling routine
18267        rts
18268
18269############################
18270fmovm_out_ctrl:
18271        mov.l           %a0,%a1                 # move <ea> to a1
18272
18273        sub.l           %d0,%sp                 # subtract size of dump
18274        lea             (%sp),%a0
18275
18276        tst.b           %d1                     # should FP0 be moved?
18277        bpl.b           fmovm_out_ctrl_fp1      # no
18278
18279        mov.l           0x0+EXC_FP0(%a6),(%a0)+ # yes
18280        mov.l           0x4+EXC_FP0(%a6),(%a0)+
18281        mov.l           0x8+EXC_FP0(%a6),(%a0)+
18282
18283fmovm_out_ctrl_fp1:
18284        lsl.b           &0x1,%d1                # should FP1 be moved?
18285        bpl.b           fmovm_out_ctrl_fp2      # no
18286
18287        mov.l           0x0+EXC_FP1(%a6),(%a0)+ # yes
18288        mov.l           0x4+EXC_FP1(%a6),(%a0)+
18289        mov.l           0x8+EXC_FP1(%a6),(%a0)+
18290
18291fmovm_out_ctrl_fp2:
18292        lsl.b           &0x1,%d1                # should FP2 be moved?
18293        bpl.b           fmovm_out_ctrl_fp3      # no
18294
18295        fmovm.x         &0x20,(%a0)             # yes
18296        add.l           &0xc,%a0
18297
18298fmovm_out_ctrl_fp3:
18299        lsl.b           &0x1,%d1                # should FP3 be moved?
18300        bpl.b           fmovm_out_ctrl_fp4      # no
18301
18302        fmovm.x         &0x10,(%a0)             # yes
18303        add.l           &0xc,%a0
18304
18305fmovm_out_ctrl_fp4:
18306        lsl.b           &0x1,%d1                # should FP4 be moved?
18307        bpl.b           fmovm_out_ctrl_fp5      # no
18308
18309        fmovm.x         &0x08,(%a0)             # yes
18310        add.l           &0xc,%a0
18311
18312fmovm_out_ctrl_fp5:
18313        lsl.b           &0x1,%d1                # should FP5 be moved?
18314        bpl.b           fmovm_out_ctrl_fp6      # no
18315
18316        fmovm.x         &0x04,(%a0)             # yes
18317        add.l           &0xc,%a0
18318
18319fmovm_out_ctrl_fp6:
18320        lsl.b           &0x1,%d1                # should FP6 be moved?
18321        bpl.b           fmovm_out_ctrl_fp7      # no
18322
18323        fmovm.x         &0x02,(%a0)             # yes
18324        add.l           &0xc,%a0
18325
18326fmovm_out_ctrl_fp7:
18327        lsl.b           &0x1,%d1                # should FP7 be moved?
18328        bpl.b           fmovm_out_ctrl_done     # no
18329
18330        fmovm.x         &0x01,(%a0)             # yes
18331        add.l           &0xc,%a0
18332
18333fmovm_out_ctrl_done:
18334        mov.l           %a1,L_SCR1(%a6)
18335
18336        lea             (%sp),%a0               # pass: supervisor src
18337        mov.l           %d0,-(%sp)              # save size
18338        bsr.l           _dmem_write             # copy data to user mem
18339
18340        mov.l           (%sp)+,%d0
18341        add.l           %d0,%sp                 # clear fpreg data from stack
18342
18343        tst.l           %d1                     # did dstore err?
18344        bne.w           fmovm_out_err           # yes
18345
18346        rts
18347
18348############
18349# MOVE IN: #
18350############
18351fmovm_data_in:
18352        mov.l           %a0,L_SCR1(%a6)
18353
18354        sub.l           %d0,%sp                 # make room for fpregs
18355        lea             (%sp),%a1
18356
18357        mov.l           %d1,-(%sp)              # save bit string for later
18358        mov.l           %d0,-(%sp)              # save # of bytes
18359
18360        bsr.l           _dmem_read              # copy data from user mem
18361
18362        mov.l           (%sp)+,%d0              # retrieve # of bytes
18363
18364        tst.l           %d1                     # did dfetch fail?
18365        bne.w           fmovm_in_err            # yes
18366
18367        mov.l           (%sp)+,%d1              # load bit string
18368
18369        lea             (%sp),%a0               # addr of stack
18370
18371        tst.b           %d1                     # should FP0 be moved?
18372        bpl.b           fmovm_data_in_fp1       # no
18373
18374        mov.l           (%a0)+,0x0+EXC_FP0(%a6) # yes
18375        mov.l           (%a0)+,0x4+EXC_FP0(%a6)
18376        mov.l           (%a0)+,0x8+EXC_FP0(%a6)
18377
18378fmovm_data_in_fp1:
18379        lsl.b           &0x1,%d1                # should FP1 be moved?
18380        bpl.b           fmovm_data_in_fp2       # no
18381
18382        mov.l           (%a0)+,0x0+EXC_FP1(%a6) # yes
18383        mov.l           (%a0)+,0x4+EXC_FP1(%a6)
18384        mov.l           (%a0)+,0x8+EXC_FP1(%a6)
18385
18386fmovm_data_in_fp2:
18387        lsl.b           &0x1,%d1                # should FP2 be moved?
18388        bpl.b           fmovm_data_in_fp3       # no
18389
18390        fmovm.x         (%a0)+,&0x20            # yes
18391
18392fmovm_data_in_fp3:
18393        lsl.b           &0x1,%d1                # should FP3 be moved?
18394        bpl.b           fmovm_data_in_fp4       # no
18395
18396        fmovm.x         (%a0)+,&0x10            # yes
18397
18398fmovm_data_in_fp4:
18399        lsl.b           &0x1,%d1                # should FP4 be moved?
18400        bpl.b           fmovm_data_in_fp5       # no
18401
18402        fmovm.x         (%a0)+,&0x08            # yes
18403
18404fmovm_data_in_fp5:
18405        lsl.b           &0x1,%d1                # should FP5 be moved?
18406        bpl.b           fmovm_data_in_fp6       # no
18407
18408        fmovm.x         (%a0)+,&0x04            # yes
18409
18410fmovm_data_in_fp6:
18411        lsl.b           &0x1,%d1                # should FP6 be moved?
18412        bpl.b           fmovm_data_in_fp7       # no
18413
18414        fmovm.x         (%a0)+,&0x02            # yes
18415
18416fmovm_data_in_fp7:
18417        lsl.b           &0x1,%d1                # should FP7 be moved?
18418        bpl.b           fmovm_data_in_done      # no
18419
18420        fmovm.x         (%a0)+,&0x01            # yes
18421
18422fmovm_data_in_done:
18423        add.l           %d0,%sp                 # remove fpregs from stack
18424        rts
18425
18426#####################################
18427
18428fmovm_data_done:
18429        rts
18430
18431##############################################################################
18432
18433#
18434# table indexed by the operation's bit string that gives the number
18435# of bytes that will be moved.
18436#
18437# number of bytes = (# of 1's in bit string) * 12(bytes/fpreg)
18438#
18439tbl_fmovm_size:
18440        byte    0x00,0x0c,0x0c,0x18,0x0c,0x18,0x18,0x24
18441        byte    0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
18442        byte    0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
18443        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
18444        byte    0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
18445        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
18446        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
18447        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
18448        byte    0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
18449        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
18450        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
18451        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
18452        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
18453        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
18454        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
18455        byte    0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
18456        byte    0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
18457        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
18458        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
18459        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
18460        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
18461        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
18462        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
18463        byte    0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
18464        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
18465        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
18466        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
18467        byte    0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
18468        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
18469        byte    0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
18470        byte    0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
18471        byte    0x3c,0x48,0x48,0x54,0x48,0x54,0x54,0x60
18472
18473#
18474# table to convert a pre-decrement bit string into a post-increment
18475# or control bit string.
18476# ex:   0x00    ==>     0x00
18477#       0x01    ==>     0x80
18478#       0x02    ==>     0x40
18479#               .
18480#               .
18481#       0xfd    ==>     0xbf
18482#       0xfe    ==>     0x7f
18483#       0xff    ==>     0xff
18484#
18485tbl_fmovm_convert:
18486        byte    0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0
18487        byte    0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0
18488        byte    0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8
18489        byte    0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8
18490        byte    0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4
18491        byte    0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4
18492        byte    0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec
18493        byte    0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc
18494        byte    0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2
18495        byte    0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2
18496        byte    0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea
18497        byte    0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa
18498        byte    0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6
18499        byte    0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6
18500        byte    0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee
18501        byte    0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe
18502        byte    0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1
18503        byte    0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1
18504        byte    0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9
18505        byte    0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9
18506        byte    0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5
18507        byte    0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5
18508        byte    0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed
18509        byte    0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd
18510        byte    0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3
18511        byte    0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3
18512        byte    0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb
18513        byte    0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb
18514        byte    0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7
18515        byte    0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7
18516        byte    0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef
18517        byte    0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
18518
18519        global          fmovm_calc_ea
18520###############################################
18521# _fmovm_calc_ea: calculate effective address #
18522###############################################
18523fmovm_calc_ea:
18524        mov.l           %d0,%a0                 # move # bytes to a0
18525
18526# currently, MODE and REG are taken from the EXC_OPWORD. this could be
18527# easily changed if they were inputs passed in registers.
18528        mov.w           EXC_OPWORD(%a6),%d0     # fetch opcode word
18529        mov.w           %d0,%d1                 # make a copy
18530
18531        andi.w          &0x3f,%d0               # extract mode field
18532        andi.l          &0x7,%d1                # extract reg  field
18533
18534# jump to the corresponding function for each {MODE,REG} pair.
18535        mov.w           (tbl_fea_mode.b,%pc,%d0.w*2),%d0 # fetch jmp distance
18536        jmp             (tbl_fea_mode.b,%pc,%d0.w*1) # jmp to correct ea mode
18537
18538        swbeg           &64
18539tbl_fea_mode:
18540        short           tbl_fea_mode    -       tbl_fea_mode
18541        short           tbl_fea_mode    -       tbl_fea_mode
18542        short           tbl_fea_mode    -       tbl_fea_mode
18543        short           tbl_fea_mode    -       tbl_fea_mode
18544        short           tbl_fea_mode    -       tbl_fea_mode
18545        short           tbl_fea_mode    -       tbl_fea_mode
18546        short           tbl_fea_mode    -       tbl_fea_mode
18547        short           tbl_fea_mode    -       tbl_fea_mode
18548
18549        short           tbl_fea_mode    -       tbl_fea_mode
18550        short           tbl_fea_mode    -       tbl_fea_mode
18551        short           tbl_fea_mode    -       tbl_fea_mode
18552        short           tbl_fea_mode    -       tbl_fea_mode
18553        short           tbl_fea_mode    -       tbl_fea_mode
18554        short           tbl_fea_mode    -       tbl_fea_mode
18555        short           tbl_fea_mode    -       tbl_fea_mode
18556        short           tbl_fea_mode    -       tbl_fea_mode
18557
18558        short           faddr_ind_a0    -       tbl_fea_mode
18559        short           faddr_ind_a1    -       tbl_fea_mode
18560        short           faddr_ind_a2    -       tbl_fea_mode
18561        short           faddr_ind_a3    -       tbl_fea_mode
18562        short           faddr_ind_a4    -       tbl_fea_mode
18563        short           faddr_ind_a5    -       tbl_fea_mode
18564        short           faddr_ind_a6    -       tbl_fea_mode
18565        short           faddr_ind_a7    -       tbl_fea_mode
18566
18567        short           faddr_ind_p_a0  -       tbl_fea_mode
18568        short           faddr_ind_p_a1  -       tbl_fea_mode
18569        short           faddr_ind_p_a2  -       tbl_fea_mode
18570        short           faddr_ind_p_a3  -       tbl_fea_mode
18571        short           faddr_ind_p_a4  -       tbl_fea_mode
18572        short           faddr_ind_p_a5  -       tbl_fea_mode
18573        short           faddr_ind_p_a6  -       tbl_fea_mode
18574        short           faddr_ind_p_a7  -       tbl_fea_mode
18575
18576        short           faddr_ind_m_a0  -       tbl_fea_mode
18577        short           faddr_ind_m_a1  -       tbl_fea_mode
18578        short           faddr_ind_m_a2  -       tbl_fea_mode
18579        short           faddr_ind_m_a3  -       tbl_fea_mode
18580        short           faddr_ind_m_a4  -       tbl_fea_mode
18581        short           faddr_ind_m_a5  -       tbl_fea_mode
18582        short           faddr_ind_m_a6  -       tbl_fea_mode
18583        short           faddr_ind_m_a7  -       tbl_fea_mode
18584
18585        short           faddr_ind_disp_a0       -       tbl_fea_mode
18586        short           faddr_ind_disp_a1       -       tbl_fea_mode
18587        short           faddr_ind_disp_a2       -       tbl_fea_mode
18588        short           faddr_ind_disp_a3       -       tbl_fea_mode
18589        short           faddr_ind_disp_a4       -       tbl_fea_mode
18590        short           faddr_ind_disp_a5       -       tbl_fea_mode
18591        short           faddr_ind_disp_a6       -       tbl_fea_mode
18592        short           faddr_ind_disp_a7       -       tbl_fea_mode
18593
18594        short           faddr_ind_ext   -       tbl_fea_mode
18595        short           faddr_ind_ext   -       tbl_fea_mode
18596        short           faddr_ind_ext   -       tbl_fea_mode
18597        short           faddr_ind_ext   -       tbl_fea_mode
18598        short           faddr_ind_ext   -       tbl_fea_mode
18599        short           faddr_ind_ext   -       tbl_fea_mode
18600        short           faddr_ind_ext   -       tbl_fea_mode
18601        short           faddr_ind_ext   -       tbl_fea_mode
18602
18603        short           fabs_short      -       tbl_fea_mode
18604        short           fabs_long       -       tbl_fea_mode
18605        short           fpc_ind         -       tbl_fea_mode
18606        short           fpc_ind_ext     -       tbl_fea_mode
18607        short           tbl_fea_mode    -       tbl_fea_mode
18608        short           tbl_fea_mode    -       tbl_fea_mode
18609        short           tbl_fea_mode    -       tbl_fea_mode
18610        short           tbl_fea_mode    -       tbl_fea_mode
18611
18612###################################
18613# Address register indirect: (An) #
18614###################################
18615faddr_ind_a0:
18616        mov.l           EXC_DREGS+0x8(%a6),%a0  # Get current a0
18617        rts
18618
18619faddr_ind_a1:
18620        mov.l           EXC_DREGS+0xc(%a6),%a0  # Get current a1
18621        rts
18622
18623faddr_ind_a2:
18624        mov.l           %a2,%a0                 # Get current a2
18625        rts
18626
18627faddr_ind_a3:
18628        mov.l           %a3,%a0                 # Get current a3
18629        rts
18630
18631faddr_ind_a4:
18632        mov.l           %a4,%a0                 # Get current a4
18633        rts
18634
18635faddr_ind_a5:
18636        mov.l           %a5,%a0                 # Get current a5
18637        rts
18638
18639faddr_ind_a6:
18640        mov.l           (%a6),%a0               # Get current a6
18641        rts
18642
18643faddr_ind_a7:
18644        mov.l           EXC_A7(%a6),%a0         # Get current a7
18645        rts
18646
18647#####################################################
18648# Address register indirect w/ postincrement: (An)+ #
18649#####################################################
18650faddr_ind_p_a0:
18651        mov.l           EXC_DREGS+0x8(%a6),%d0  # Get current a0
18652        mov.l           %d0,%d1
18653        add.l           %a0,%d1                 # Increment
18654        mov.l           %d1,EXC_DREGS+0x8(%a6)  # Save incr value
18655        mov.l           %d0,%a0
18656        rts
18657
18658faddr_ind_p_a1:
18659        mov.l           EXC_DREGS+0xc(%a6),%d0  # Get current a1
18660        mov.l           %d0,%d1
18661        add.l           %a0,%d1                 # Increment
18662        mov.l           %d1,EXC_DREGS+0xc(%a6)  # Save incr value
18663        mov.l           %d0,%a0
18664        rts
18665
18666faddr_ind_p_a2:
18667        mov.l           %a2,%d0                 # Get current a2
18668        mov.l           %d0,%d1
18669        add.l           %a0,%d1                 # Increment
18670        mov.l           %d1,%a2                 # Save incr value
18671        mov.l           %d0,%a0
18672        rts
18673
18674faddr_ind_p_a3:
18675        mov.l           %a3,%d0                 # Get current a3
18676        mov.l           %d0,%d1
18677        add.l           %a0,%d1                 # Increment
18678        mov.l           %d1,%a3                 # Save incr value
18679        mov.l           %d0,%a0
18680        rts
18681
18682faddr_ind_p_a4:
18683        mov.l           %a4,%d0                 # Get current a4
18684        mov.l           %d0,%d1
18685        add.l           %a0,%d1                 # Increment
18686        mov.l           %d1,%a4                 # Save incr value
18687        mov.l           %d0,%a0
18688        rts
18689
18690faddr_ind_p_a5:
18691        mov.l           %a5,%d0                 # Get current a5
18692        mov.l           %d0,%d1
18693        add.l           %a0,%d1                 # Increment
18694        mov.l           %d1,%a5                 # Save incr value
18695        mov.l           %d0,%a0
18696        rts
18697
18698faddr_ind_p_a6:
18699        mov.l           (%a6),%d0               # Get current a6
18700        mov.l           %d0,%d1
18701        add.l           %a0,%d1                 # Increment
18702        mov.l           %d1,(%a6)               # Save incr value
18703        mov.l           %d0,%a0
18704        rts
18705
18706faddr_ind_p_a7:
18707        mov.b           &mia7_flg,SPCOND_FLG(%a6) # set "special case" flag
18708
18709        mov.l           EXC_A7(%a6),%d0         # Get current a7
18710        mov.l           %d0,%d1
18711        add.l           %a0,%d1                 # Increment
18712        mov.l           %d1,EXC_A7(%a6)         # Save incr value
18713        mov.l           %d0,%a0
18714        rts
18715
18716####################################################
18717# Address register indirect w/ predecrement: -(An) #
18718####################################################
18719faddr_ind_m_a0:
18720        mov.l           EXC_DREGS+0x8(%a6),%d0  # Get current a0
18721        sub.l           %a0,%d0                 # Decrement
18722        mov.l           %d0,EXC_DREGS+0x8(%a6)  # Save decr value
18723        mov.l           %d0,%a0
18724        rts
18725
18726faddr_ind_m_a1:
18727        mov.l           EXC_DREGS+0xc(%a6),%d0  # Get current a1
18728        sub.l           %a0,%d0                 # Decrement
18729        mov.l           %d0,EXC_DREGS+0xc(%a6)  # Save decr value
18730        mov.l           %d0,%a0
18731        rts
18732
18733faddr_ind_m_a2:
18734        mov.l           %a2,%d0                 # Get current a2
18735        sub.l           %a0,%d0                 # Decrement
18736        mov.l           %d0,%a2                 # Save decr value
18737        mov.l           %d0,%a0
18738        rts
18739
18740faddr_ind_m_a3:
18741        mov.l           %a3,%d0                 # Get current a3
18742        sub.l           %a0,%d0                 # Decrement
18743        mov.l           %d0,%a3                 # Save decr value
18744        mov.l           %d0,%a0
18745        rts
18746
18747faddr_ind_m_a4:
18748        mov.l           %a4,%d0                 # Get current a4
18749        sub.l           %a0,%d0                 # Decrement
18750        mov.l           %d0,%a4                 # Save decr value
18751        mov.l           %d0,%a0
18752        rts
18753
18754faddr_ind_m_a5:
18755        mov.l           %a5,%d0                 # Get current a5
18756        sub.l           %a0,%d0                 # Decrement
18757        mov.l           %d0,%a5                 # Save decr value
18758        mov.l           %d0,%a0
18759        rts
18760
18761faddr_ind_m_a6:
18762        mov.l           (%a6),%d0               # Get current a6
18763        sub.l           %a0,%d0                 # Decrement
18764        mov.l           %d0,(%a6)               # Save decr value
18765        mov.l           %d0,%a0
18766        rts
18767
18768faddr_ind_m_a7:
18769        mov.b           &mda7_flg,SPCOND_FLG(%a6) # set "special case" flag
18770
18771        mov.l           EXC_A7(%a6),%d0         # Get current a7
18772        sub.l           %a0,%d0                 # Decrement
18773        mov.l           %d0,EXC_A7(%a6)         # Save decr value
18774        mov.l           %d0,%a0
18775        rts
18776
18777########################################################
18778# Address register indirect w/ displacement: (d16, An) #
18779########################################################
18780faddr_ind_disp_a0:
18781        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
18782        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
18783        bsr.l           _imem_read_word
18784
18785        tst.l           %d1                     # did ifetch fail?
18786        bne.l           iea_iacc                # yes
18787
18788        mov.w           %d0,%a0                 # sign extend displacement
18789
18790        add.l           EXC_DREGS+0x8(%a6),%a0  # a0 + d16
18791        rts
18792
18793faddr_ind_disp_a1:
18794        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
18795        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
18796        bsr.l           _imem_read_word
18797
18798        tst.l           %d1                     # did ifetch fail?
18799        bne.l           iea_iacc                # yes
18800
18801        mov.w           %d0,%a0                 # sign extend displacement
18802
18803        add.l           EXC_DREGS+0xc(%a6),%a0  # a1 + d16
18804        rts
18805
18806faddr_ind_disp_a2:
18807        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
18808        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
18809        bsr.l           _imem_read_word
18810
18811        tst.l           %d1                     # did ifetch fail?
18812        bne.l           iea_iacc                # yes
18813
18814        mov.w           %d0,%a0                 # sign extend displacement
18815
18816        add.l           %a2,%a0                 # a2 + d16
18817        rts
18818
18819faddr_ind_disp_a3:
18820        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
18821        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
18822        bsr.l           _imem_read_word
18823
18824        tst.l           %d1                     # did ifetch fail?
18825        bne.l           iea_iacc                # yes
18826
18827        mov.w           %d0,%a0                 # sign extend displacement
18828
18829        add.l           %a3,%a0                 # a3 + d16
18830        rts
18831
18832faddr_ind_disp_a4:
18833        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
18834        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
18835        bsr.l           _imem_read_word
18836
18837        tst.l           %d1                     # did ifetch fail?
18838        bne.l           iea_iacc                # yes
18839
18840        mov.w           %d0,%a0                 # sign extend displacement
18841
18842        add.l           %a4,%a0                 # a4 + d16
18843        rts
18844
18845faddr_ind_disp_a5:
18846        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
18847        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
18848        bsr.l           _imem_read_word
18849
18850        tst.l           %d1                     # did ifetch fail?
18851        bne.l           iea_iacc                # yes
18852
18853        mov.w           %d0,%a0                 # sign extend displacement
18854
18855        add.l           %a5,%a0                 # a5 + d16
18856        rts
18857
18858faddr_ind_disp_a6:
18859        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
18860        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
18861        bsr.l           _imem_read_word
18862
18863        tst.l           %d1                     # did ifetch fail?
18864        bne.l           iea_iacc                # yes
18865
18866        mov.w           %d0,%a0                 # sign extend displacement
18867
18868        add.l           (%a6),%a0               # a6 + d16
18869        rts
18870
18871faddr_ind_disp_a7:
18872        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
18873        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
18874        bsr.l           _imem_read_word
18875
18876        tst.l           %d1                     # did ifetch fail?
18877        bne.l           iea_iacc                # yes
18878
18879        mov.w           %d0,%a0                 # sign extend displacement
18880
18881        add.l           EXC_A7(%a6),%a0         # a7 + d16
18882        rts
18883
18884########################################################################
18885# Address register indirect w/ index(8-bit displacement): (d8, An, Xn) #
18886#    "       "         "    w/   "  (base displacement): (bd, An, Xn)  #
18887# Memory indirect postindexed: ([bd, An], Xn, od)                      #
18888# Memory indirect preindexed: ([bd, An, Xn], od)                       #
18889########################################################################
18890faddr_ind_ext:
18891        addq.l          &0x8,%d1
18892        bsr.l           fetch_dreg              # fetch base areg
18893        mov.l           %d0,-(%sp)
18894
18895        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
18896        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
18897        bsr.l           _imem_read_word         # fetch extword in d0
18898
18899        tst.l           %d1                     # did ifetch fail?
18900        bne.l           iea_iacc                # yes
18901
18902        mov.l           (%sp)+,%a0
18903
18904        btst            &0x8,%d0
18905        bne.w           fcalc_mem_ind
18906
18907        mov.l           %d0,L_SCR1(%a6)         # hold opword
18908
18909        mov.l           %d0,%d1
18910        rol.w           &0x4,%d1
18911        andi.w          &0xf,%d1                # extract index regno
18912
18913# count on fetch_dreg() not to alter a0...
18914        bsr.l           fetch_dreg              # fetch index
18915
18916        mov.l           %d2,-(%sp)              # save d2
18917        mov.l           L_SCR1(%a6),%d2         # fetch opword
18918
18919        btst            &0xb,%d2                # is it word or long?
18920        bne.b           faii8_long
18921        ext.l           %d0                     # sign extend word index
18922faii8_long:
18923        mov.l           %d2,%d1
18924        rol.w           &0x7,%d1
18925        andi.l          &0x3,%d1                # extract scale value
18926
18927        lsl.l           %d1,%d0                 # shift index by scale
18928
18929        extb.l          %d2                     # sign extend displacement
18930        add.l           %d2,%d0                 # index + disp
18931        add.l           %d0,%a0                 # An + (index + disp)
18932
18933        mov.l           (%sp)+,%d2              # restore old d2
18934        rts
18935
18936###########################
18937# Absolute short: (XXX).W #
18938###########################
18939fabs_short:
18940        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
18941        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
18942        bsr.l           _imem_read_word         # fetch short address
18943
18944        tst.l           %d1                     # did ifetch fail?
18945        bne.l           iea_iacc                # yes
18946
18947        mov.w           %d0,%a0                 # return <ea> in a0
18948        rts
18949
18950##########################
18951# Absolute long: (XXX).L #
18952##########################
18953fabs_long:
18954        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
18955        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
18956        bsr.l           _imem_read_long         # fetch long address
18957
18958        tst.l           %d1                     # did ifetch fail?
18959        bne.l           iea_iacc                # yes
18960
18961        mov.l           %d0,%a0                 # return <ea> in a0
18962        rts
18963
18964#######################################################
18965# Program counter indirect w/ displacement: (d16, PC) #
18966#######################################################
18967fpc_ind:
18968        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
18969        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
18970        bsr.l           _imem_read_word         # fetch word displacement
18971
18972        tst.l           %d1                     # did ifetch fail?
18973        bne.l           iea_iacc                # yes
18974
18975        mov.w           %d0,%a0                 # sign extend displacement
18976
18977        add.l           EXC_EXTWPTR(%a6),%a0    # pc + d16
18978
18979# _imem_read_word() increased the extwptr by 2. need to adjust here.
18980        subq.l          &0x2,%a0                # adjust <ea>
18981        rts
18982
18983##########################################################
18984# PC indirect w/ index(8-bit displacement): (d8, PC, An) #
18985# "     "     w/   "  (base displacement): (bd, PC, An)  #
18986# PC memory indirect postindexed: ([bd, PC], Xn, od)     #
18987# PC memory indirect preindexed: ([bd, PC, Xn], od)      #
18988##########################################################
18989fpc_ind_ext:
18990        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
18991        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
18992        bsr.l           _imem_read_word         # fetch ext word
18993
18994        tst.l           %d1                     # did ifetch fail?
18995        bne.l           iea_iacc                # yes
18996
18997        mov.l           EXC_EXTWPTR(%a6),%a0    # put base in a0
18998        subq.l          &0x2,%a0                # adjust base
18999
19000        btst            &0x8,%d0                # is disp only 8 bits?
19001        bne.w           fcalc_mem_ind           # calc memory indirect
19002
19003        mov.l           %d0,L_SCR1(%a6)         # store opword
19004
19005        mov.l           %d0,%d1                 # make extword copy
19006        rol.w           &0x4,%d1                # rotate reg num into place
19007        andi.w          &0xf,%d1                # extract register number
19008
19009# count on fetch_dreg() not to alter a0...
19010        bsr.l           fetch_dreg              # fetch index
19011
19012        mov.l           %d2,-(%sp)              # save d2
19013        mov.l           L_SCR1(%a6),%d2         # fetch opword
19014
19015        btst            &0xb,%d2                # is index word or long?
19016        bne.b           fpii8_long              # long
19017        ext.l           %d0                     # sign extend word index
19018fpii8_long:
19019        mov.l           %d2,%d1
19020        rol.w           &0x7,%d1                # rotate scale value into place
19021        andi.l          &0x3,%d1                # extract scale value
19022
19023        lsl.l           %d1,%d0                 # shift index by scale
19024
19025        extb.l          %d2                     # sign extend displacement
19026        add.l           %d2,%d0                 # disp + index
19027        add.l           %d0,%a0                 # An + (index + disp)
19028
19029        mov.l           (%sp)+,%d2              # restore temp register
19030        rts
19031
19032# d2 = index
19033# d3 = base
19034# d4 = od
19035# d5 = extword
19036fcalc_mem_ind:
19037        btst            &0x6,%d0                # is the index suppressed?
19038        beq.b           fcalc_index
19039
19040        movm.l          &0x3c00,-(%sp)          # save d2-d5
19041
19042        mov.l           %d0,%d5                 # put extword in d5
19043        mov.l           %a0,%d3                 # put base in d3
19044
19045        clr.l           %d2                     # yes, so index = 0
19046        bra.b           fbase_supp_ck
19047
19048# index:
19049fcalc_index:
19050        mov.l           %d0,L_SCR1(%a6)         # save d0 (opword)
19051        bfextu          %d0{&16:&4},%d1         # fetch dreg index
19052        bsr.l           fetch_dreg
19053
19054        movm.l          &0x3c00,-(%sp)          # save d2-d5
19055        mov.l           %d0,%d2                 # put index in d2
19056        mov.l           L_SCR1(%a6),%d5
19057        mov.l           %a0,%d3
19058
19059        btst            &0xb,%d5                # is index word or long?
19060        bne.b           fno_ext
19061        ext.l           %d2
19062
19063fno_ext:
19064        bfextu          %d5{&21:&2},%d0
19065        lsl.l           %d0,%d2
19066
19067# base address (passed as parameter in d3):
19068# we clear the value here if it should actually be suppressed.
19069fbase_supp_ck:
19070        btst            &0x7,%d5                # is the bd suppressed?
19071        beq.b           fno_base_sup
19072        clr.l           %d3
19073
19074# base displacement:
19075fno_base_sup:
19076        bfextu          %d5{&26:&2},%d0         # get bd size
19077#       beq.l           fmovm_error             # if (size == 0) it's reserved
19078
19079        cmpi.b          %d0,&0x2
19080        blt.b           fno_bd
19081        beq.b           fget_word_bd
19082
19083        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
19084        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
19085        bsr.l           _imem_read_long
19086
19087        tst.l           %d1                     # did ifetch fail?
19088        bne.l           fcea_iacc               # yes
19089
19090        bra.b           fchk_ind
19091
19092fget_word_bd:
19093        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
19094        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
19095        bsr.l           _imem_read_word
19096
19097        tst.l           %d1                     # did ifetch fail?
19098        bne.l           fcea_iacc               # yes
19099
19100        ext.l           %d0                     # sign extend bd
19101
19102fchk_ind:
19103        add.l           %d0,%d3                 # base += bd
19104
19105# outer displacement:
19106fno_bd:
19107        bfextu          %d5{&30:&2},%d0         # is od suppressed?
19108        beq.w           faii_bd
19109
19110        cmpi.b          %d0,&0x2
19111        blt.b           fnull_od
19112        beq.b           fword_od
19113
19114        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
19115        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
19116        bsr.l           _imem_read_long
19117
19118        tst.l           %d1                     # did ifetch fail?
19119        bne.l           fcea_iacc               # yes
19120
19121        bra.b           fadd_them
19122
19123fword_od:
19124        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
19125        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
19126        bsr.l           _imem_read_word
19127
19128        tst.l           %d1                     # did ifetch fail?
19129        bne.l           fcea_iacc               # yes
19130
19131        ext.l           %d0                     # sign extend od
19132        bra.b           fadd_them
19133
19134fnull_od:
19135        clr.l           %d0
19136
19137fadd_them:
19138        mov.l           %d0,%d4
19139
19140        btst            &0x2,%d5                # pre or post indexing?
19141        beq.b           fpre_indexed
19142
19143        mov.l           %d3,%a0
19144        bsr.l           _dmem_read_long
19145
19146        tst.l           %d1                     # did dfetch fail?
19147        bne.w           fcea_err                # yes
19148
19149        add.l           %d2,%d0                 # <ea> += index
19150        add.l           %d4,%d0                 # <ea> += od
19151        bra.b           fdone_ea
19152
19153fpre_indexed:
19154        add.l           %d2,%d3                 # preindexing
19155        mov.l           %d3,%a0
19156        bsr.l           _dmem_read_long
19157
19158        tst.l           %d1                     # did dfetch fail?
19159        bne.w           fcea_err                # yes
19160
19161        add.l           %d4,%d0                 # ea += od
19162        bra.b           fdone_ea
19163
19164faii_bd:
19165        add.l           %d2,%d3                 # ea = (base + bd) + index
19166        mov.l           %d3,%d0
19167fdone_ea:
19168        mov.l           %d0,%a0
19169
19170        movm.l          (%sp)+,&0x003c          # restore d2-d5
19171        rts
19172
19173#########################################################
19174fcea_err:
19175        mov.l           %d3,%a0
19176
19177        movm.l          (%sp)+,&0x003c          # restore d2-d5
19178        mov.w           &0x0101,%d0
19179        bra.l           iea_dacc
19180
19181fcea_iacc:
19182        movm.l          (%sp)+,&0x003c          # restore d2-d5
19183        bra.l           iea_iacc
19184
19185fmovm_out_err:
19186        bsr.l           restore
19187        mov.w           &0x00e1,%d0
19188        bra.b           fmovm_err
19189
19190fmovm_in_err:
19191        bsr.l           restore
19192        mov.w           &0x0161,%d0
19193
19194fmovm_err:
19195        mov.l           L_SCR1(%a6),%a0
19196        bra.l           iea_dacc
19197
19198#########################################################################
19199# XDEF **************************************************************** #
19200#       fmovm_ctrl(): emulate fmovm.l of control registers instr        #
19201#                                                                       #
19202# XREF **************************************************************** #
19203#       _imem_read_long() - read longword from memory                   #
19204#       iea_iacc() - _imem_read_long() failed; error recovery           #
19205#                                                                       #
19206# INPUT *************************************************************** #
19207#       None                                                            #
19208#                                                                       #
19209# OUTPUT ************************************************************** #
19210#       If _imem_read_long() doesn't fail:                              #
19211#               USER_FPCR(a6)  = new FPCR value                         #
19212#               USER_FPSR(a6)  = new FPSR value                         #
19213#               USER_FPIAR(a6) = new FPIAR value                        #
19214#                                                                       #
19215# ALGORITHM *********************************************************** #
19216#       Decode the instruction type by looking at the extension word    #
19217# in order to see how many control registers to fetch from memory.      #
19218# Fetch them using _imem_read_long(). If this fetch fails, exit through #
19219# the special access error exit handler iea_iacc().                     #
19220#                                                                       #
19221# Instruction word decoding:                                            #
19222#                                                                       #
19223#       fmovem.l #<data>, {FPIAR&|FPCR&|FPSR}                           #
19224#                                                                       #
19225#               WORD1                   WORD2                           #
19226#       1111 0010 00 111100     100$ $$00 0000 0000                     #
19227#                                                                       #
19228#       $$$ (100): FPCR                                                 #
19229#           (010): FPSR                                                 #
19230#           (001): FPIAR                                                #
19231#           (000): FPIAR                                                #
19232#                                                                       #
19233#########################################################################
19234
19235        global          fmovm_ctrl
19236fmovm_ctrl:
19237        mov.b           EXC_EXTWORD(%a6),%d0    # fetch reg select bits
19238        cmpi.b          %d0,&0x9c               # fpcr & fpsr & fpiar ?
19239        beq.w           fctrl_in_7              # yes
19240        cmpi.b          %d0,&0x98               # fpcr & fpsr ?
19241        beq.w           fctrl_in_6              # yes
19242        cmpi.b          %d0,&0x94               # fpcr & fpiar ?
19243        beq.b           fctrl_in_5              # yes
19244
19245# fmovem.l #<data>, fpsr/fpiar
19246fctrl_in_3:
19247        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
19248        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
19249        bsr.l           _imem_read_long         # fetch FPSR from mem
19250
19251        tst.l           %d1                     # did ifetch fail?
19252        bne.l           iea_iacc                # yes
19253
19254        mov.l           %d0,USER_FPSR(%a6)      # store new FPSR to stack
19255        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
19256        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
19257        bsr.l           _imem_read_long         # fetch FPIAR from mem
19258
19259        tst.l           %d1                     # did ifetch fail?
19260        bne.l           iea_iacc                # yes
19261
19262        mov.l           %d0,USER_FPIAR(%a6)     # store new FPIAR to stack
19263        rts
19264
19265# fmovem.l #<data>, fpcr/fpiar
19266fctrl_in_5:
19267        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
19268        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
19269        bsr.l           _imem_read_long         # fetch FPCR from mem
19270
19271        tst.l           %d1                     # did ifetch fail?
19272        bne.l           iea_iacc                # yes
19273
19274        mov.l           %d0,USER_FPCR(%a6)      # store new FPCR to stack
19275        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
19276        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
19277        bsr.l           _imem_read_long         # fetch FPIAR from mem
19278
19279        tst.l           %d1                     # did ifetch fail?
19280        bne.l           iea_iacc                # yes
19281
19282        mov.l           %d0,USER_FPIAR(%a6)     # store new FPIAR to stack
19283        rts
19284
19285# fmovem.l #<data>, fpcr/fpsr
19286fctrl_in_6:
19287        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
19288        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
19289        bsr.l           _imem_read_long         # fetch FPCR from mem
19290
19291        tst.l           %d1                     # did ifetch fail?
19292        bne.l           iea_iacc                # yes
19293
19294        mov.l           %d0,USER_FPCR(%a6)      # store new FPCR to mem
19295        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
19296        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
19297        bsr.l           _imem_read_long         # fetch FPSR from mem
19298
19299        tst.l           %d1                     # did ifetch fail?
19300        bne.l           iea_iacc                # yes
19301
19302        mov.l           %d0,USER_FPSR(%a6)      # store new FPSR to mem
19303        rts
19304
19305# fmovem.l #<data>, fpcr/fpsr/fpiar
19306fctrl_in_7:
19307        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
19308        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
19309        bsr.l           _imem_read_long         # fetch FPCR from mem
19310
19311        tst.l           %d1                     # did ifetch fail?
19312        bne.l           iea_iacc                # yes
19313
19314        mov.l           %d0,USER_FPCR(%a6)      # store new FPCR to mem
19315        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
19316        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
19317        bsr.l           _imem_read_long         # fetch FPSR from mem
19318
19319        tst.l           %d1                     # did ifetch fail?
19320        bne.l           iea_iacc                # yes
19321
19322        mov.l           %d0,USER_FPSR(%a6)      # store new FPSR to mem
19323        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
19324        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
19325        bsr.l           _imem_read_long         # fetch FPIAR from mem
19326
19327        tst.l           %d1                     # did ifetch fail?
19328        bne.l           iea_iacc                # yes
19329
19330        mov.l           %d0,USER_FPIAR(%a6)     # store new FPIAR to mem
19331        rts
19332
19333#########################################################################
19334# XDEF **************************************************************** #
19335#       _dcalc_ea(): calc correct <ea> from <ea> stacked on exception   #
19336#                                                                       #
19337# XREF **************************************************************** #
19338#       inc_areg() - increment an address register                      #
19339#       dec_areg() - decrement an address register                      #
19340#                                                                       #
19341# INPUT *************************************************************** #
19342#       d0 = number of bytes to adjust <ea> by                          #
19343#                                                                       #
19344# OUTPUT ************************************************************** #
19345#       None                                                            #
19346#                                                                       #
19347# ALGORITHM *********************************************************** #
19348# "Dummy" CALCulate Effective Address:                                  #
19349#       The stacked <ea> for FP unimplemented instructions and opclass  #
19350#       two packed instructions is correct with the exception of...     #
19351#                                                                       #
19352#       1) -(An)   : The register is not updated regardless of size.    #
19353#                    Also, for extended precision and packed, the       #
19354#                    stacked <ea> value is 8 bytes too big              #
19355#       2) (An)+   : The register is not updated.                       #
19356#       3) #<data> : The upper longword of the immediate operand is     #
19357#                    stacked b,w,l and s sizes are completely stacked.  #
19358#                    d,x, and p are not.                                #
19359#                                                                       #
19360#########################################################################
19361
19362        global          _dcalc_ea
19363_dcalc_ea:
19364        mov.l           %d0, %a0                # move # bytes to %a0
19365
19366        mov.b           1+EXC_OPWORD(%a6), %d0  # fetch opcode word
19367        mov.l           %d0, %d1                # make a copy
19368
19369        andi.w          &0x38, %d0              # extract mode field
19370        andi.l          &0x7, %d1               # extract reg  field
19371
19372        cmpi.b          %d0,&0x18               # is mode (An)+ ?
19373        beq.b           dcea_pi                 # yes
19374
19375        cmpi.b          %d0,&0x20               # is mode -(An) ?
19376        beq.b           dcea_pd                 # yes
19377
19378        or.w            %d1,%d0                 # concat mode,reg
19379        cmpi.b          %d0,&0x3c               # is mode #<data>?
19380
19381        beq.b           dcea_imm                # yes
19382
19383        mov.l           EXC_EA(%a6),%a0         # return <ea>
19384        rts
19385
19386# need to set immediate data flag here since we'll need to do
19387# an imem_read to fetch this later.
19388dcea_imm:
19389        mov.b           &immed_flg,SPCOND_FLG(%a6)
19390        lea             ([USER_FPIAR,%a6],0x4),%a0 # no; return <ea>
19391        rts
19392
19393# here, the <ea> is stacked correctly. however, we must update the
19394# address register...
19395dcea_pi:
19396        mov.l           %a0,%d0                 # pass amt to inc by
19397        bsr.l           inc_areg                # inc addr register
19398
19399        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
19400        rts
19401
19402# the <ea> is stacked correctly for all but extended and packed which
19403# the <ea>s are 8 bytes too large.
19404# it would make no sense to have a pre-decrement to a7 in supervisor
19405# mode so we don't even worry about this tricky case here : )
19406dcea_pd:
19407        mov.l           %a0,%d0                 # pass amt to dec by
19408        bsr.l           dec_areg                # dec addr register
19409
19410        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
19411
19412        cmpi.b          %d0,&0xc                # is opsize ext or packed?
19413        beq.b           dcea_pd2                # yes
19414        rts
19415dcea_pd2:
19416        sub.l           &0x8,%a0                # correct <ea>
19417        mov.l           %a0,EXC_EA(%a6)         # put correct <ea> on stack
19418        rts
19419
19420#########################################################################
19421# XDEF **************************************************************** #
19422#       _calc_ea_fout(): calculate correct stacked <ea> for extended    #
19423#                        and packed data opclass 3 operations.          #
19424#                                                                       #
19425# XREF **************************************************************** #
19426#       None                                                            #
19427#                                                                       #
19428# INPUT *************************************************************** #
19429#       None                                                            #
19430#                                                                       #
19431# OUTPUT ************************************************************** #
19432#       a0 = return correct effective address                           #
19433#                                                                       #
19434# ALGORITHM *********************************************************** #
19435#       For opclass 3 extended and packed data operations, the <ea>     #
19436# stacked for the exception is incorrect for -(an) and (an)+ addressing #
19437# modes. Also, while we're at it, the index register itself must get    #
19438# updated.                                                              #
19439#       So, for -(an), we must subtract 8 off of the stacked <ea> value #
19440# and return that value as the correct <ea> and store that value in An. #
19441# For (an)+, the stacked <ea> is correct but we must adjust An by +12.  #
19442#                                                                       #
19443#########################################################################
19444
19445# This calc_ea is currently used to retrieve the correct <ea>
19446# for fmove outs of type extended and packed.
19447        global          _calc_ea_fout
19448_calc_ea_fout:
19449        mov.b           1+EXC_OPWORD(%a6),%d0   # fetch opcode word
19450        mov.l           %d0,%d1                 # make a copy
19451
19452        andi.w          &0x38,%d0               # extract mode field
19453        andi.l          &0x7,%d1                # extract reg  field
19454
19455        cmpi.b          %d0,&0x18               # is mode (An)+ ?
19456        beq.b           ceaf_pi                 # yes
19457
19458        cmpi.b          %d0,&0x20               # is mode -(An) ?
19459        beq.w           ceaf_pd                 # yes
19460
19461        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
19462        rts
19463
19464# (An)+ : extended and packed fmove out
19465#       : stacked <ea> is correct
19466#       : "An" not updated
19467ceaf_pi:
19468        mov.w           (tbl_ceaf_pi.b,%pc,%d1.w*2),%d1
19469        mov.l           EXC_EA(%a6),%a0
19470        jmp             (tbl_ceaf_pi.b,%pc,%d1.w*1)
19471
19472        swbeg           &0x8
19473tbl_ceaf_pi:
19474        short           ceaf_pi0 - tbl_ceaf_pi
19475        short           ceaf_pi1 - tbl_ceaf_pi
19476        short           ceaf_pi2 - tbl_ceaf_pi
19477        short           ceaf_pi3 - tbl_ceaf_pi
19478        short           ceaf_pi4 - tbl_ceaf_pi
19479        short           ceaf_pi5 - tbl_ceaf_pi
19480        short           ceaf_pi6 - tbl_ceaf_pi
19481        short           ceaf_pi7 - tbl_ceaf_pi
19482
19483ceaf_pi0:
19484        addi.l          &0xc,EXC_DREGS+0x8(%a6)
19485        rts
19486ceaf_pi1:
19487        addi.l          &0xc,EXC_DREGS+0xc(%a6)
19488        rts
19489ceaf_pi2:
19490        add.l           &0xc,%a2
19491        rts
19492ceaf_pi3:
19493        add.l           &0xc,%a3
19494        rts
19495ceaf_pi4:
19496        add.l           &0xc,%a4
19497        rts
19498ceaf_pi5:
19499        add.l           &0xc,%a5
19500        rts
19501ceaf_pi6:
19502        addi.l          &0xc,EXC_A6(%a6)
19503        rts
19504ceaf_pi7:
19505        mov.b           &mia7_flg,SPCOND_FLG(%a6)
19506        addi.l          &0xc,EXC_A7(%a6)
19507        rts
19508
19509# -(An) : extended and packed fmove out
19510#       : stacked <ea> = actual <ea> + 8
19511#       : "An" not updated
19512ceaf_pd:
19513        mov.w           (tbl_ceaf_pd.b,%pc,%d1.w*2),%d1
19514        mov.l           EXC_EA(%a6),%a0
19515        sub.l           &0x8,%a0
19516        sub.l           &0x8,EXC_EA(%a6)
19517        jmp             (tbl_ceaf_pd.b,%pc,%d1.w*1)
19518
19519        swbeg           &0x8
19520tbl_ceaf_pd:
19521        short           ceaf_pd0 - tbl_ceaf_pd
19522        short           ceaf_pd1 - tbl_ceaf_pd
19523        short           ceaf_pd2 - tbl_ceaf_pd
19524        short           ceaf_pd3 - tbl_ceaf_pd
19525        short           ceaf_pd4 - tbl_ceaf_pd
19526        short           ceaf_pd5 - tbl_ceaf_pd
19527        short           ceaf_pd6 - tbl_ceaf_pd
19528        short           ceaf_pd7 - tbl_ceaf_pd
19529
19530ceaf_pd0:
19531        mov.l           %a0,EXC_DREGS+0x8(%a6)
19532        rts
19533ceaf_pd1:
19534        mov.l           %a0,EXC_DREGS+0xc(%a6)
19535        rts
19536ceaf_pd2:
19537        mov.l           %a0,%a2
19538        rts
19539ceaf_pd3:
19540        mov.l           %a0,%a3
19541        rts
19542ceaf_pd4:
19543        mov.l           %a0,%a4
19544        rts
19545ceaf_pd5:
19546        mov.l           %a0,%a5
19547        rts
19548ceaf_pd6:
19549        mov.l           %a0,EXC_A6(%a6)
19550        rts
19551ceaf_pd7:
19552        mov.l           %a0,EXC_A7(%a6)
19553        mov.b           &mda7_flg,SPCOND_FLG(%a6)
19554        rts
19555
19556#########################################################################
19557# XDEF **************************************************************** #
19558#       _load_fop(): load operand for unimplemented FP exception        #
19559#                                                                       #
19560# XREF **************************************************************** #
19561#       set_tag_x() - determine ext prec optype tag                     #
19562#       set_tag_s() - determine sgl prec optype tag                     #
19563#       set_tag_d() - determine dbl prec optype tag                     #
19564#       unnorm_fix() - convert normalized number to denorm or zero      #
19565#       norm() - normalize a denormalized number                        #
19566#       get_packed() - fetch a packed operand from memory               #
19567#       _dcalc_ea() - calculate <ea>, fixing An in process              #
19568#                                                                       #
19569#       _imem_read_{word,long}() - read from instruction memory         #
19570#       _dmem_read() - read from data memory                            #
19571#       _dmem_read_{byte,word,long}() - read from data memory           #
19572#                                                                       #
19573#       facc_in_{b,w,l,d,x}() - mem read failed; special exit point     #
19574#                                                                       #
19575# INPUT *************************************************************** #
19576#       None                                                            #
19577#                                                                       #
19578# OUTPUT ************************************************************** #
19579#       If memory access doesn't fail:                                  #
19580#               FP_SRC(a6) = source operand in extended precision       #
19581#               FP_DST(a6) = destination operand in extended precision  #
19582#                                                                       #
19583# ALGORITHM *********************************************************** #
19584#       This is called from the Unimplemented FP exception handler in   #
19585# order to load the source and maybe destination operand into           #
19586# FP_SRC(a6) and FP_DST(a6). If the instruction was opclass zero, load  #
19587# the source and destination from the FP register file. Set the optype  #
19588# tags for both if dyadic, one for monadic. If a number is an UNNORM,   #
19589# convert it to a DENORM or a ZERO.                                     #
19590#       If the instruction is opclass two (memory->reg), then fetch     #
19591# the destination from the register file and the source operand from    #
19592# memory. Tag and fix both as above w/ opclass zero instructions.       #
19593#       If the source operand is byte,word,long, or single, it may be   #
19594# in the data register file. If it's actually out in memory, use one of #
19595# the mem_read() routines to fetch it. If the mem_read() access returns #
19596# a failing value, exit through the special facc_in() routine which     #
19597# will create an access error exception frame from the current exception #
19598# frame.                                                                #
19599#       Immediate data and regular data accesses are separated because  #
19600# if an immediate data access fails, the resulting fault status         #
19601# longword stacked for the access error exception must have the         #
19602# instruction bit set.                                                  #
19603#                                                                       #
19604#########################################################################
19605
19606        global          _load_fop
19607_load_fop:
19608
19609#  15     13 12 10  9 7  6       0
19610# /        \ /   \ /  \ /         \
19611# ---------------------------------
19612# | opclass | RX  | RY | EXTENSION |  (2nd word of general FP instruction)
19613# ---------------------------------
19614#
19615
19616#       bfextu          EXC_CMDREG(%a6){&0:&3}, %d0 # extract opclass
19617#       cmpi.b          %d0, &0x2               # which class is it? ('000,'010,'011)
19618#       beq.w           op010                   # handle <ea> -> fpn
19619#       bgt.w           op011                   # handle fpn -> <ea>
19620
19621# we're not using op011 for now...
19622        btst            &0x6,EXC_CMDREG(%a6)
19623        bne.b           op010
19624
19625############################
19626# OPCLASS '000: reg -> reg #
19627############################
19628op000:
19629        mov.b           1+EXC_CMDREG(%a6),%d0   # fetch extension word lo
19630        btst            &0x5,%d0                # testing extension bits
19631        beq.b           op000_src               # (bit 5 == 0) => monadic
19632        btst            &0x4,%d0                # (bit 5 == 1)
19633        beq.b           op000_dst               # (bit 4 == 0) => dyadic
19634        and.w           &0x007f,%d0             # extract extension bits {6:0}
19635        cmpi.w          %d0,&0x0038             # is it an fcmp (dyadic) ?
19636        bne.b           op000_src               # it's an fcmp
19637
19638op000_dst:
19639        bfextu          EXC_CMDREG(%a6){&6:&3}, %d0 # extract dst field
19640        bsr.l           load_fpn2               # fetch dst fpreg into FP_DST
19641
19642        bsr.l           set_tag_x               # get dst optype tag
19643
19644        cmpi.b          %d0, &UNNORM            # is dst fpreg an UNNORM?
19645        beq.b           op000_dst_unnorm        # yes
19646op000_dst_cont:
19647        mov.b           %d0, DTAG(%a6)          # store the dst optype tag
19648
19649op000_src:
19650        bfextu          EXC_CMDREG(%a6){&3:&3}, %d0 # extract src field
19651        bsr.l           load_fpn1               # fetch src fpreg into FP_SRC
19652
19653        bsr.l           set_tag_x               # get src optype tag
19654
19655        cmpi.b          %d0, &UNNORM            # is src fpreg an UNNORM?
19656        beq.b           op000_src_unnorm        # yes
19657op000_src_cont:
19658        mov.b           %d0, STAG(%a6)          # store the src optype tag
19659        rts
19660
19661op000_dst_unnorm:
19662        bsr.l           unnorm_fix              # fix the dst UNNORM
19663        bra.b           op000_dst_cont
19664op000_src_unnorm:
19665        bsr.l           unnorm_fix              # fix the src UNNORM
19666        bra.b           op000_src_cont
19667
19668#############################
19669# OPCLASS '010: <ea> -> reg #
19670#############################
19671op010:
19672        mov.w           EXC_CMDREG(%a6),%d0     # fetch extension word
19673        btst            &0x5,%d0                # testing extension bits
19674        beq.b           op010_src               # (bit 5 == 0) => monadic
19675        btst            &0x4,%d0                # (bit 5 == 1)
19676        beq.b           op010_dst               # (bit 4 == 0) => dyadic
19677        and.w           &0x007f,%d0             # extract extension bits {6:0}
19678        cmpi.w          %d0,&0x0038             # is it an fcmp (dyadic) ?
19679        bne.b           op010_src               # it's an fcmp
19680
19681op010_dst:
19682        bfextu          EXC_CMDREG(%a6){&6:&3}, %d0 # extract dst field
19683        bsr.l           load_fpn2               # fetch dst fpreg ptr
19684
19685        bsr.l           set_tag_x               # get dst type tag
19686
19687        cmpi.b          %d0, &UNNORM            # is dst fpreg an UNNORM?
19688        beq.b           op010_dst_unnorm        # yes
19689op010_dst_cont:
19690        mov.b           %d0, DTAG(%a6)          # store the dst optype tag
19691
19692op010_src:
19693        bfextu          EXC_CMDREG(%a6){&3:&3}, %d0 # extract src type field
19694
19695        bfextu          EXC_OPWORD(%a6){&10:&3}, %d1 # extract <ea> mode field
19696        bne.w           fetch_from_mem          # src op is in memory
19697
19698op010_dreg:
19699        clr.b           STAG(%a6)               # either NORM or ZERO
19700        bfextu          EXC_OPWORD(%a6){&13:&3}, %d1 # extract src reg field
19701
19702        mov.w           (tbl_op010_dreg.b,%pc,%d0.w*2), %d0 # jmp based on optype
19703        jmp             (tbl_op010_dreg.b,%pc,%d0.w*1) # fetch src from dreg
19704
19705op010_dst_unnorm:
19706        bsr.l           unnorm_fix              # fix the dst UNNORM
19707        bra.b           op010_dst_cont
19708
19709        swbeg           &0x8
19710tbl_op010_dreg:
19711        short           opd_long        - tbl_op010_dreg
19712        short           opd_sgl         - tbl_op010_dreg
19713        short           tbl_op010_dreg  - tbl_op010_dreg
19714        short           tbl_op010_dreg  - tbl_op010_dreg
19715        short           opd_word        - tbl_op010_dreg
19716        short           tbl_op010_dreg  - tbl_op010_dreg
19717        short           opd_byte        - tbl_op010_dreg
19718        short           tbl_op010_dreg  - tbl_op010_dreg
19719
19720#
19721# LONG: can be either NORM or ZERO...
19722#
19723opd_long:
19724        bsr.l           fetch_dreg              # fetch long in d0
19725        fmov.l          %d0, %fp0               # load a long
19726        fmovm.x         &0x80, FP_SRC(%a6)      # return src op in FP_SRC
19727        fbeq.w          opd_long_zero           # long is a ZERO
19728        rts
19729opd_long_zero:
19730        mov.b           &ZERO, STAG(%a6)        # set ZERO optype flag
19731        rts
19732
19733#
19734# WORD: can be either NORM or ZERO...
19735#
19736opd_word:
19737        bsr.l           fetch_dreg              # fetch word in d0
19738        fmov.w          %d0, %fp0               # load a word
19739        fmovm.x         &0x80, FP_SRC(%a6)      # return src op in FP_SRC
19740        fbeq.w          opd_word_zero           # WORD is a ZERO
19741        rts
19742opd_word_zero:
19743        mov.b           &ZERO, STAG(%a6)        # set ZERO optype flag
19744        rts
19745
19746#
19747# BYTE: can be either NORM or ZERO...
19748#
19749opd_byte:
19750        bsr.l           fetch_dreg              # fetch word in d0
19751        fmov.b          %d0, %fp0               # load a byte
19752        fmovm.x         &0x80, FP_SRC(%a6)      # return src op in FP_SRC
19753        fbeq.w          opd_byte_zero           # byte is a ZERO
19754        rts
19755opd_byte_zero:
19756        mov.b           &ZERO, STAG(%a6)        # set ZERO optype flag
19757        rts
19758
19759#
19760# SGL: can be either NORM, DENORM, ZERO, INF, QNAN or SNAN but not UNNORM
19761#
19762# separate SNANs and DENORMs so they can be loaded w/ special care.
19763# all others can simply be moved "in" using fmove.
19764#
19765opd_sgl:
19766        bsr.l           fetch_dreg              # fetch sgl in d0
19767        mov.l           %d0,L_SCR1(%a6)
19768
19769        lea             L_SCR1(%a6), %a0        # pass: ptr to the sgl
19770        bsr.l           set_tag_s               # determine sgl type
19771        mov.b           %d0, STAG(%a6)          # save the src tag
19772
19773        cmpi.b          %d0, &SNAN              # is it an SNAN?
19774        beq.w           get_sgl_snan            # yes
19775
19776        cmpi.b          %d0, &DENORM            # is it a DENORM?
19777        beq.w           get_sgl_denorm          # yes
19778
19779        fmov.s          (%a0), %fp0             # no, so can load it regular
19780        fmovm.x         &0x80, FP_SRC(%a6)      # return src op in FP_SRC
19781        rts
19782
19783##############################################################################
19784
19785#########################################################################
19786# fetch_from_mem():                                                     #
19787# - src is out in memory. must:                                         #
19788#       (1) calc ea - must read AFTER you know the src type since       #
19789#                     if the ea is -() or ()+, need to know # of bytes. #
19790#       (2) read it in from either user or supervisor space             #
19791#       (3) if (b || w || l) then simply read in                        #
19792#           if (s || d || x) then check for SNAN,UNNORM,DENORM          #
19793#           if (packed) then punt for now                               #
19794# INPUT:                                                                #
19795#       %d0 : src type field                                            #
19796#########################################################################
19797fetch_from_mem:
19798        clr.b           STAG(%a6)               # either NORM or ZERO
19799
19800        mov.w           (tbl_fp_type.b,%pc,%d0.w*2), %d0 # index by src type field
19801        jmp             (tbl_fp_type.b,%pc,%d0.w*1)
19802
19803        swbeg           &0x8
19804tbl_fp_type:
19805        short           load_long       - tbl_fp_type
19806        short           load_sgl        - tbl_fp_type
19807        short           load_ext        - tbl_fp_type
19808        short           load_packed     - tbl_fp_type
19809        short           load_word       - tbl_fp_type
19810        short           load_dbl        - tbl_fp_type
19811        short           load_byte       - tbl_fp_type
19812        short           tbl_fp_type     - tbl_fp_type
19813
19814#########################################
19815# load a LONG into %fp0:                #
19816#       -number can't fault             #
19817#       (1) calc ea                     #
19818#       (2) read 4 bytes into L_SCR1    #
19819#       (3) fmov.l into %fp0            #
19820#########################################
19821load_long:
19822        movq.l          &0x4, %d0               # pass: 4 (bytes)
19823        bsr.l           _dcalc_ea               # calc <ea>; <ea> in %a0
19824
19825        cmpi.b          SPCOND_FLG(%a6),&immed_flg
19826        beq.b           load_long_immed
19827
19828        bsr.l           _dmem_read_long         # fetch src operand from memory
19829
19830        tst.l           %d1                     # did dfetch fail?
19831        bne.l           facc_in_l               # yes
19832
19833load_long_cont:
19834        fmov.l          %d0, %fp0               # read into %fp0;convert to xprec
19835        fmovm.x         &0x80, FP_SRC(%a6)      # return src op in FP_SRC
19836
19837        fbeq.w          load_long_zero          # src op is a ZERO
19838        rts
19839load_long_zero:
19840        mov.b           &ZERO, STAG(%a6)        # set optype tag to ZERO
19841        rts
19842
19843load_long_immed:
19844        bsr.l           _imem_read_long         # fetch src operand immed data
19845
19846        tst.l           %d1                     # did ifetch fail?
19847        bne.l           funimp_iacc             # yes
19848        bra.b           load_long_cont
19849
19850#########################################
19851# load a WORD into %fp0:                #
19852#       -number can't fault             #
19853#       (1) calc ea                     #
19854#       (2) read 2 bytes into L_SCR1    #
19855#       (3) fmov.w into %fp0            #
19856#########################################
19857load_word:
19858        movq.l          &0x2, %d0               # pass: 2 (bytes)
19859        bsr.l           _dcalc_ea               # calc <ea>; <ea> in %a0
19860
19861        cmpi.b          SPCOND_FLG(%a6),&immed_flg
19862        beq.b           load_word_immed
19863
19864        bsr.l           _dmem_read_word         # fetch src operand from memory
19865
19866        tst.l           %d1                     # did dfetch fail?
19867        bne.l           facc_in_w               # yes
19868
19869load_word_cont:
19870        fmov.w          %d0, %fp0               # read into %fp0;convert to xprec
19871        fmovm.x         &0x80, FP_SRC(%a6)      # return src op in FP_SRC
19872
19873        fbeq.w          load_word_zero          # src op is a ZERO
19874        rts
19875load_word_zero:
19876        mov.b           &ZERO, STAG(%a6)        # set optype tag to ZERO
19877        rts
19878
19879load_word_immed:
19880        bsr.l           _imem_read_word         # fetch src operand immed data
19881
19882        tst.l           %d1                     # did ifetch fail?
19883        bne.l           funimp_iacc             # yes
19884        bra.b           load_word_cont
19885
19886#########################################
19887# load a BYTE into %fp0:                #
19888#       -number can't fault             #
19889#       (1) calc ea                     #
19890#       (2) read 1 byte into L_SCR1     #
19891#       (3) fmov.b into %fp0            #
19892#########################################
19893load_byte:
19894        movq.l          &0x1, %d0               # pass: 1 (byte)
19895        bsr.l           _dcalc_ea               # calc <ea>; <ea> in %a0
19896
19897        cmpi.b          SPCOND_FLG(%a6),&immed_flg
19898        beq.b           load_byte_immed
19899
19900        bsr.l           _dmem_read_byte         # fetch src operand from memory
19901
19902        tst.l           %d1                     # did dfetch fail?
19903        bne.l           facc_in_b               # yes
19904
19905load_byte_cont:
19906        fmov.b          %d0, %fp0               # read into %fp0;convert to xprec
19907        fmovm.x         &0x80, FP_SRC(%a6)      # return src op in FP_SRC
19908
19909        fbeq.w          load_byte_zero          # src op is a ZERO
19910        rts
19911load_byte_zero:
19912        mov.b           &ZERO, STAG(%a6)        # set optype tag to ZERO
19913        rts
19914
19915load_byte_immed:
19916        bsr.l           _imem_read_word         # fetch src operand immed data
19917
19918        tst.l           %d1                     # did ifetch fail?
19919        bne.l           funimp_iacc             # yes
19920        bra.b           load_byte_cont
19921
19922#########################################
19923# load a SGL into %fp0:                 #
19924#       -number can't fault             #
19925#       (1) calc ea                     #
19926#       (2) read 4 bytes into L_SCR1    #
19927#       (3) fmov.s into %fp0            #
19928#########################################
19929load_sgl:
19930        movq.l          &0x4, %d0               # pass: 4 (bytes)
19931        bsr.l           _dcalc_ea               # calc <ea>; <ea> in %a0
19932
19933        cmpi.b          SPCOND_FLG(%a6),&immed_flg
19934        beq.b           load_sgl_immed
19935
19936        bsr.l           _dmem_read_long         # fetch src operand from memory
19937        mov.l           %d0, L_SCR1(%a6)        # store src op on stack
19938
19939        tst.l           %d1                     # did dfetch fail?
19940        bne.l           facc_in_l               # yes
19941
19942load_sgl_cont:
19943        lea             L_SCR1(%a6), %a0        # pass: ptr to sgl src op
19944        bsr.l           set_tag_s               # determine src type tag
19945        mov.b           %d0, STAG(%a6)          # save src optype tag on stack
19946
19947        cmpi.b          %d0, &DENORM            # is it a sgl DENORM?
19948        beq.w           get_sgl_denorm          # yes
19949
19950        cmpi.b          %d0, &SNAN              # is it a sgl SNAN?
19951        beq.w           get_sgl_snan            # yes
19952
19953        fmov.s          L_SCR1(%a6), %fp0       # read into %fp0;convert to xprec
19954        fmovm.x         &0x80, FP_SRC(%a6)      # return src op in FP_SRC
19955        rts
19956
19957load_sgl_immed:
19958        bsr.l           _imem_read_long         # fetch src operand immed data
19959
19960        tst.l           %d1                     # did ifetch fail?
19961        bne.l           funimp_iacc             # yes
19962        bra.b           load_sgl_cont
19963
19964# must convert sgl denorm format to an Xprec denorm fmt suitable for
19965# normalization...
19966# %a0 : points to sgl denorm
19967get_sgl_denorm:
19968        clr.w           FP_SRC_EX(%a6)
19969        bfextu          (%a0){&9:&23}, %d0      # fetch sgl hi(_mantissa)
19970        lsl.l           &0x8, %d0
19971        mov.l           %d0, FP_SRC_HI(%a6)     # set ext hi(_mantissa)
19972        clr.l           FP_SRC_LO(%a6)          # set ext lo(_mantissa)
19973
19974        clr.w           FP_SRC_EX(%a6)
19975        btst            &0x7, (%a0)             # is sgn bit set?
19976        beq.b           sgl_dnrm_norm
19977        bset            &0x7, FP_SRC_EX(%a6)    # set sgn of xprec value
19978
19979sgl_dnrm_norm:
19980        lea             FP_SRC(%a6), %a0
19981        bsr.l           norm                    # normalize number
19982        mov.w           &0x3f81, %d1            # xprec exp = 0x3f81
19983        sub.w           %d0, %d1                # exp = 0x3f81 - shft amt.
19984        or.w            %d1, FP_SRC_EX(%a6)     # {sgn,exp}
19985
19986        mov.b           &NORM, STAG(%a6)        # fix src type tag
19987        rts
19988
19989# convert sgl to ext SNAN
19990# %a0 : points to sgl SNAN
19991get_sgl_snan:
19992        mov.w           &0x7fff, FP_SRC_EX(%a6) # set exp of SNAN
19993        bfextu          (%a0){&9:&23}, %d0
19994        lsl.l           &0x8, %d0               # extract and insert hi(man)
19995        mov.l           %d0, FP_SRC_HI(%a6)
19996        clr.l           FP_SRC_LO(%a6)
19997
19998        btst            &0x7, (%a0)             # see if sign of SNAN is set
19999        beq.b           no_sgl_snan_sgn
20000        bset            &0x7, FP_SRC_EX(%a6)
20001no_sgl_snan_sgn:
20002        rts
20003
20004#########################################
20005# load a DBL into %fp0:                 #
20006#       -number can't fault             #
20007#       (1) calc ea                     #
20008#       (2) read 8 bytes into L_SCR(1,2)#
20009#       (3) fmov.d into %fp0            #
20010#########################################
20011load_dbl:
20012        movq.l          &0x8, %d0               # pass: 8 (bytes)
20013        bsr.l           _dcalc_ea               # calc <ea>; <ea> in %a0
20014
20015        cmpi.b          SPCOND_FLG(%a6),&immed_flg
20016        beq.b           load_dbl_immed
20017
20018        lea             L_SCR1(%a6), %a1        # pass: ptr to input dbl tmp space
20019        movq.l          &0x8, %d0               # pass: # bytes to read
20020        bsr.l           _dmem_read              # fetch src operand from memory
20021
20022        tst.l           %d1                     # did dfetch fail?
20023        bne.l           facc_in_d               # yes
20024
20025load_dbl_cont:
20026        lea             L_SCR1(%a6), %a0        # pass: ptr to input dbl
20027        bsr.l           set_tag_d               # determine src type tag
20028        mov.b           %d0, STAG(%a6)          # set src optype tag
20029
20030        cmpi.b          %d0, &DENORM            # is it a dbl DENORM?
20031        beq.w           get_dbl_denorm          # yes
20032
20033        cmpi.b          %d0, &SNAN              # is it a dbl SNAN?
20034        beq.w           get_dbl_snan            # yes
20035
20036        fmov.d          L_SCR1(%a6), %fp0       # read into %fp0;convert to xprec
20037        fmovm.x         &0x80, FP_SRC(%a6)      # return src op in FP_SRC
20038        rts
20039
20040load_dbl_immed:
20041        lea             L_SCR1(%a6), %a1        # pass: ptr to input dbl tmp space
20042        movq.l          &0x8, %d0               # pass: # bytes to read
20043        bsr.l           _imem_read              # fetch src operand from memory
20044
20045        tst.l           %d1                     # did ifetch fail?
20046        bne.l           funimp_iacc             # yes
20047        bra.b           load_dbl_cont
20048
20049# must convert dbl denorm format to an Xprec denorm fmt suitable for
20050# normalization...
20051# %a0 : loc. of dbl denorm
20052get_dbl_denorm:
20053        clr.w           FP_SRC_EX(%a6)
20054        bfextu          (%a0){&12:&31}, %d0     # fetch hi(_mantissa)
20055        mov.l           %d0, FP_SRC_HI(%a6)
20056        bfextu          4(%a0){&11:&21}, %d0    # fetch lo(_mantissa)
20057        mov.l           &0xb, %d1
20058        lsl.l           %d1, %d0
20059        mov.l           %d0, FP_SRC_LO(%a6)
20060
20061        btst            &0x7, (%a0)             # is sgn bit set?
20062        beq.b           dbl_dnrm_norm
20063        bset            &0x7, FP_SRC_EX(%a6)    # set sgn of xprec value
20064
20065dbl_dnrm_norm:
20066        lea             FP_SRC(%a6), %a0
20067        bsr.l           norm                    # normalize number
20068        mov.w           &0x3c01, %d1            # xprec exp = 0x3c01
20069        sub.w           %d0, %d1                # exp = 0x3c01 - shft amt.
20070        or.w            %d1, FP_SRC_EX(%a6)     # {sgn,exp}
20071
20072        mov.b           &NORM, STAG(%a6)        # fix src type tag
20073        rts
20074
20075# convert dbl to ext SNAN
20076# %a0 : points to dbl SNAN
20077get_dbl_snan:
20078        mov.w           &0x7fff, FP_SRC_EX(%a6) # set exp of SNAN
20079
20080        bfextu          (%a0){&12:&31}, %d0     # fetch hi(_mantissa)
20081        mov.l           %d0, FP_SRC_HI(%a6)
20082        bfextu          4(%a0){&11:&21}, %d0    # fetch lo(_mantissa)
20083        mov.l           &0xb, %d1
20084        lsl.l           %d1, %d0
20085        mov.l           %d0, FP_SRC_LO(%a6)
20086
20087        btst            &0x7, (%a0)             # see if sign of SNAN is set
20088        beq.b           no_dbl_snan_sgn
20089        bset            &0x7, FP_SRC_EX(%a6)
20090no_dbl_snan_sgn:
20091        rts
20092
20093#################################################
20094# load a Xprec into %fp0:                       #
20095#       -number can't fault                     #
20096#       (1) calc ea                             #
20097#       (2) read 12 bytes into L_SCR(1,2)       #
20098#       (3) fmov.x into %fp0                    #
20099#################################################
20100load_ext:
20101        mov.l           &0xc, %d0               # pass: 12 (bytes)
20102        bsr.l           _dcalc_ea               # calc <ea>
20103
20104        lea             FP_SRC(%a6), %a1        # pass: ptr to input ext tmp space
20105        mov.l           &0xc, %d0               # pass: # of bytes to read
20106        bsr.l           _dmem_read              # fetch src operand from memory
20107
20108        tst.l           %d1                     # did dfetch fail?
20109        bne.l           facc_in_x               # yes
20110
20111        lea             FP_SRC(%a6), %a0        # pass: ptr to src op
20112        bsr.l           set_tag_x               # determine src type tag
20113
20114        cmpi.b          %d0, &UNNORM            # is the src op an UNNORM?
20115        beq.b           load_ext_unnorm         # yes
20116
20117        mov.b           %d0, STAG(%a6)          # store the src optype tag
20118        rts
20119
20120load_ext_unnorm:
20121        bsr.l           unnorm_fix              # fix the src UNNORM
20122        mov.b           %d0, STAG(%a6)          # store the src optype tag
20123        rts
20124
20125#################################################
20126# load a packed into %fp0:                      #
20127#       -number can't fault                     #
20128#       (1) calc ea                             #
20129#       (2) read 12 bytes into L_SCR(1,2,3)     #
20130#       (3) fmov.x into %fp0                    #
20131#################################################
20132load_packed:
20133        bsr.l           get_packed
20134
20135        lea             FP_SRC(%a6),%a0         # pass ptr to src op
20136        bsr.l           set_tag_x               # determine src type tag
20137        cmpi.b          %d0,&UNNORM             # is the src op an UNNORM ZERO?
20138        beq.b           load_packed_unnorm      # yes
20139
20140        mov.b           %d0,STAG(%a6)           # store the src optype tag
20141        rts
20142
20143load_packed_unnorm:
20144        bsr.l           unnorm_fix              # fix the UNNORM ZERO
20145        mov.b           %d0,STAG(%a6)           # store the src optype tag
20146        rts
20147
20148#########################################################################
20149# XDEF **************************************************************** #
20150#       fout(): move from fp register to memory or data register        #
20151#                                                                       #
20152# XREF **************************************************************** #
20153#       _round() - needed to create EXOP for sgl/dbl precision          #
20154#       norm() - needed to create EXOP for extended precision           #
20155#       ovf_res() - create default overflow result for sgl/dbl precision#
20156#       unf_res() - create default underflow result for sgl/dbl prec.   #
20157#       dst_dbl() - create rounded dbl precision result.                #
20158#       dst_sgl() - create rounded sgl precision result.                #
20159#       fetch_dreg() - fetch dynamic k-factor reg for packed.           #
20160#       bindec() - convert FP binary number to packed number.           #
20161#       _mem_write() - write data to memory.                            #
20162#       _mem_write2() - write data to memory unless supv mode -(a7) exc.#
20163#       _dmem_write_{byte,word,long}() - write data to memory.          #
20164#       store_dreg_{b,w,l}() - store data to data register file.        #
20165#       facc_out_{b,w,l,d,x}() - data access error occurred.            #
20166#                                                                       #
20167# INPUT *************************************************************** #
20168#       a0 = pointer to extended precision source operand               #
20169#       d0 = round prec,mode                                            #
20170#                                                                       #
20171# OUTPUT ************************************************************** #
20172#       fp0 : intermediate underflow or overflow result if              #
20173#             OVFL/UNFL occurred for a sgl or dbl operand               #
20174#                                                                       #
20175# ALGORITHM *********************************************************** #
20176#       This routine is accessed by many handlers that need to do an    #
20177# opclass three move of an operand out to memory.                       #
20178#       Decode an fmove out (opclass 3) instruction to determine if     #
20179# it's b,w,l,s,d,x, or p in size. b,w,l can be stored to either a data  #
20180# register or memory. The algorithm uses a standard "fmove" to create   #
20181# the rounded result. Also, since exceptions are disabled, this also    #
20182# create the correct OPERR default result if appropriate.               #
20183#       For sgl or dbl precision, overflow or underflow can occur. If   #
20184# either occurs and is enabled, the EXOP.                               #
20185#       For extended precision, the stacked <ea> must be fixed along    #
20186# w/ the address index register as appropriate w/ _calc_ea_fout(). If   #
20187# the source is a denorm and if underflow is enabled, an EXOP must be   #
20188# created.                                                              #
20189#       For packed, the k-factor must be fetched from the instruction   #
20190# word or a data register. The <ea> must be fixed as w/ extended        #
20191# precision. Then, bindec() is called to create the appropriate         #
20192# packed result.                                                        #
20193#       If at any time an access error is flagged by one of the move-   #
20194# to-memory routines, then a special exit must be made so that the      #
20195# access error can be handled properly.                                 #
20196#                                                                       #
20197#########################################################################
20198
20199        global          fout
20200fout:
20201        bfextu          EXC_CMDREG(%a6){&3:&3},%d1 # extract dst fmt
20202        mov.w           (tbl_fout.b,%pc,%d1.w*2),%a1 # use as index
20203        jmp             (tbl_fout.b,%pc,%a1)    # jump to routine
20204
20205        swbeg           &0x8
20206tbl_fout:
20207        short           fout_long       -       tbl_fout
20208        short           fout_sgl        -       tbl_fout
20209        short           fout_ext        -       tbl_fout
20210        short           fout_pack       -       tbl_fout
20211        short           fout_word       -       tbl_fout
20212        short           fout_dbl        -       tbl_fout
20213        short           fout_byte       -       tbl_fout
20214        short           fout_pack       -       tbl_fout
20215
20216#################################################################
20217# fmove.b out ###################################################
20218#################################################################
20219
20220# Only "Unimplemented Data Type" exceptions enter here. The operand
20221# is either a DENORM or a NORM.
20222fout_byte:
20223        tst.b           STAG(%a6)               # is operand normalized?
20224        bne.b           fout_byte_denorm        # no
20225
20226        fmovm.x         SRC(%a0),&0x80          # load value
20227
20228fout_byte_norm:
20229        fmov.l          %d0,%fpcr               # insert rnd prec,mode
20230
20231        fmov.b          %fp0,%d0                # exec move out w/ correct rnd mode
20232
20233        fmov.l          &0x0,%fpcr              # clear FPCR
20234        fmov.l          %fpsr,%d1               # fetch FPSR
20235        or.w            %d1,2+USER_FPSR(%a6)    # save new exc,accrued bits
20236
20237        mov.b           1+EXC_OPWORD(%a6),%d1   # extract dst mode
20238        andi.b          &0x38,%d1               # is mode == 0? (Dreg dst)
20239        beq.b           fout_byte_dn            # must save to integer regfile
20240
20241        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
20242        bsr.l           _dmem_write_byte        # write byte
20243
20244        tst.l           %d1                     # did dstore fail?
20245        bne.l           facc_out_b              # yes
20246
20247        rts
20248
20249fout_byte_dn:
20250        mov.b           1+EXC_OPWORD(%a6),%d1   # extract Dn
20251        andi.w          &0x7,%d1
20252        bsr.l           store_dreg_b
20253        rts
20254
20255fout_byte_denorm:
20256        mov.l           SRC_EX(%a0),%d1
20257        andi.l          &0x80000000,%d1         # keep DENORM sign
20258        ori.l           &0x00800000,%d1         # make smallest sgl
20259        fmov.s          %d1,%fp0
20260        bra.b           fout_byte_norm
20261
20262#################################################################
20263# fmove.w out ###################################################
20264#################################################################
20265
20266# Only "Unimplemented Data Type" exceptions enter here. The operand
20267# is either a DENORM or a NORM.
20268fout_word:
20269        tst.b           STAG(%a6)               # is operand normalized?
20270        bne.b           fout_word_denorm        # no
20271
20272        fmovm.x         SRC(%a0),&0x80          # load value
20273
20274fout_word_norm:
20275        fmov.l          %d0,%fpcr               # insert rnd prec:mode
20276
20277        fmov.w          %fp0,%d0                # exec move out w/ correct rnd mode
20278
20279        fmov.l          &0x0,%fpcr              # clear FPCR
20280        fmov.l          %fpsr,%d1               # fetch FPSR
20281        or.w            %d1,2+USER_FPSR(%a6)    # save new exc,accrued bits
20282
20283        mov.b           1+EXC_OPWORD(%a6),%d1   # extract dst mode
20284        andi.b          &0x38,%d1               # is mode == 0? (Dreg dst)
20285        beq.b           fout_word_dn            # must save to integer regfile
20286
20287        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
20288        bsr.l           _dmem_write_word        # write word
20289
20290        tst.l           %d1                     # did dstore fail?
20291        bne.l           facc_out_w              # yes
20292
20293        rts
20294
20295fout_word_dn:
20296        mov.b           1+EXC_OPWORD(%a6),%d1   # extract Dn
20297        andi.w          &0x7,%d1
20298        bsr.l           store_dreg_w
20299        rts
20300
20301fout_word_denorm:
20302        mov.l           SRC_EX(%a0),%d1
20303        andi.l          &0x80000000,%d1         # keep DENORM sign
20304        ori.l           &0x00800000,%d1         # make smallest sgl
20305        fmov.s          %d1,%fp0
20306        bra.b           fout_word_norm
20307
20308#################################################################
20309# fmove.l out ###################################################
20310#################################################################
20311
20312# Only "Unimplemented Data Type" exceptions enter here. The operand
20313# is either a DENORM or a NORM.
20314fout_long:
20315        tst.b           STAG(%a6)               # is operand normalized?
20316        bne.b           fout_long_denorm        # no
20317
20318        fmovm.x         SRC(%a0),&0x80          # load value
20319
20320fout_long_norm:
20321        fmov.l          %d0,%fpcr               # insert rnd prec:mode
20322
20323        fmov.l          %fp0,%d0                # exec move out w/ correct rnd mode
20324
20325        fmov.l          &0x0,%fpcr              # clear FPCR
20326        fmov.l          %fpsr,%d1               # fetch FPSR
20327        or.w            %d1,2+USER_FPSR(%a6)    # save new exc,accrued bits
20328
20329fout_long_write:
20330        mov.b           1+EXC_OPWORD(%a6),%d1   # extract dst mode
20331        andi.b          &0x38,%d1               # is mode == 0? (Dreg dst)
20332        beq.b           fout_long_dn            # must save to integer regfile
20333
20334        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
20335        bsr.l           _dmem_write_long        # write long
20336
20337        tst.l           %d1                     # did dstore fail?
20338        bne.l           facc_out_l              # yes
20339
20340        rts
20341
20342fout_long_dn:
20343        mov.b           1+EXC_OPWORD(%a6),%d1   # extract Dn
20344        andi.w          &0x7,%d1
20345        bsr.l           store_dreg_l
20346        rts
20347
20348fout_long_denorm:
20349        mov.l           SRC_EX(%a0),%d1
20350        andi.l          &0x80000000,%d1         # keep DENORM sign
20351        ori.l           &0x00800000,%d1         # make smallest sgl
20352        fmov.s          %d1,%fp0
20353        bra.b           fout_long_norm
20354
20355#################################################################
20356# fmove.x out ###################################################
20357#################################################################
20358
20359# Only "Unimplemented Data Type" exceptions enter here. The operand
20360# is either a DENORM or a NORM.
20361# The DENORM causes an Underflow exception.
20362fout_ext:
20363
20364# we copy the extended precision result to FP_SCR0 so that the reserved
20365# 16-bit field gets zeroed. we do this since we promise not to disturb
20366# what's at SRC(a0).
20367        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
20368        clr.w           2+FP_SCR0_EX(%a6)       # clear reserved field
20369        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
20370        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
20371
20372        fmovm.x         SRC(%a0),&0x80          # return result
20373
20374        bsr.l           _calc_ea_fout           # fix stacked <ea>
20375
20376        mov.l           %a0,%a1                 # pass: dst addr
20377        lea             FP_SCR0(%a6),%a0        # pass: src addr
20378        mov.l           &0xc,%d0                # pass: opsize is 12 bytes
20379
20380# we must not yet write the extended precision data to the stack
20381# in the pre-decrement case from supervisor mode or else we'll corrupt
20382# the stack frame. so, leave it in FP_SRC for now and deal with it later...
20383        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
20384        beq.b           fout_ext_a7
20385
20386        bsr.l           _dmem_write             # write ext prec number to memory
20387
20388        tst.l           %d1                     # did dstore fail?
20389        bne.w           fout_ext_err            # yes
20390
20391        tst.b           STAG(%a6)               # is operand normalized?
20392        bne.b           fout_ext_denorm         # no
20393        rts
20394
20395# the number is a DENORM. must set the underflow exception bit
20396fout_ext_denorm:
20397        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set underflow exc bit
20398
20399        mov.b           FPCR_ENABLE(%a6),%d0
20400        andi.b          &0x0a,%d0               # is UNFL or INEX enabled?
20401        bne.b           fout_ext_exc            # yes
20402        rts
20403
20404# we don't want to do the write if the exception occurred in supervisor mode
20405# so _mem_write2() handles this for us.
20406fout_ext_a7:
20407        bsr.l           _mem_write2             # write ext prec number to memory
20408
20409        tst.l           %d1                     # did dstore fail?
20410        bne.w           fout_ext_err            # yes
20411
20412        tst.b           STAG(%a6)               # is operand normalized?
20413        bne.b           fout_ext_denorm         # no
20414        rts
20415
20416fout_ext_exc:
20417        lea             FP_SCR0(%a6),%a0
20418        bsr.l           norm                    # normalize the mantissa
20419        neg.w           %d0                     # new exp = -(shft amt)
20420        andi.w          &0x7fff,%d0
20421        andi.w          &0x8000,FP_SCR0_EX(%a6) # keep only old sign
20422        or.w            %d0,FP_SCR0_EX(%a6)     # insert new exponent
20423        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
20424        rts
20425
20426fout_ext_err:
20427        mov.l           EXC_A6(%a6),(%a6)       # fix stacked a6
20428        bra.l           facc_out_x
20429
20430#########################################################################
20431# fmove.s out ###########################################################
20432#########################################################################
20433fout_sgl:
20434        andi.b          &0x30,%d0               # clear rnd prec
20435        ori.b           &s_mode*0x10,%d0        # insert sgl prec
20436        mov.l           %d0,L_SCR3(%a6)         # save rnd prec,mode on stack
20437
20438#
20439# operand is a normalized number. first, we check to see if the move out
20440# would cause either an underflow or overflow. these cases are handled
20441# separately. otherwise, set the FPCR to the proper rounding mode and
20442# execute the move.
20443#
20444        mov.w           SRC_EX(%a0),%d0         # extract exponent
20445        andi.w          &0x7fff,%d0             # strip sign
20446
20447        cmpi.w          %d0,&SGL_HI             # will operand overflow?
20448        bgt.w           fout_sgl_ovfl           # yes; go handle OVFL
20449        beq.w           fout_sgl_may_ovfl       # maybe; go handle possible OVFL
20450        cmpi.w          %d0,&SGL_LO             # will operand underflow?
20451        blt.w           fout_sgl_unfl           # yes; go handle underflow
20452
20453#
20454# NORMs(in range) can be stored out by a simple "fmov.s"
20455# Unnormalized inputs can come through this point.
20456#
20457fout_sgl_exg:
20458        fmovm.x         SRC(%a0),&0x80          # fetch fop from stack
20459
20460        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
20461        fmov.l          &0x0,%fpsr              # clear FPSR
20462
20463        fmov.s          %fp0,%d0                # store does convert and round
20464
20465        fmov.l          &0x0,%fpcr              # clear FPCR
20466        fmov.l          %fpsr,%d1               # save FPSR
20467
20468        or.w            %d1,2+USER_FPSR(%a6)    # set possible inex2/ainex
20469
20470fout_sgl_exg_write:
20471        mov.b           1+EXC_OPWORD(%a6),%d1   # extract dst mode
20472        andi.b          &0x38,%d1               # is mode == 0? (Dreg dst)
20473        beq.b           fout_sgl_exg_write_dn   # must save to integer regfile
20474
20475        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
20476        bsr.l           _dmem_write_long        # write long
20477
20478        tst.l           %d1                     # did dstore fail?
20479        bne.l           facc_out_l              # yes
20480
20481        rts
20482
20483fout_sgl_exg_write_dn:
20484        mov.b           1+EXC_OPWORD(%a6),%d1   # extract Dn
20485        andi.w          &0x7,%d1
20486        bsr.l           store_dreg_l
20487        rts
20488
20489#
20490# here, we know that the operand would UNFL if moved out to single prec,
20491# so, denorm and round and then use generic store single routine to
20492# write the value to memory.
20493#
20494fout_sgl_unfl:
20495        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set UNFL
20496
20497        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
20498        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
20499        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
20500        mov.l           %a0,-(%sp)
20501
20502        clr.l           %d0                     # pass: S.F. = 0
20503
20504        cmpi.b          STAG(%a6),&DENORM       # fetch src optype tag
20505        bne.b           fout_sgl_unfl_cont      # let DENORMs fall through
20506
20507        lea             FP_SCR0(%a6),%a0
20508        bsr.l           norm                    # normalize the DENORM
20509
20510fout_sgl_unfl_cont:
20511        lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
20512        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
20513        bsr.l           unf_res                 # calc default underflow result
20514
20515        lea             FP_SCR0(%a6),%a0        # pass: ptr to fop
20516        bsr.l           dst_sgl                 # convert to single prec
20517
20518        mov.b           1+EXC_OPWORD(%a6),%d1   # extract dst mode
20519        andi.b          &0x38,%d1               # is mode == 0? (Dreg dst)
20520        beq.b           fout_sgl_unfl_dn        # must save to integer regfile
20521
20522        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
20523        bsr.l           _dmem_write_long        # write long
20524
20525        tst.l           %d1                     # did dstore fail?
20526        bne.l           facc_out_l              # yes
20527
20528        bra.b           fout_sgl_unfl_chkexc
20529
20530fout_sgl_unfl_dn:
20531        mov.b           1+EXC_OPWORD(%a6),%d1   # extract Dn
20532        andi.w          &0x7,%d1
20533        bsr.l           store_dreg_l
20534
20535fout_sgl_unfl_chkexc:
20536        mov.b           FPCR_ENABLE(%a6),%d1
20537        andi.b          &0x0a,%d1               # is UNFL or INEX enabled?
20538        bne.w           fout_sd_exc_unfl        # yes
20539        addq.l          &0x4,%sp
20540        rts
20541
20542#
20543# it's definitely an overflow so call ovf_res to get the correct answer
20544#
20545fout_sgl_ovfl:
20546        tst.b           3+SRC_HI(%a0)           # is result inexact?
20547        bne.b           fout_sgl_ovfl_inex2
20548        tst.l           SRC_LO(%a0)             # is result inexact?
20549        bne.b           fout_sgl_ovfl_inex2
20550        ori.w           &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex
20551        bra.b           fout_sgl_ovfl_cont
20552fout_sgl_ovfl_inex2:
20553        ori.w           &ovfinx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex/inex2
20554
20555fout_sgl_ovfl_cont:
20556        mov.l           %a0,-(%sp)
20557
20558# call ovf_res() w/ sgl prec and the correct rnd mode to create the default
20559# overflow result. DON'T save the returned ccodes from ovf_res() since
20560# fmove out doesn't alter them.
20561        tst.b           SRC_EX(%a0)             # is operand negative?
20562        smi             %d1                     # set if so
20563        mov.l           L_SCR3(%a6),%d0         # pass: sgl prec,rnd mode
20564        bsr.l           ovf_res                 # calc OVFL result
20565        fmovm.x         (%a0),&0x80             # load default overflow result
20566        fmov.s          %fp0,%d0                # store to single
20567
20568        mov.b           1+EXC_OPWORD(%a6),%d1   # extract dst mode
20569        andi.b          &0x38,%d1               # is mode == 0? (Dreg dst)
20570        beq.b           fout_sgl_ovfl_dn        # must save to integer regfile
20571
20572        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
20573        bsr.l           _dmem_write_long        # write long
20574
20575        tst.l           %d1                     # did dstore fail?
20576        bne.l           facc_out_l              # yes
20577
20578        bra.b           fout_sgl_ovfl_chkexc
20579
20580fout_sgl_ovfl_dn:
20581        mov.b           1+EXC_OPWORD(%a6),%d1   # extract Dn
20582        andi.w          &0x7,%d1
20583        bsr.l           store_dreg_l
20584
20585fout_sgl_ovfl_chkexc:
20586        mov.b           FPCR_ENABLE(%a6),%d1
20587        andi.b          &0x0a,%d1               # is UNFL or INEX enabled?
20588        bne.w           fout_sd_exc_ovfl        # yes
20589        addq.l          &0x4,%sp
20590        rts
20591
20592#
20593# move out MAY overflow:
20594# (1) force the exp to 0x3fff
20595# (2) do a move w/ appropriate rnd mode
20596# (3) if exp still equals zero, then insert original exponent
20597#       for the correct result.
20598#     if exp now equals one, then it overflowed so call ovf_res.
20599#
20600fout_sgl_may_ovfl:
20601        mov.w           SRC_EX(%a0),%d1         # fetch current sign
20602        andi.w          &0x8000,%d1             # keep it,clear exp
20603        ori.w           &0x3fff,%d1             # insert exp = 0
20604        mov.w           %d1,FP_SCR0_EX(%a6)     # insert scaled exp
20605        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6) # copy hi(man)
20606        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6) # copy lo(man)
20607
20608        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
20609
20610        fmov.x          FP_SCR0(%a6),%fp0       # force fop to be rounded
20611        fmov.l          &0x0,%fpcr              # clear FPCR
20612
20613        fabs.x          %fp0                    # need absolute value
20614        fcmp.b          %fp0,&0x2               # did exponent increase?
20615        fblt.w          fout_sgl_exg            # no; go finish NORM
20616        bra.w           fout_sgl_ovfl           # yes; go handle overflow
20617
20618################
20619
20620fout_sd_exc_unfl:
20621        mov.l           (%sp)+,%a0
20622
20623        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
20624        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
20625        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
20626
20627        cmpi.b          STAG(%a6),&DENORM       # was src a DENORM?
20628        bne.b           fout_sd_exc_cont        # no
20629
20630        lea             FP_SCR0(%a6),%a0
20631        bsr.l           norm
20632        neg.l           %d0
20633        andi.w          &0x7fff,%d0
20634        bfins           %d0,FP_SCR0_EX(%a6){&1:&15}
20635        bra.b           fout_sd_exc_cont
20636
20637fout_sd_exc:
20638fout_sd_exc_ovfl:
20639        mov.l           (%sp)+,%a0              # restore a0
20640
20641        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
20642        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
20643        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
20644
20645fout_sd_exc_cont:
20646        bclr            &0x7,FP_SCR0_EX(%a6)    # clear sign bit
20647        sne.b           2+FP_SCR0_EX(%a6)       # set internal sign bit
20648        lea             FP_SCR0(%a6),%a0        # pass: ptr to DENORM
20649
20650        mov.b           3+L_SCR3(%a6),%d1
20651        lsr.b           &0x4,%d1
20652        andi.w          &0x0c,%d1
20653        swap            %d1
20654        mov.b           3+L_SCR3(%a6),%d1
20655        lsr.b           &0x4,%d1
20656        andi.w          &0x03,%d1
20657        clr.l           %d0                     # pass: zero g,r,s
20658        bsr.l           _round                  # round the DENORM
20659
20660        tst.b           2+FP_SCR0_EX(%a6)       # is EXOP negative?
20661        beq.b           fout_sd_exc_done        # no
20662        bset            &0x7,FP_SCR0_EX(%a6)    # yes
20663
20664fout_sd_exc_done:
20665        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
20666        rts
20667
20668#################################################################
20669# fmove.d out ###################################################
20670#################################################################
20671fout_dbl:
20672        andi.b          &0x30,%d0               # clear rnd prec
20673        ori.b           &d_mode*0x10,%d0        # insert dbl prec
20674        mov.l           %d0,L_SCR3(%a6)         # save rnd prec,mode on stack
20675
20676#
20677# operand is a normalized number. first, we check to see if the move out
20678# would cause either an underflow or overflow. these cases are handled
20679# separately. otherwise, set the FPCR to the proper rounding mode and
20680# execute the move.
20681#
20682        mov.w           SRC_EX(%a0),%d0         # extract exponent
20683        andi.w          &0x7fff,%d0             # strip sign
20684
20685        cmpi.w          %d0,&DBL_HI             # will operand overflow?
20686        bgt.w           fout_dbl_ovfl           # yes; go handle OVFL
20687        beq.w           fout_dbl_may_ovfl       # maybe; go handle possible OVFL
20688        cmpi.w          %d0,&DBL_LO             # will operand underflow?
20689        blt.w           fout_dbl_unfl           # yes; go handle underflow
20690
20691#
20692# NORMs(in range) can be stored out by a simple "fmov.d"
20693# Unnormalized inputs can come through this point.
20694#
20695fout_dbl_exg:
20696        fmovm.x         SRC(%a0),&0x80          # fetch fop from stack
20697
20698        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
20699        fmov.l          &0x0,%fpsr              # clear FPSR
20700
20701        fmov.d          %fp0,L_SCR1(%a6)        # store does convert and round
20702
20703        fmov.l          &0x0,%fpcr              # clear FPCR
20704        fmov.l          %fpsr,%d0               # save FPSR
20705
20706        or.w            %d0,2+USER_FPSR(%a6)    # set possible inex2/ainex
20707
20708        mov.l           EXC_EA(%a6),%a1         # pass: dst addr
20709        lea             L_SCR1(%a6),%a0         # pass: src addr
20710        movq.l          &0x8,%d0                # pass: opsize is 8 bytes
20711        bsr.l           _dmem_write             # store dbl fop to memory
20712
20713        tst.l           %d1                     # did dstore fail?
20714        bne.l           facc_out_d              # yes
20715
20716        rts                                     # no; so we're finished
20717
20718#
20719# here, we know that the operand would UNFL if moved out to double prec,
20720# so, denorm and round and then use generic store double routine to
20721# write the value to memory.
20722#
20723fout_dbl_unfl:
20724        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set UNFL
20725
20726        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
20727        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
20728        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
20729        mov.l           %a0,-(%sp)
20730
20731        clr.l           %d0                     # pass: S.F. = 0
20732
20733        cmpi.b          STAG(%a6),&DENORM       # fetch src optype tag
20734        bne.b           fout_dbl_unfl_cont      # let DENORMs fall through
20735
20736        lea             FP_SCR0(%a6),%a0
20737        bsr.l           norm                    # normalize the DENORM
20738
20739fout_dbl_unfl_cont:
20740        lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
20741        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
20742        bsr.l           unf_res                 # calc default underflow result
20743
20744        lea             FP_SCR0(%a6),%a0        # pass: ptr to fop
20745        bsr.l           dst_dbl                 # convert to single prec
20746        mov.l           %d0,L_SCR1(%a6)
20747        mov.l           %d1,L_SCR2(%a6)
20748
20749        mov.l           EXC_EA(%a6),%a1         # pass: dst addr
20750        lea             L_SCR1(%a6),%a0         # pass: src addr
20751        movq.l          &0x8,%d0                # pass: opsize is 8 bytes
20752        bsr.l           _dmem_write             # store dbl fop to memory
20753
20754        tst.l           %d1                     # did dstore fail?
20755        bne.l           facc_out_d              # yes
20756
20757        mov.b           FPCR_ENABLE(%a6),%d1
20758        andi.b          &0x0a,%d1               # is UNFL or INEX enabled?
20759        bne.w           fout_sd_exc_unfl        # yes
20760        addq.l          &0x4,%sp
20761        rts
20762
20763#
20764# it's definitely an overflow so call ovf_res to get the correct answer
20765#
20766fout_dbl_ovfl:
20767        mov.w           2+SRC_LO(%a0),%d0
20768        andi.w          &0x7ff,%d0
20769        bne.b           fout_dbl_ovfl_inex2
20770
20771        ori.w           &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex
20772        bra.b           fout_dbl_ovfl_cont
20773fout_dbl_ovfl_inex2:
20774        ori.w           &ovfinx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex/inex2
20775
20776fout_dbl_ovfl_cont:
20777        mov.l           %a0,-(%sp)
20778
20779# call ovf_res() w/ dbl prec and the correct rnd mode to create the default
20780# overflow result. DON'T save the returned ccodes from ovf_res() since
20781# fmove out doesn't alter them.
20782        tst.b           SRC_EX(%a0)             # is operand negative?
20783        smi             %d1                     # set if so
20784        mov.l           L_SCR3(%a6),%d0         # pass: dbl prec,rnd mode
20785        bsr.l           ovf_res                 # calc OVFL result
20786        fmovm.x         (%a0),&0x80             # load default overflow result
20787        fmov.d          %fp0,L_SCR1(%a6)        # store to double
20788
20789        mov.l           EXC_EA(%a6),%a1         # pass: dst addr
20790        lea             L_SCR1(%a6),%a0         # pass: src addr
20791        movq.l          &0x8,%d0                # pass: opsize is 8 bytes
20792        bsr.l           _dmem_write             # store dbl fop to memory
20793
20794        tst.l           %d1                     # did dstore fail?
20795        bne.l           facc_out_d              # yes
20796
20797        mov.b           FPCR_ENABLE(%a6),%d1
20798        andi.b          &0x0a,%d1               # is UNFL or INEX enabled?
20799        bne.w           fout_sd_exc_ovfl        # yes
20800        addq.l          &0x4,%sp
20801        rts
20802
20803#
20804# move out MAY overflow:
20805# (1) force the exp to 0x3fff
20806# (2) do a move w/ appropriate rnd mode
20807# (3) if exp still equals zero, then insert original exponent
20808#       for the correct result.
20809#     if exp now equals one, then it overflowed so call ovf_res.
20810#
20811fout_dbl_may_ovfl:
20812        mov.w           SRC_EX(%a0),%d1         # fetch current sign
20813        andi.w          &0x8000,%d1             # keep it,clear exp
20814        ori.w           &0x3fff,%d1             # insert exp = 0
20815        mov.w           %d1,FP_SCR0_EX(%a6)     # insert scaled exp
20816        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6) # copy hi(man)
20817        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6) # copy lo(man)
20818
20819        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
20820
20821        fmov.x          FP_SCR0(%a6),%fp0       # force fop to be rounded
20822        fmov.l          &0x0,%fpcr              # clear FPCR
20823
20824        fabs.x          %fp0                    # need absolute value
20825        fcmp.b          %fp0,&0x2               # did exponent increase?
20826        fblt.w          fout_dbl_exg            # no; go finish NORM
20827        bra.w           fout_dbl_ovfl           # yes; go handle overflow
20828
20829#########################################################################
20830# XDEF **************************************************************** #
20831#       dst_dbl(): create double precision value from extended prec.    #
20832#                                                                       #
20833# XREF **************************************************************** #
20834#       None                                                            #
20835#                                                                       #
20836# INPUT *************************************************************** #
20837#       a0 = pointer to source operand in extended precision            #
20838#                                                                       #
20839# OUTPUT ************************************************************** #
20840#       d0 = hi(double precision result)                                #
20841#       d1 = lo(double precision result)                                #
20842#                                                                       #
20843# ALGORITHM *********************************************************** #
20844#                                                                       #
20845#  Changes extended precision to double precision.                      #
20846#  Note: no attempt is made to round the extended value to double.      #
20847#       dbl_sign = ext_sign                                             #
20848#       dbl_exp = ext_exp - $3fff(ext bias) + $7ff(dbl bias)            #
20849#       get rid of ext integer bit                                      #
20850#       dbl_mant = ext_mant{62:12}                                      #
20851#                                                                       #
20852#               ---------------   ---------------    ---------------    #
20853#  extended ->  |s|    exp    |   |1| ms mant   |    | ls mant     |    #
20854#               ---------------   ---------------    ---------------    #
20855#                95         64    63 62       32      31     11   0     #
20856#                                    |                       |          #
20857#                                    |                       |          #
20858#                                    |                       |          #
20859#                                    v                       v          #
20860#                             ---------------   ---------------         #
20861#  double   ->                |s|exp| mant  |   |  mant       |         #
20862#                             ---------------   ---------------         #
20863#                             63     51   32   31              0        #
20864#                                                                       #
20865#########################################################################
20866
20867dst_dbl:
20868        clr.l           %d0                     # clear d0
20869        mov.w           FTEMP_EX(%a0),%d0       # get exponent
20870        subi.w          &EXT_BIAS,%d0           # subtract extended precision bias
20871        addi.w          &DBL_BIAS,%d0           # add double precision bias
20872        tst.b           FTEMP_HI(%a0)           # is number a denorm?
20873        bmi.b           dst_get_dupper          # no
20874        subq.w          &0x1,%d0                # yes; denorm bias = DBL_BIAS - 1
20875dst_get_dupper:
20876        swap            %d0                     # d0 now in upper word
20877        lsl.l           &0x4,%d0                # d0 in proper place for dbl prec exp
20878        tst.b           FTEMP_EX(%a0)           # test sign
20879        bpl.b           dst_get_dman            # if positive, go process mantissa
20880        bset            &0x1f,%d0               # if negative, set sign
20881dst_get_dman:
20882        mov.l           FTEMP_HI(%a0),%d1       # get ms mantissa
20883        bfextu          %d1{&1:&20},%d1         # get upper 20 bits of ms
20884        or.l            %d1,%d0                 # put these bits in ms word of double
20885        mov.l           %d0,L_SCR1(%a6)         # put the new exp back on the stack
20886        mov.l           FTEMP_HI(%a0),%d1       # get ms mantissa
20887        mov.l           &21,%d0                 # load shift count
20888        lsl.l           %d0,%d1                 # put lower 11 bits in upper bits
20889        mov.l           %d1,L_SCR2(%a6)         # build lower lword in memory
20890        mov.l           FTEMP_LO(%a0),%d1       # get ls mantissa
20891        bfextu          %d1{&0:&21},%d0         # get ls 21 bits of double
20892        mov.l           L_SCR2(%a6),%d1
20893        or.l            %d0,%d1                 # put them in double result
20894        mov.l           L_SCR1(%a6),%d0
20895        rts
20896
20897#########################################################################
20898# XDEF **************************************************************** #
20899#       dst_sgl(): create single precision value from extended prec     #
20900#                                                                       #
20901# XREF **************************************************************** #
20902#                                                                       #
20903# INPUT *************************************************************** #
20904#       a0 = pointer to source operand in extended precision            #
20905#                                                                       #
20906# OUTPUT ************************************************************** #
20907#       d0 = single precision result                                    #
20908#                                                                       #
20909# ALGORITHM *********************************************************** #
20910#                                                                       #
20911# Changes extended precision to single precision.                       #
20912#       sgl_sign = ext_sign                                             #
20913#       sgl_exp = ext_exp - $3fff(ext bias) + $7f(sgl bias)             #
20914#       get rid of ext integer bit                                      #
20915#       sgl_mant = ext_mant{62:12}                                      #
20916#                                                                       #
20917#               ---------------   ---------------    ---------------    #
20918#  extended ->  |s|    exp    |   |1| ms mant   |    | ls mant     |    #
20919#               ---------------   ---------------    ---------------    #
20920#                95         64    63 62    40 32      31     12   0     #
20921#                                    |     |                            #
20922#                                    |     |                            #
20923#                                    |     |                            #
20924#                                    v     v                            #
20925#                             ---------------                           #
20926#  single   ->                |s|exp| mant  |                           #
20927#                             ---------------                           #
20928#                             31     22     0                           #
20929#                                                                       #
20930#########################################################################
20931
20932dst_sgl:
20933        clr.l           %d0
20934        mov.w           FTEMP_EX(%a0),%d0       # get exponent
20935        subi.w          &EXT_BIAS,%d0           # subtract extended precision bias
20936        addi.w          &SGL_BIAS,%d0           # add single precision bias
20937        tst.b           FTEMP_HI(%a0)           # is number a denorm?
20938        bmi.b           dst_get_supper          # no
20939        subq.w          &0x1,%d0                # yes; denorm bias = SGL_BIAS - 1
20940dst_get_supper:
20941        swap            %d0                     # put exp in upper word of d0
20942        lsl.l           &0x7,%d0                # shift it into single exp bits
20943        tst.b           FTEMP_EX(%a0)           # test sign
20944        bpl.b           dst_get_sman            # if positive, continue
20945        bset            &0x1f,%d0               # if negative, put in sign first
20946dst_get_sman:
20947        mov.l           FTEMP_HI(%a0),%d1       # get ms mantissa
20948        andi.l          &0x7fffff00,%d1         # get upper 23 bits of ms
20949        lsr.l           &0x8,%d1                # and put them flush right
20950        or.l            %d1,%d0                 # put these bits in ms word of single
20951        rts
20952
20953##############################################################################
20954fout_pack:
20955        bsr.l           _calc_ea_fout           # fetch the <ea>
20956        mov.l           %a0,-(%sp)
20957
20958        mov.b           STAG(%a6),%d0           # fetch input type
20959        bne.w           fout_pack_not_norm      # input is not NORM
20960
20961fout_pack_norm:
20962        btst            &0x4,EXC_CMDREG(%a6)    # static or dynamic?
20963        beq.b           fout_pack_s             # static
20964
20965fout_pack_d:
20966        mov.b           1+EXC_CMDREG(%a6),%d1   # fetch dynamic reg
20967        lsr.b           &0x4,%d1
20968        andi.w          &0x7,%d1
20969
20970        bsr.l           fetch_dreg              # fetch Dn w/ k-factor
20971
20972        bra.b           fout_pack_type
20973fout_pack_s:
20974        mov.b           1+EXC_CMDREG(%a6),%d0   # fetch static field
20975
20976fout_pack_type:
20977        bfexts          %d0{&25:&7},%d0         # extract k-factor
20978        mov.l   %d0,-(%sp)
20979
20980        lea             FP_SRC(%a6),%a0         # pass: ptr to input
20981
20982# bindec is currently scrambling FP_SRC for denorm inputs.
20983# we'll have to change this, but for now, tough luck!!!
20984        bsr.l           bindec                  # convert xprec to packed
20985
20986#       andi.l          &0xcfff000f,FP_SCR0(%a6) # clear unused fields
20987        andi.l          &0xcffff00f,FP_SCR0(%a6) # clear unused fields
20988
20989        mov.l   (%sp)+,%d0
20990
20991        tst.b           3+FP_SCR0_EX(%a6)
20992        bne.b           fout_pack_set
20993        tst.l           FP_SCR0_HI(%a6)
20994        bne.b           fout_pack_set
20995        tst.l           FP_SCR0_LO(%a6)
20996        bne.b           fout_pack_set
20997
20998# add the extra condition that only if the k-factor was zero, too, should
20999# we zero the exponent
21000        tst.l           %d0
21001        bne.b           fout_pack_set
21002# "mantissa" is all zero which means that the answer is zero. but, the '040
21003# algorithm allows the exponent to be non-zero. the 881/2 do not. Therefore,
21004# if the mantissa is zero, I will zero the exponent, too.
21005# the question now is whether the exponents sign bit is allowed to be non-zero
21006# for a zero, also...
21007        andi.w          &0xf000,FP_SCR0(%a6)
21008
21009fout_pack_set:
21010
21011        lea             FP_SCR0(%a6),%a0        # pass: src addr
21012
21013fout_pack_write:
21014        mov.l           (%sp)+,%a1              # pass: dst addr
21015        mov.l           &0xc,%d0                # pass: opsize is 12 bytes
21016
21017        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
21018        beq.b           fout_pack_a7
21019
21020        bsr.l           _dmem_write             # write ext prec number to memory
21021
21022        tst.l           %d1                     # did dstore fail?
21023        bne.w           fout_ext_err            # yes
21024
21025        rts
21026
21027# we don't want to do the write if the exception occurred in supervisor mode
21028# so _mem_write2() handles this for us.
21029fout_pack_a7:
21030        bsr.l           _mem_write2             # write ext prec number to memory
21031
21032        tst.l           %d1                     # did dstore fail?
21033        bne.w           fout_ext_err            # yes
21034
21035        rts
21036
21037fout_pack_not_norm:
21038        cmpi.b          %d0,&DENORM             # is it a DENORM?
21039        beq.w           fout_pack_norm          # yes
21040        lea             FP_SRC(%a6),%a0
21041        clr.w           2+FP_SRC_EX(%a6)
21042        cmpi.b          %d0,&SNAN               # is it an SNAN?
21043        beq.b           fout_pack_snan          # yes
21044        bra.b           fout_pack_write         # no
21045
21046fout_pack_snan:
21047        ori.w           &snaniop2_mask,FPSR_EXCEPT(%a6) # set SNAN/AIOP
21048        bset            &0x6,FP_SRC_HI(%a6)     # set snan bit
21049        bra.b           fout_pack_write
21050
21051#########################################################################
21052# XDEF **************************************************************** #
21053#       fetch_dreg(): fetch register according to index in d1           #
21054#                                                                       #
21055# XREF **************************************************************** #
21056#       None                                                            #
21057#                                                                       #
21058# INPUT *************************************************************** #
21059#       d1 = index of register to fetch from                            #
21060#                                                                       #
21061# OUTPUT ************************************************************** #
21062#       d0 = value of register fetched                                  #
21063#                                                                       #
21064# ALGORITHM *********************************************************** #
21065#       According to the index value in d1 which can range from zero    #
21066# to fifteen, load the corresponding register file value (where         #
21067# address register indexes start at 8). D0/D1/A0/A1/A6/A7 are on the    #
21068# stack. The rest should still be in their original places.             #
21069#                                                                       #
21070#########################################################################
21071
21072# this routine leaves d1 intact for subsequent store_dreg calls.
21073        global          fetch_dreg
21074fetch_dreg:
21075        mov.w           (tbl_fdreg.b,%pc,%d1.w*2),%d0
21076        jmp             (tbl_fdreg.b,%pc,%d0.w*1)
21077
21078tbl_fdreg:
21079        short           fdreg0 - tbl_fdreg
21080        short           fdreg1 - tbl_fdreg
21081        short           fdreg2 - tbl_fdreg
21082        short           fdreg3 - tbl_fdreg
21083        short           fdreg4 - tbl_fdreg
21084        short           fdreg5 - tbl_fdreg
21085        short           fdreg6 - tbl_fdreg
21086        short           fdreg7 - tbl_fdreg
21087        short           fdreg8 - tbl_fdreg
21088        short           fdreg9 - tbl_fdreg
21089        short           fdrega - tbl_fdreg
21090        short           fdregb - tbl_fdreg
21091        short           fdregc - tbl_fdreg
21092        short           fdregd - tbl_fdreg
21093        short           fdrege - tbl_fdreg
21094        short           fdregf - tbl_fdreg
21095
21096fdreg0:
21097        mov.l           EXC_DREGS+0x0(%a6),%d0
21098        rts
21099fdreg1:
21100        mov.l           EXC_DREGS+0x4(%a6),%d0
21101        rts
21102fdreg2:
21103        mov.l           %d2,%d0
21104        rts
21105fdreg3:
21106        mov.l           %d3,%d0
21107        rts
21108fdreg4:
21109        mov.l           %d4,%d0
21110        rts
21111fdreg5:
21112        mov.l           %d5,%d0
21113        rts
21114fdreg6:
21115        mov.l           %d6,%d0
21116        rts
21117fdreg7:
21118        mov.l           %d7,%d0
21119        rts
21120fdreg8:
21121        mov.l           EXC_DREGS+0x8(%a6),%d0
21122        rts
21123fdreg9:
21124        mov.l           EXC_DREGS+0xc(%a6),%d0
21125        rts
21126fdrega:
21127        mov.l           %a2,%d0
21128        rts
21129fdregb:
21130        mov.l           %a3,%d0
21131        rts
21132fdregc:
21133        mov.l           %a4,%d0
21134        rts
21135fdregd:
21136        mov.l           %a5,%d0
21137        rts
21138fdrege:
21139        mov.l           (%a6),%d0
21140        rts
21141fdregf:
21142        mov.l           EXC_A7(%a6),%d0
21143        rts
21144
21145#########################################################################
21146# XDEF **************************************************************** #
21147#       store_dreg_l(): store longword to data register specified by d1 #
21148#                                                                       #
21149# XREF **************************************************************** #
21150#       None                                                            #
21151#                                                                       #
21152# INPUT *************************************************************** #
21153#       d0 = longowrd value to store                                    #
21154#       d1 = index of register to fetch from                            #
21155#                                                                       #
21156# OUTPUT ************************************************************** #
21157#       (data register is updated)                                      #
21158#                                                                       #
21159# ALGORITHM *********************************************************** #
21160#       According to the index value in d1, store the longword value    #
21161# in d0 to the corresponding data register. D0/D1 are on the stack      #
21162# while the rest are in their initial places.                           #
21163#                                                                       #
21164#########################################################################
21165
21166        global          store_dreg_l
21167store_dreg_l:
21168        mov.w           (tbl_sdregl.b,%pc,%d1.w*2),%d1
21169        jmp             (tbl_sdregl.b,%pc,%d1.w*1)
21170
21171tbl_sdregl:
21172        short           sdregl0 - tbl_sdregl
21173        short           sdregl1 - tbl_sdregl
21174        short           sdregl2 - tbl_sdregl
21175        short           sdregl3 - tbl_sdregl
21176        short           sdregl4 - tbl_sdregl
21177        short           sdregl5 - tbl_sdregl
21178        short           sdregl6 - tbl_sdregl
21179        short           sdregl7 - tbl_sdregl
21180
21181sdregl0:
21182        mov.l           %d0,EXC_DREGS+0x0(%a6)
21183        rts
21184sdregl1:
21185        mov.l           %d0,EXC_DREGS+0x4(%a6)
21186        rts
21187sdregl2:
21188        mov.l           %d0,%d2
21189        rts
21190sdregl3:
21191        mov.l           %d0,%d3
21192        rts
21193sdregl4:
21194        mov.l           %d0,%d4
21195        rts
21196sdregl5:
21197        mov.l           %d0,%d5
21198        rts
21199sdregl6:
21200        mov.l           %d0,%d6
21201        rts
21202sdregl7:
21203        mov.l           %d0,%d7
21204        rts
21205
21206#########################################################################
21207# XDEF **************************************************************** #
21208#       store_dreg_w(): store word to data register specified by d1     #
21209#                                                                       #
21210# XREF **************************************************************** #
21211#       None                                                            #
21212#                                                                       #
21213# INPUT *************************************************************** #
21214#       d0 = word value to store                                        #
21215#       d1 = index of register to fetch from                            #
21216#                                                                       #
21217# OUTPUT ************************************************************** #
21218#       (data register is updated)                                      #
21219#                                                                       #
21220# ALGORITHM *********************************************************** #
21221#       According to the index value in d1, store the word value        #
21222# in d0 to the corresponding data register. D0/D1 are on the stack      #
21223# while the rest are in their initial places.                           #
21224#                                                                       #
21225#########################################################################
21226
21227        global          store_dreg_w
21228store_dreg_w:
21229        mov.w           (tbl_sdregw.b,%pc,%d1.w*2),%d1
21230        jmp             (tbl_sdregw.b,%pc,%d1.w*1)
21231
21232tbl_sdregw:
21233        short           sdregw0 - tbl_sdregw
21234        short           sdregw1 - tbl_sdregw
21235        short           sdregw2 - tbl_sdregw
21236        short           sdregw3 - tbl_sdregw
21237        short           sdregw4 - tbl_sdregw
21238        short           sdregw5 - tbl_sdregw
21239        short           sdregw6 - tbl_sdregw
21240        short           sdregw7 - tbl_sdregw
21241
21242sdregw0:
21243        mov.w           %d0,2+EXC_DREGS+0x0(%a6)
21244        rts
21245sdregw1:
21246        mov.w           %d0,2+EXC_DREGS+0x4(%a6)
21247        rts
21248sdregw2:
21249        mov.w           %d0,%d2
21250        rts
21251sdregw3:
21252        mov.w           %d0,%d3
21253        rts
21254sdregw4:
21255        mov.w           %d0,%d4
21256        rts
21257sdregw5:
21258        mov.w           %d0,%d5
21259        rts
21260sdregw6:
21261        mov.w           %d0,%d6
21262        rts
21263sdregw7:
21264        mov.w           %d0,%d7
21265        rts
21266
21267#########################################################################
21268# XDEF **************************************************************** #
21269#       store_dreg_b(): store byte to data register specified by d1     #
21270#                                                                       #
21271# XREF **************************************************************** #
21272#       None                                                            #
21273#                                                                       #
21274# INPUT *************************************************************** #
21275#       d0 = byte value to store                                        #
21276#       d1 = index of register to fetch from                            #
21277#                                                                       #
21278# OUTPUT ************************************************************** #
21279#       (data register is updated)                                      #
21280#                                                                       #
21281# ALGORITHM *********************************************************** #
21282#       According to the index value in d1, store the byte value        #
21283# in d0 to the corresponding data register. D0/D1 are on the stack      #
21284# while the rest are in their initial places.                           #
21285#                                                                       #
21286#########################################################################
21287
21288        global          store_dreg_b
21289store_dreg_b:
21290        mov.w           (tbl_sdregb.b,%pc,%d1.w*2),%d1
21291        jmp             (tbl_sdregb.b,%pc,%d1.w*1)
21292
21293tbl_sdregb:
21294        short           sdregb0 - tbl_sdregb
21295        short           sdregb1 - tbl_sdregb
21296        short           sdregb2 - tbl_sdregb
21297        short           sdregb3 - tbl_sdregb
21298        short           sdregb4 - tbl_sdregb
21299        short           sdregb5 - tbl_sdregb
21300        short           sdregb6 - tbl_sdregb
21301        short           sdregb7 - tbl_sdregb
21302
21303sdregb0:
21304        mov.b           %d0,3+EXC_DREGS+0x0(%a6)
21305        rts
21306sdregb1:
21307        mov.b           %d0,3+EXC_DREGS+0x4(%a6)
21308        rts
21309sdregb2:
21310        mov.b           %d0,%d2
21311        rts
21312sdregb3:
21313        mov.b           %d0,%d3
21314        rts
21315sdregb4:
21316        mov.b           %d0,%d4
21317        rts
21318sdregb5:
21319        mov.b           %d0,%d5
21320        rts
21321sdregb6:
21322        mov.b           %d0,%d6
21323        rts
21324sdregb7:
21325        mov.b           %d0,%d7
21326        rts
21327
21328#########################################################################
21329# XDEF **************************************************************** #
21330#       inc_areg(): increment an address register by the value in d0    #
21331#                                                                       #
21332# XREF **************************************************************** #
21333#       None                                                            #
21334#                                                                       #
21335# INPUT *************************************************************** #
21336#       d0 = amount to increment by                                     #
21337#       d1 = index of address register to increment                     #
21338#                                                                       #
21339# OUTPUT ************************************************************** #
21340#       (address register is updated)                                   #
21341#                                                                       #
21342# ALGORITHM *********************************************************** #
21343#       Typically used for an instruction w/ a post-increment <ea>,     #
21344# this routine adds the increment value in d0 to the address register   #
21345# specified by d1. A0/A1/A6/A7 reside on the stack. The rest reside     #
21346# in their original places.                                             #
21347#       For a7, if the increment amount is one, then we have to         #
21348# increment by two. For any a7 update, set the mia7_flag so that if     #
21349# an access error exception occurs later in emulation, this address     #
21350# register update can be undone.                                        #
21351#                                                                       #
21352#########################################################################
21353
21354        global          inc_areg
21355inc_areg:
21356        mov.w           (tbl_iareg.b,%pc,%d1.w*2),%d1
21357        jmp             (tbl_iareg.b,%pc,%d1.w*1)
21358
21359tbl_iareg:
21360        short           iareg0 - tbl_iareg
21361        short           iareg1 - tbl_iareg
21362        short           iareg2 - tbl_iareg
21363        short           iareg3 - tbl_iareg
21364        short           iareg4 - tbl_iareg
21365        short           iareg5 - tbl_iareg
21366        short           iareg6 - tbl_iareg
21367        short           iareg7 - tbl_iareg
21368
21369iareg0: add.l           %d0,EXC_DREGS+0x8(%a6)
21370        rts
21371iareg1: add.l           %d0,EXC_DREGS+0xc(%a6)
21372        rts
21373iareg2: add.l           %d0,%a2
21374        rts
21375iareg3: add.l           %d0,%a3
21376        rts
21377iareg4: add.l           %d0,%a4
21378        rts
21379iareg5: add.l           %d0,%a5
21380        rts
21381iareg6: add.l           %d0,(%a6)
21382        rts
21383iareg7: mov.b           &mia7_flg,SPCOND_FLG(%a6)
21384        cmpi.b          %d0,&0x1
21385        beq.b           iareg7b
21386        add.l           %d0,EXC_A7(%a6)
21387        rts
21388iareg7b:
21389        addq.l          &0x2,EXC_A7(%a6)
21390        rts
21391
21392#########################################################################
21393# XDEF **************************************************************** #
21394#       dec_areg(): decrement an address register by the value in d0    #
21395#                                                                       #
21396# XREF **************************************************************** #
21397#       None                                                            #
21398#                                                                       #
21399# INPUT *************************************************************** #
21400#       d0 = amount to decrement by                                     #
21401#       d1 = index of address register to decrement                     #
21402#                                                                       #
21403# OUTPUT ************************************************************** #
21404#       (address register is updated)                                   #
21405#                                                                       #
21406# ALGORITHM *********************************************************** #
21407#       Typically used for an instruction w/ a pre-decrement <ea>,      #
21408# this routine adds the decrement value in d0 to the address register   #
21409# specified by d1. A0/A1/A6/A7 reside on the stack. The rest reside     #
21410# in their original places.                                             #
21411#       For a7, if the decrement amount is one, then we have to         #
21412# decrement by two. For any a7 update, set the mda7_flag so that if     #
21413# an access error exception occurs later in emulation, this address     #
21414# register update can be undone.                                        #
21415#                                                                       #
21416#########################################################################
21417
21418        global          dec_areg
21419dec_areg:
21420        mov.w           (tbl_dareg.b,%pc,%d1.w*2),%d1
21421        jmp             (tbl_dareg.b,%pc,%d1.w*1)
21422
21423tbl_dareg:
21424        short           dareg0 - tbl_dareg
21425        short           dareg1 - tbl_dareg
21426        short           dareg2 - tbl_dareg
21427        short           dareg3 - tbl_dareg
21428        short           dareg4 - tbl_dareg
21429        short           dareg5 - tbl_dareg
21430        short           dareg6 - tbl_dareg
21431        short           dareg7 - tbl_dareg
21432
21433dareg0: sub.l           %d0,EXC_DREGS+0x8(%a6)
21434        rts
21435dareg1: sub.l           %d0,EXC_DREGS+0xc(%a6)
21436        rts
21437dareg2: sub.l           %d0,%a2
21438        rts
21439dareg3: sub.l           %d0,%a3
21440        rts
21441dareg4: sub.l           %d0,%a4
21442        rts
21443dareg5: sub.l           %d0,%a5
21444        rts
21445dareg6: sub.l           %d0,(%a6)
21446        rts
21447dareg7: mov.b           &mda7_flg,SPCOND_FLG(%a6)
21448        cmpi.b          %d0,&0x1
21449        beq.b           dareg7b
21450        sub.l           %d0,EXC_A7(%a6)
21451        rts
21452dareg7b:
21453        subq.l          &0x2,EXC_A7(%a6)
21454        rts
21455
21456##############################################################################
21457
21458#########################################################################
21459# XDEF **************************************************************** #
21460#       load_fpn1(): load FP register value into FP_SRC(a6).            #
21461#                                                                       #
21462# XREF **************************************************************** #
21463#       None                                                            #
21464#                                                                       #
21465# INPUT *************************************************************** #
21466#       d0 = index of FP register to load                               #
21467#                                                                       #
21468# OUTPUT ************************************************************** #
21469#       FP_SRC(a6) = value loaded from FP register file                 #
21470#                                                                       #
21471# ALGORITHM *********************************************************** #
21472#       Using the index in d0, load FP_SRC(a6) with a number from the   #
21473# FP register file.                                                     #
21474#                                                                       #
21475#########################################################################
21476
21477        global          load_fpn1
21478load_fpn1:
21479        mov.w           (tbl_load_fpn1.b,%pc,%d0.w*2), %d0
21480        jmp             (tbl_load_fpn1.b,%pc,%d0.w*1)
21481
21482tbl_load_fpn1:
21483        short           load_fpn1_0 - tbl_load_fpn1
21484        short           load_fpn1_1 - tbl_load_fpn1
21485        short           load_fpn1_2 - tbl_load_fpn1
21486        short           load_fpn1_3 - tbl_load_fpn1
21487        short           load_fpn1_4 - tbl_load_fpn1
21488        short           load_fpn1_5 - tbl_load_fpn1
21489        short           load_fpn1_6 - tbl_load_fpn1
21490        short           load_fpn1_7 - tbl_load_fpn1
21491
21492load_fpn1_0:
21493        mov.l           0+EXC_FP0(%a6), 0+FP_SRC(%a6)
21494        mov.l           4+EXC_FP0(%a6), 4+FP_SRC(%a6)
21495        mov.l           8+EXC_FP0(%a6), 8+FP_SRC(%a6)
21496        lea             FP_SRC(%a6), %a0
21497        rts
21498load_fpn1_1:
21499        mov.l           0+EXC_FP1(%a6), 0+FP_SRC(%a6)
21500        mov.l           4+EXC_FP1(%a6), 4+FP_SRC(%a6)
21501        mov.l           8+EXC_FP1(%a6), 8+FP_SRC(%a6)
21502        lea             FP_SRC(%a6), %a0
21503        rts
21504load_fpn1_2:
21505        fmovm.x         &0x20, FP_SRC(%a6)
21506        lea             FP_SRC(%a6), %a0
21507        rts
21508load_fpn1_3:
21509        fmovm.x         &0x10, FP_SRC(%a6)
21510        lea             FP_SRC(%a6), %a0
21511        rts
21512load_fpn1_4:
21513        fmovm.x         &0x08, FP_SRC(%a6)
21514        lea             FP_SRC(%a6), %a0
21515        rts
21516load_fpn1_5:
21517        fmovm.x         &0x04, FP_SRC(%a6)
21518        lea             FP_SRC(%a6), %a0
21519        rts
21520load_fpn1_6:
21521        fmovm.x         &0x02, FP_SRC(%a6)
21522        lea             FP_SRC(%a6), %a0
21523        rts
21524load_fpn1_7:
21525        fmovm.x         &0x01, FP_SRC(%a6)
21526        lea             FP_SRC(%a6), %a0
21527        rts
21528
21529#############################################################################
21530
21531#########################################################################
21532# XDEF **************************************************************** #
21533#       load_fpn2(): load FP register value into FP_DST(a6).            #
21534#                                                                       #
21535# XREF **************************************************************** #
21536#       None                                                            #
21537#                                                                       #
21538# INPUT *************************************************************** #
21539#       d0 = index of FP register to load                               #
21540#                                                                       #
21541# OUTPUT ************************************************************** #
21542#       FP_DST(a6) = value loaded from FP register file                 #
21543#                                                                       #
21544# ALGORITHM *********************************************************** #
21545#       Using the index in d0, load FP_DST(a6) with a number from the   #
21546# FP register file.                                                     #
21547#                                                                       #
21548#########################################################################
21549
21550        global          load_fpn2
21551load_fpn2:
21552        mov.w           (tbl_load_fpn2.b,%pc,%d0.w*2), %d0
21553        jmp             (tbl_load_fpn2.b,%pc,%d0.w*1)
21554
21555tbl_load_fpn2:
21556        short           load_fpn2_0 - tbl_load_fpn2
21557        short           load_fpn2_1 - tbl_load_fpn2
21558        short           load_fpn2_2 - tbl_load_fpn2
21559        short           load_fpn2_3 - tbl_load_fpn2
21560        short           load_fpn2_4 - tbl_load_fpn2
21561        short           load_fpn2_5 - tbl_load_fpn2
21562        short           load_fpn2_6 - tbl_load_fpn2
21563        short           load_fpn2_7 - tbl_load_fpn2
21564
21565load_fpn2_0:
21566        mov.l           0+EXC_FP0(%a6), 0+FP_DST(%a6)
21567        mov.l           4+EXC_FP0(%a6), 4+FP_DST(%a6)
21568        mov.l           8+EXC_FP0(%a6), 8+FP_DST(%a6)
21569        lea             FP_DST(%a6), %a0
21570        rts
21571load_fpn2_1:
21572        mov.l           0+EXC_FP1(%a6), 0+FP_DST(%a6)
21573        mov.l           4+EXC_FP1(%a6), 4+FP_DST(%a6)
21574        mov.l           8+EXC_FP1(%a6), 8+FP_DST(%a6)
21575        lea             FP_DST(%a6), %a0
21576        rts
21577load_fpn2_2:
21578        fmovm.x         &0x20, FP_DST(%a6)
21579        lea             FP_DST(%a6), %a0
21580        rts
21581load_fpn2_3:
21582        fmovm.x         &0x10, FP_DST(%a6)
21583        lea             FP_DST(%a6), %a0
21584        rts
21585load_fpn2_4:
21586        fmovm.x         &0x08, FP_DST(%a6)
21587        lea             FP_DST(%a6), %a0
21588        rts
21589load_fpn2_5:
21590        fmovm.x         &0x04, FP_DST(%a6)
21591        lea             FP_DST(%a6), %a0
21592        rts
21593load_fpn2_6:
21594        fmovm.x         &0x02, FP_DST(%a6)
21595        lea             FP_DST(%a6), %a0
21596        rts
21597load_fpn2_7:
21598        fmovm.x         &0x01, FP_DST(%a6)
21599        lea             FP_DST(%a6), %a0
21600        rts
21601
21602#############################################################################
21603
21604#########################################################################
21605# XDEF **************************************************************** #
21606#       store_fpreg(): store an fp value to the fpreg designated d0.    #
21607#                                                                       #
21608# XREF **************************************************************** #
21609#       None                                                            #
21610#                                                                       #
21611# INPUT *************************************************************** #
21612#       fp0 = extended precision value to store                         #
21613#       d0  = index of floating-point register                          #
21614#                                                                       #
21615# OUTPUT ************************************************************** #
21616#       None                                                            #
21617#                                                                       #
21618# ALGORITHM *********************************************************** #
21619#       Store the value in fp0 to the FP register designated by the     #
21620# value in d0. The FP number can be DENORM or SNAN so we have to be     #
21621# careful that we don't take an exception here.                         #
21622#                                                                       #
21623#########################################################################
21624
21625        global          store_fpreg
21626store_fpreg:
21627        mov.w           (tbl_store_fpreg.b,%pc,%d0.w*2), %d0
21628        jmp             (tbl_store_fpreg.b,%pc,%d0.w*1)
21629
21630tbl_store_fpreg:
21631        short           store_fpreg_0 - tbl_store_fpreg
21632        short           store_fpreg_1 - tbl_store_fpreg
21633        short           store_fpreg_2 - tbl_store_fpreg
21634        short           store_fpreg_3 - tbl_store_fpreg
21635        short           store_fpreg_4 - tbl_store_fpreg
21636        short           store_fpreg_5 - tbl_store_fpreg
21637        short           store_fpreg_6 - tbl_store_fpreg
21638        short           store_fpreg_7 - tbl_store_fpreg
21639
21640store_fpreg_0:
21641        fmovm.x         &0x80, EXC_FP0(%a6)
21642        rts
21643store_fpreg_1:
21644        fmovm.x         &0x80, EXC_FP1(%a6)
21645        rts
21646store_fpreg_2:
21647        fmovm.x         &0x01, -(%sp)
21648        fmovm.x         (%sp)+, &0x20
21649        rts
21650store_fpreg_3:
21651        fmovm.x         &0x01, -(%sp)
21652        fmovm.x         (%sp)+, &0x10
21653        rts
21654store_fpreg_4:
21655        fmovm.x         &0x01, -(%sp)
21656        fmovm.x         (%sp)+, &0x08
21657        rts
21658store_fpreg_5:
21659        fmovm.x         &0x01, -(%sp)
21660        fmovm.x         (%sp)+, &0x04
21661        rts
21662store_fpreg_6:
21663        fmovm.x         &0x01, -(%sp)
21664        fmovm.x         (%sp)+, &0x02
21665        rts
21666store_fpreg_7:
21667        fmovm.x         &0x01, -(%sp)
21668        fmovm.x         (%sp)+, &0x01
21669        rts
21670
21671#########################################################################
21672# XDEF **************************************************************** #
21673#       _denorm(): denormalize an intermediate result                   #
21674#                                                                       #
21675# XREF **************************************************************** #
21676#       None                                                            #
21677#                                                                       #
21678# INPUT *************************************************************** #
21679#       a0 = points to the operand to be denormalized                   #
21680#               (in the internal extended format)                       #
21681#                                                                       #
21682#       d0 = rounding precision                                         #
21683#                                                                       #
21684# OUTPUT ************************************************************** #
21685#       a0 = pointer to the denormalized result                         #
21686#               (in the internal extended format)                       #
21687#                                                                       #
21688#       d0 = guard,round,sticky                                         #
21689#                                                                       #
21690# ALGORITHM *********************************************************** #
21691#       According to the exponent underflow threshold for the given     #
21692# precision, shift the mantissa bits to the right in order raise the    #
21693# exponent of the operand to the threshold value. While shifting the    #
21694# mantissa bits right, maintain the value of the guard, round, and      #
21695# sticky bits.                                                          #
21696# other notes:                                                          #
21697#       (1) _denorm() is called by the underflow routines               #
21698#       (2) _denorm() does NOT affect the status register               #
21699#                                                                       #
21700#########################################################################
21701
21702#
21703# table of exponent threshold values for each precision
21704#
21705tbl_thresh:
21706        short           0x0
21707        short           sgl_thresh
21708        short           dbl_thresh
21709
21710        global          _denorm
21711_denorm:
21712#
21713# Load the exponent threshold for the precision selected and check
21714# to see if (threshold - exponent) is > 65 in which case we can
21715# simply calculate the sticky bit and zero the mantissa. otherwise
21716# we have to call the denormalization routine.
21717#
21718        lsr.b           &0x2, %d0               # shift prec to lo bits
21719        mov.w           (tbl_thresh.b,%pc,%d0.w*2), %d1 # load prec threshold
21720        mov.w           %d1, %d0                # copy d1 into d0
21721        sub.w           FTEMP_EX(%a0), %d0      # diff = threshold - exp
21722        cmpi.w          %d0, &66                # is diff > 65? (mant + g,r bits)
21723        bpl.b           denorm_set_stky         # yes; just calc sticky
21724
21725        clr.l           %d0                     # clear g,r,s
21726        btst            &inex2_bit, FPSR_EXCEPT(%a6) # yes; was INEX2 set?
21727        beq.b           denorm_call             # no; don't change anything
21728        bset            &29, %d0                # yes; set sticky bit
21729
21730denorm_call:
21731        bsr.l           dnrm_lp                 # denormalize the number
21732        rts
21733
21734#
21735# all bit would have been shifted off during the denorm so simply
21736# calculate if the sticky should be set and clear the entire mantissa.
21737#
21738denorm_set_stky:
21739        mov.l           &0x20000000, %d0        # set sticky bit in return value
21740        mov.w           %d1, FTEMP_EX(%a0)      # load exp with threshold
21741        clr.l           FTEMP_HI(%a0)           # set d1 = 0 (ms mantissa)
21742        clr.l           FTEMP_LO(%a0)           # set d2 = 0 (ms mantissa)
21743        rts
21744
21745#                                                                       #
21746# dnrm_lp(): normalize exponent/mantissa to specified threshold         #
21747#                                                                       #
21748# INPUT:                                                                #
21749#       %a0        : points to the operand to be denormalized           #
21750#       %d0{31:29} : initial guard,round,sticky                         #
21751#       %d1{15:0}  : denormalization threshold                          #
21752# OUTPUT:                                                               #
21753#       %a0        : points to the denormalized operand                 #
21754#       %d0{31:29} : final guard,round,sticky                           #
21755#                                                                       #
21756
21757# *** Local Equates *** #
21758set     GRS,            L_SCR2                  # g,r,s temp storage
21759set     FTEMP_LO2,      L_SCR1                  # FTEMP_LO copy
21760
21761        global          dnrm_lp
21762dnrm_lp:
21763
21764#
21765# make a copy of FTEMP_LO and place the g,r,s bits directly after it
21766# in memory so as to make the bitfield extraction for denormalization easier.
21767#
21768        mov.l           FTEMP_LO(%a0), FTEMP_LO2(%a6) # make FTEMP_LO copy
21769        mov.l           %d0, GRS(%a6)           # place g,r,s after it
21770
21771#
21772# check to see how much less than the underflow threshold the operand
21773# exponent is.
21774#
21775        mov.l           %d1, %d0                # copy the denorm threshold
21776        sub.w           FTEMP_EX(%a0), %d1      # d1 = threshold - uns exponent
21777        ble.b           dnrm_no_lp              # d1 <= 0
21778        cmpi.w          %d1, &0x20              # is ( 0 <= d1 < 32) ?
21779        blt.b           case_1                  # yes
21780        cmpi.w          %d1, &0x40              # is (32 <= d1 < 64) ?
21781        blt.b           case_2                  # yes
21782        bra.w           case_3                  # (d1 >= 64)
21783
21784#
21785# No normalization necessary
21786#
21787dnrm_no_lp:
21788        mov.l           GRS(%a6), %d0           # restore original g,r,s
21789        rts
21790
21791#
21792# case (0<d1<32)
21793#
21794# %d0 = denorm threshold
21795# %d1 = "n" = amt to shift
21796#
21797#       ---------------------------------------------------------
21798#       |     FTEMP_HI    |     FTEMP_LO     |grs000.........000|
21799#       ---------------------------------------------------------
21800#       <-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)->
21801#       \          \                  \                  \
21802#        \          \                  \                  \
21803#         \          \                  \                  \
21804#          \          \                  \                  \
21805#           \          \                  \                  \
21806#            \          \                  \                  \
21807#             \          \                  \                  \
21808#              \          \                  \                  \
21809#       <-(n)-><-(32 - n)-><------(32)-------><------(32)------->
21810#       ---------------------------------------------------------
21811#       |0.....0| NEW_HI  |  NEW_FTEMP_LO     |grs              |
21812#       ---------------------------------------------------------
21813#
21814case_1:
21815        mov.l           %d2, -(%sp)             # create temp storage
21816
21817        mov.w           %d0, FTEMP_EX(%a0)      # exponent = denorm threshold
21818        mov.l           &32, %d0
21819        sub.w           %d1, %d0                # %d0 = 32 - %d1
21820
21821        cmpi.w          %d1, &29                # is shft amt >= 29
21822        blt.b           case1_extract           # no; no fix needed
21823        mov.b           GRS(%a6), %d2
21824        or.b            %d2, 3+FTEMP_LO2(%a6)
21825
21826case1_extract:
21827        bfextu          FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_HI
21828        bfextu          FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new FTEMP_LO
21829        bfextu          FTEMP_LO2(%a6){%d0:&32}, %d0 # %d0 = new G,R,S
21830
21831        mov.l           %d2, FTEMP_HI(%a0)      # store new FTEMP_HI
21832        mov.l           %d1, FTEMP_LO(%a0)      # store new FTEMP_LO
21833
21834        bftst           %d0{&2:&30}             # were bits shifted off?
21835        beq.b           case1_sticky_clear      # no; go finish
21836        bset            &rnd_stky_bit, %d0      # yes; set sticky bit
21837
21838case1_sticky_clear:
21839        and.l           &0xe0000000, %d0        # clear all but G,R,S
21840        mov.l           (%sp)+, %d2             # restore temp register
21841        rts
21842
21843#
21844# case (32<=d1<64)
21845#
21846# %d0 = denorm threshold
21847# %d1 = "n" = amt to shift
21848#
21849#       ---------------------------------------------------------
21850#       |     FTEMP_HI    |     FTEMP_LO     |grs000.........000|
21851#       ---------------------------------------------------------
21852#       <-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)->
21853#       \          \                  \
21854#        \          \                  \
21855#         \          \                  -------------------
21856#          \          --------------------                 \
21857#           -------------------           \                 \
21858#                              \           \                 \
21859#                               \           \                 \
21860#                                \           \                 \
21861#       <-------(32)------><-(n)-><-(32 - n)-><------(32)------->
21862#       ---------------------------------------------------------
21863#       |0...............0|0....0| NEW_LO     |grs              |
21864#       ---------------------------------------------------------
21865#
21866case_2:
21867        mov.l           %d2, -(%sp)             # create temp storage
21868
21869        mov.w           %d0, FTEMP_EX(%a0)      # exponent = denorm threshold
21870        subi.w          &0x20, %d1              # %d1 now between 0 and 32
21871        mov.l           &0x20, %d0
21872        sub.w           %d1, %d0                # %d0 = 32 - %d1
21873
21874# subtle step here; or in the g,r,s at the bottom of FTEMP_LO to minimize
21875# the number of bits to check for the sticky detect.
21876# it only plays a role in shift amounts of 61-63.
21877        mov.b           GRS(%a6), %d2
21878        or.b            %d2, 3+FTEMP_LO2(%a6)
21879
21880        bfextu          FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_LO
21881        bfextu          FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new G,R,S
21882
21883        bftst           %d1{&2:&30}             # were any bits shifted off?
21884        bne.b           case2_set_sticky        # yes; set sticky bit
21885        bftst           FTEMP_LO2(%a6){%d0:&31} # were any bits shifted off?
21886        bne.b           case2_set_sticky        # yes; set sticky bit
21887
21888        mov.l           %d1, %d0                # move new G,R,S to %d0
21889        bra.b           case2_end
21890
21891case2_set_sticky:
21892        mov.l           %d1, %d0                # move new G,R,S to %d0
21893        bset            &rnd_stky_bit, %d0      # set sticky bit
21894
21895case2_end:
21896        clr.l           FTEMP_HI(%a0)           # store FTEMP_HI = 0
21897        mov.l           %d2, FTEMP_LO(%a0)      # store FTEMP_LO
21898        and.l           &0xe0000000, %d0        # clear all but G,R,S
21899
21900        mov.l           (%sp)+,%d2              # restore temp register
21901        rts
21902
21903#
21904# case (d1>=64)
21905#
21906# %d0 = denorm threshold
21907# %d1 = amt to shift
21908#
21909case_3:
21910        mov.w           %d0, FTEMP_EX(%a0)      # insert denorm threshold
21911
21912        cmpi.w          %d1, &65                # is shift amt > 65?
21913        blt.b           case3_64                # no; it's == 64
21914        beq.b           case3_65                # no; it's == 65
21915
21916#
21917# case (d1>65)
21918#
21919# Shift value is > 65 and out of range. All bits are shifted off.
21920# Return a zero mantissa with the sticky bit set
21921#
21922        clr.l           FTEMP_HI(%a0)           # clear hi(mantissa)
21923        clr.l           FTEMP_LO(%a0)           # clear lo(mantissa)
21924        mov.l           &0x20000000, %d0        # set sticky bit
21925        rts
21926
21927#
21928# case (d1 == 64)
21929#
21930#       ---------------------------------------------------------
21931#       |     FTEMP_HI    |     FTEMP_LO     |grs000.........000|
21932#       ---------------------------------------------------------
21933#       <-------(32)------>
21934#       \                  \
21935#        \                  \
21936#         \                  \
21937#          \                  ------------------------------
21938#           -------------------------------                 \
21939#                                          \                 \
21940#                                           \                 \
21941#                                            \                 \
21942#                                             <-------(32)------>
21943#       ---------------------------------------------------------
21944#       |0...............0|0................0|grs               |
21945#       ---------------------------------------------------------
21946#
21947case3_64:
21948        mov.l           FTEMP_HI(%a0), %d0      # fetch hi(mantissa)
21949        mov.l           %d0, %d1                # make a copy
21950        and.l           &0xc0000000, %d0        # extract G,R
21951        and.l           &0x3fffffff, %d1        # extract other bits
21952
21953        bra.b           case3_complete
21954
21955#
21956# case (d1 == 65)
21957#
21958#       ---------------------------------------------------------
21959#       |     FTEMP_HI    |     FTEMP_LO     |grs000.........000|
21960#       ---------------------------------------------------------
21961#       <-------(32)------>
21962#       \                  \
21963#        \                  \
21964#         \                  \
21965#          \                  ------------------------------
21966#           --------------------------------                \
21967#                                           \                \
21968#                                            \                \
21969#                                             \                \
21970#                                              <-------(31)----->
21971#       ---------------------------------------------------------
21972#       |0...............0|0................0|0rs               |
21973#       ---------------------------------------------------------
21974#
21975case3_65:
21976        mov.l           FTEMP_HI(%a0), %d0      # fetch hi(mantissa)
21977        and.l           &0x80000000, %d0        # extract R bit
21978        lsr.l           &0x1, %d0               # shift high bit into R bit
21979        and.l           &0x7fffffff, %d1        # extract other bits
21980
21981case3_complete:
21982# last operation done was an "and" of the bits shifted off so the condition
21983# codes are already set so branch accordingly.
21984        bne.b           case3_set_sticky        # yes; go set new sticky
21985        tst.l           FTEMP_LO(%a0)           # were any bits shifted off?
21986        bne.b           case3_set_sticky        # yes; go set new sticky
21987        tst.b           GRS(%a6)                # were any bits shifted off?
21988        bne.b           case3_set_sticky        # yes; go set new sticky
21989
21990#
21991# no bits were shifted off so don't set the sticky bit.
21992# the guard and
21993# the entire mantissa is zero.
21994#
21995        clr.l           FTEMP_HI(%a0)           # clear hi(mantissa)
21996        clr.l           FTEMP_LO(%a0)           # clear lo(mantissa)
21997        rts
21998
21999#
22000# some bits were shifted off so set the sticky bit.
22001# the entire mantissa is zero.
22002#
22003case3_set_sticky:
22004        bset            &rnd_stky_bit,%d0       # set new sticky bit
22005        clr.l           FTEMP_HI(%a0)           # clear hi(mantissa)
22006        clr.l           FTEMP_LO(%a0)           # clear lo(mantissa)
22007        rts
22008
22009#########################################################################
22010# XDEF **************************************************************** #
22011#       _round(): round result according to precision/mode              #
22012#                                                                       #
22013# XREF **************************************************************** #
22014#       None                                                            #
22015#                                                                       #
22016# INPUT *************************************************************** #
22017#       a0        = ptr to input operand in internal extended format    #
22018#       d1(hi)    = contains rounding precision:                        #
22019#                       ext = $0000xxxx                                 #
22020#                       sgl = $0004xxxx                                 #
22021#                       dbl = $0008xxxx                                 #
22022#       d1(lo)    = contains rounding mode:                             #
22023#                       RN  = $xxxx0000                                 #
22024#                       RZ  = $xxxx0001                                 #
22025#                       RM  = $xxxx0002                                 #
22026#                       RP  = $xxxx0003                                 #
22027#       d0{31:29} = contains the g,r,s bits (extended)                  #
22028#                                                                       #
22029# OUTPUT ************************************************************** #
22030#       a0 = pointer to rounded result                                  #
22031#                                                                       #
22032# ALGORITHM *********************************************************** #
22033#       On return the value pointed to by a0 is correctly rounded,      #
22034#       a0 is preserved and the g-r-s bits in d0 are cleared.           #
22035#       The result is not typed - the tag field is invalid.  The        #
22036#       result is still in the internal extended format.                #
22037#                                                                       #
22038#       The INEX bit of USER_FPSR will be set if the rounded result was #
22039#       inexact (i.e. if any of the g-r-s bits were set).               #
22040#                                                                       #
22041#########################################################################
22042
22043        global          _round
22044_round:
22045#
22046# ext_grs() looks at the rounding precision and sets the appropriate
22047# G,R,S bits.
22048# If (G,R,S == 0) then result is exact and round is done, else set
22049# the inex flag in status reg and continue.
22050#
22051        bsr.l           ext_grs                 # extract G,R,S
22052
22053        tst.l           %d0                     # are G,R,S zero?
22054        beq.w           truncate                # yes; round is complete
22055
22056        or.w            &inx2a_mask, 2+USER_FPSR(%a6) # set inex2/ainex
22057
22058#
22059# Use rounding mode as an index into a jump table for these modes.
22060# All of the following assumes grs != 0.
22061#
22062        mov.w           (tbl_mode.b,%pc,%d1.w*2), %a1 # load jump offset
22063        jmp             (tbl_mode.b,%pc,%a1)    # jmp to rnd mode handler
22064
22065tbl_mode:
22066        short           rnd_near - tbl_mode
22067        short           truncate - tbl_mode     # RZ always truncates
22068        short           rnd_mnus - tbl_mode
22069        short           rnd_plus - tbl_mode
22070
22071#################################################################
22072#       ROUND PLUS INFINITY                                     #
22073#                                                               #
22074#       If sign of fp number = 0 (positive), then add 1 to l.   #
22075#################################################################
22076rnd_plus:
22077        tst.b           FTEMP_SGN(%a0)          # check for sign
22078        bmi.w           truncate                # if positive then truncate
22079
22080        mov.l           &0xffffffff, %d0        # force g,r,s to be all f's
22081        swap            %d1                     # set up d1 for round prec.
22082
22083        cmpi.b          %d1, &s_mode            # is prec = sgl?
22084        beq.w           add_sgl                 # yes
22085        bgt.w           add_dbl                 # no; it's dbl
22086        bra.w           add_ext                 # no; it's ext
22087
22088#################################################################
22089#       ROUND MINUS INFINITY                                    #
22090#                                                               #
22091#       If sign of fp number = 1 (negative), then add 1 to l.   #
22092#################################################################
22093rnd_mnus:
22094        tst.b           FTEMP_SGN(%a0)          # check for sign
22095        bpl.w           truncate                # if negative then truncate
22096
22097        mov.l           &0xffffffff, %d0        # force g,r,s to be all f's
22098        swap            %d1                     # set up d1 for round prec.
22099
22100        cmpi.b          %d1, &s_mode            # is prec = sgl?
22101        beq.w           add_sgl                 # yes
22102        bgt.w           add_dbl                 # no; it's dbl
22103        bra.w           add_ext                 # no; it's ext
22104
22105#################################################################
22106#       ROUND NEAREST                                           #
22107#                                                               #
22108#       If (g=1), then add 1 to l and if (r=s=0), then clear l  #
22109#       Note that this will round to even in case of a tie.     #
22110#################################################################
22111rnd_near:
22112        asl.l           &0x1, %d0               # shift g-bit to c-bit
22113        bcc.w           truncate                # if (g=1) then
22114
22115        swap            %d1                     # set up d1 for round prec.
22116
22117        cmpi.b          %d1, &s_mode            # is prec = sgl?
22118        beq.w           add_sgl                 # yes
22119        bgt.w           add_dbl                 # no; it's dbl
22120        bra.w           add_ext                 # no; it's ext
22121
22122# *** LOCAL EQUATES ***
22123set     ad_1_sgl,       0x00000100      # constant to add 1 to l-bit in sgl prec
22124set     ad_1_dbl,       0x00000800      # constant to add 1 to l-bit in dbl prec
22125
22126#########################
22127#       ADD SINGLE      #
22128#########################
22129add_sgl:
22130        add.l           &ad_1_sgl, FTEMP_HI(%a0)
22131        bcc.b           scc_clr                 # no mantissa overflow
22132        roxr.w          FTEMP_HI(%a0)           # shift v-bit back in
22133        roxr.w          FTEMP_HI+2(%a0)         # shift v-bit back in
22134        add.w           &0x1, FTEMP_EX(%a0)     # and incr exponent
22135scc_clr:
22136        tst.l           %d0                     # test for rs = 0
22137        bne.b           sgl_done
22138        and.w           &0xfe00, FTEMP_HI+2(%a0) # clear the l-bit
22139sgl_done:
22140        and.l           &0xffffff00, FTEMP_HI(%a0) # truncate bits beyond sgl limit
22141        clr.l           FTEMP_LO(%a0)           # clear d2
22142        rts
22143
22144#########################
22145#       ADD EXTENDED    #
22146#########################
22147add_ext:
22148        addq.l          &1,FTEMP_LO(%a0)        # add 1 to l-bit
22149        bcc.b           xcc_clr                 # test for carry out
22150        addq.l          &1,FTEMP_HI(%a0)        # propagate carry
22151        bcc.b           xcc_clr
22152        roxr.w          FTEMP_HI(%a0)           # mant is 0 so restore v-bit
22153        roxr.w          FTEMP_HI+2(%a0)         # mant is 0 so restore v-bit
22154        roxr.w          FTEMP_LO(%a0)
22155        roxr.w          FTEMP_LO+2(%a0)
22156        add.w           &0x1,FTEMP_EX(%a0)      # and inc exp
22157xcc_clr:
22158        tst.l           %d0                     # test rs = 0
22159        bne.b           add_ext_done
22160        and.b           &0xfe,FTEMP_LO+3(%a0)   # clear the l bit
22161add_ext_done:
22162        rts
22163
22164#########################
22165#       ADD DOUBLE      #
22166#########################
22167add_dbl:
22168        add.l           &ad_1_dbl, FTEMP_LO(%a0) # add 1 to lsb
22169        bcc.b           dcc_clr                 # no carry
22170        addq.l          &0x1, FTEMP_HI(%a0)     # propagate carry
22171        bcc.b           dcc_clr                 # no carry
22172
22173        roxr.w          FTEMP_HI(%a0)           # mant is 0 so restore v-bit
22174        roxr.w          FTEMP_HI+2(%a0)         # mant is 0 so restore v-bit
22175        roxr.w          FTEMP_LO(%a0)
22176        roxr.w          FTEMP_LO+2(%a0)
22177        addq.w          &0x1, FTEMP_EX(%a0)     # incr exponent
22178dcc_clr:
22179        tst.l           %d0                     # test for rs = 0
22180        bne.b           dbl_done
22181        and.w           &0xf000, FTEMP_LO+2(%a0) # clear the l-bit
22182
22183dbl_done:
22184        and.l           &0xfffff800,FTEMP_LO(%a0) # truncate bits beyond dbl limit
22185        rts
22186
22187###########################
22188# Truncate all other bits #
22189###########################
22190truncate:
22191        swap            %d1                     # select rnd prec
22192
22193        cmpi.b          %d1, &s_mode            # is prec sgl?
22194        beq.w           sgl_done                # yes
22195        bgt.b           dbl_done                # no; it's dbl
22196        rts                                     # no; it's ext
22197
22198
22199#
22200# ext_grs(): extract guard, round and sticky bits according to
22201#            rounding precision.
22202#
22203# INPUT
22204#       d0         = extended precision g,r,s (in d0{31:29})
22205#       d1         = {PREC,ROUND}
22206# OUTPUT
22207#       d0{31:29}  = guard, round, sticky
22208#
22209# The ext_grs extract the guard/round/sticky bits according to the
22210# selected rounding precision. It is called by the round subroutine
22211# only.  All registers except d0 are kept intact. d0 becomes an
22212# updated guard,round,sticky in d0{31:29}
22213#
22214# Notes: the ext_grs uses the round PREC, and therefore has to swap d1
22215#        prior to usage, and needs to restore d1 to original. this
22216#        routine is tightly tied to the round routine and not meant to
22217#        uphold standard subroutine calling practices.
22218#
22219
22220ext_grs:
22221        swap            %d1                     # have d1.w point to round precision
22222        tst.b           %d1                     # is rnd prec = extended?
22223        bne.b           ext_grs_not_ext         # no; go handle sgl or dbl
22224
22225#
22226# %d0 actually already hold g,r,s since _round() had it before calling
22227# this function. so, as long as we don't disturb it, we are "returning" it.
22228#
22229ext_grs_ext:
22230        swap            %d1                     # yes; return to correct positions
22231        rts
22232
22233ext_grs_not_ext:
22234        movm.l          &0x3000, -(%sp)         # make some temp registers {d2/d3}
22235
22236        cmpi.b          %d1, &s_mode            # is rnd prec = sgl?
22237        bne.b           ext_grs_dbl             # no; go handle dbl
22238
22239#
22240# sgl:
22241#       96              64        40    32              0
22242#       -----------------------------------------------------
22243#       | EXP   |XXXXXXX|         |xx   |               |grs|
22244#       -----------------------------------------------------
22245#                       <--(24)--->nn\                     /
22246#                                  ee ---------------------
22247#                                  ww           |
22248#                                               v
22249#                                  gr      new sticky
22250#
22251ext_grs_sgl:
22252        bfextu          FTEMP_HI(%a0){&24:&2}, %d3 # sgl prec. g-r are 2 bits right
22253        mov.l           &30, %d2                # of the sgl prec. limits
22254        lsl.l           %d2, %d3                # shift g-r bits to MSB of d3
22255        mov.l           FTEMP_HI(%a0), %d2      # get word 2 for s-bit test
22256        and.l           &0x0000003f, %d2        # s bit is the or of all other
22257        bne.b           ext_grs_st_stky         # bits to the right of g-r
22258        tst.l           FTEMP_LO(%a0)           # test lower mantissa
22259        bne.b           ext_grs_st_stky         # if any are set, set sticky
22260        tst.l           %d0                     # test original g,r,s
22261        bne.b           ext_grs_st_stky         # if any are set, set sticky
22262        bra.b           ext_grs_end_sd          # if words 3 and 4 are clr, exit
22263
22264#
22265# dbl:
22266#       96              64              32       11     0
22267#       -----------------------------------------------------
22268#       | EXP   |XXXXXXX|               |        |xx    |grs|
22269#       -----------------------------------------------------
22270#                                                 nn\       /
22271#                                                 ee -------
22272#                                                 ww    |
22273#                                                       v
22274#                                                 gr    new sticky
22275#
22276ext_grs_dbl:
22277        bfextu          FTEMP_LO(%a0){&21:&2}, %d3 # dbl-prec. g-r are 2 bits right
22278        mov.l           &30, %d2                # of the dbl prec. limits
22279        lsl.l           %d2, %d3                # shift g-r bits to the MSB of d3
22280        mov.l           FTEMP_LO(%a0), %d2      # get lower mantissa  for s-bit test
22281        and.l           &0x000001ff, %d2        # s bit is the or-ing of all
22282        bne.b           ext_grs_st_stky         # other bits to the right of g-r
22283        tst.l           %d0                     # test word original g,r,s
22284        bne.b           ext_grs_st_stky         # if any are set, set sticky
22285        bra.b           ext_grs_end_sd          # if clear, exit
22286
22287ext_grs_st_stky:
22288        bset            &rnd_stky_bit, %d3      # set sticky bit
22289ext_grs_end_sd:
22290        mov.l           %d3, %d0                # return grs to d0
22291
22292        movm.l          (%sp)+, &0xc            # restore scratch registers {d2/d3}
22293
22294        swap            %d1                     # restore d1 to original
22295        rts
22296
22297#########################################################################
22298# norm(): normalize the mantissa of an extended precision input. the    #
22299#         input operand should not be normalized already.               #
22300#                                                                       #
22301# XDEF **************************************************************** #
22302#       norm()                                                          #
22303#                                                                       #
22304# XREF **************************************************************** #
22305#       none                                                            #
22306#                                                                       #
22307# INPUT *************************************************************** #
22308#       a0 = pointer fp extended precision operand to normalize         #
22309#                                                                       #
22310# OUTPUT ************************************************************** #
22311#       d0 = number of bit positions the mantissa was shifted           #
22312#       a0 = the input operand's mantissa is normalized; the exponent   #
22313#            is unchanged.                                              #
22314#                                                                       #
22315#########################################################################
22316        global          norm
22317norm:
22318        mov.l           %d2, -(%sp)             # create some temp regs
22319        mov.l           %d3, -(%sp)
22320
22321        mov.l           FTEMP_HI(%a0), %d0      # load hi(mantissa)
22322        mov.l           FTEMP_LO(%a0), %d1      # load lo(mantissa)
22323
22324        bfffo           %d0{&0:&32}, %d2        # how many places to shift?
22325        beq.b           norm_lo                 # hi(man) is all zeroes!
22326
22327norm_hi:
22328        lsl.l           %d2, %d0                # left shift hi(man)
22329        bfextu          %d1{&0:%d2}, %d3        # extract lo bits
22330
22331        or.l            %d3, %d0                # create hi(man)
22332        lsl.l           %d2, %d1                # create lo(man)
22333
22334        mov.l           %d0, FTEMP_HI(%a0)      # store new hi(man)
22335        mov.l           %d1, FTEMP_LO(%a0)      # store new lo(man)
22336
22337        mov.l           %d2, %d0                # return shift amount
22338
22339        mov.l           (%sp)+, %d3             # restore temp regs
22340        mov.l           (%sp)+, %d2
22341
22342        rts
22343
22344norm_lo:
22345        bfffo           %d1{&0:&32}, %d2        # how many places to shift?
22346        lsl.l           %d2, %d1                # shift lo(man)
22347        add.l           &32, %d2                # add 32 to shft amount
22348
22349        mov.l           %d1, FTEMP_HI(%a0)      # store hi(man)
22350        clr.l           FTEMP_LO(%a0)           # lo(man) is now zero
22351
22352        mov.l           %d2, %d0                # return shift amount
22353
22354        mov.l           (%sp)+, %d3             # restore temp regs
22355        mov.l           (%sp)+, %d2
22356
22357        rts
22358
22359#########################################################################
22360# unnorm_fix(): - changes an UNNORM to one of NORM, DENORM, or ZERO     #
22361#               - returns corresponding optype tag                      #
22362#                                                                       #
22363# XDEF **************************************************************** #
22364#       unnorm_fix()                                                    #
22365#                                                                       #
22366# XREF **************************************************************** #
22367#       norm() - normalize the mantissa                                 #
22368#                                                                       #
22369# INPUT *************************************************************** #
22370#       a0 = pointer to unnormalized extended precision number          #
22371#                                                                       #
22372# OUTPUT ************************************************************** #
22373#       d0 = optype tag - is corrected to one of NORM, DENORM, or ZERO  #
22374#       a0 = input operand has been converted to a norm, denorm, or     #
22375#            zero; both the exponent and mantissa are changed.          #
22376#                                                                       #
22377#########################################################################
22378
22379        global          unnorm_fix
22380unnorm_fix:
22381        bfffo           FTEMP_HI(%a0){&0:&32}, %d0 # how many shifts are needed?
22382        bne.b           unnorm_shift            # hi(man) is not all zeroes
22383
22384#
22385# hi(man) is all zeroes so see if any bits in lo(man) are set
22386#
22387unnorm_chk_lo:
22388        bfffo           FTEMP_LO(%a0){&0:&32}, %d0 # is operand really a zero?
22389        beq.w           unnorm_zero             # yes
22390
22391        add.w           &32, %d0                # no; fix shift distance
22392
22393#
22394# d0 = # shifts needed for complete normalization
22395#
22396unnorm_shift:
22397        clr.l           %d1                     # clear top word
22398        mov.w           FTEMP_EX(%a0), %d1      # extract exponent
22399        and.w           &0x7fff, %d1            # strip off sgn
22400
22401        cmp.w           %d0, %d1                # will denorm push exp < 0?
22402        bgt.b           unnorm_nrm_zero         # yes; denorm only until exp = 0
22403
22404#
22405# exponent would not go < 0. Therefore, number stays normalized
22406#
22407        sub.w           %d0, %d1                # shift exponent value
22408        mov.w           FTEMP_EX(%a0), %d0      # load old exponent
22409        and.w           &0x8000, %d0            # save old sign
22410        or.w            %d0, %d1                # {sgn,new exp}
22411        mov.w           %d1, FTEMP_EX(%a0)      # insert new exponent
22412
22413        bsr.l           norm                    # normalize UNNORM
22414
22415        mov.b           &NORM, %d0              # return new optype tag
22416        rts
22417
22418#
22419# exponent would go < 0, so only denormalize until exp = 0
22420#
22421unnorm_nrm_zero:
22422        cmp.b           %d1, &32                # is exp <= 32?
22423        bgt.b           unnorm_nrm_zero_lrg     # no; go handle large exponent
22424
22425        bfextu          FTEMP_HI(%a0){%d1:&32}, %d0 # extract new hi(man)
22426        mov.l           %d0, FTEMP_HI(%a0)      # save new hi(man)
22427
22428        mov.l           FTEMP_LO(%a0), %d0      # fetch old lo(man)
22429        lsl.l           %d1, %d0                # extract new lo(man)
22430        mov.l           %d0, FTEMP_LO(%a0)      # save new lo(man)
22431
22432        and.w           &0x8000, FTEMP_EX(%a0)  # set exp = 0
22433
22434        mov.b           &DENORM, %d0            # return new optype tag
22435        rts
22436
22437#
22438# only mantissa bits set are in lo(man)
22439#
22440unnorm_nrm_zero_lrg:
22441        sub.w           &32, %d1                # adjust shft amt by 32
22442
22443        mov.l           FTEMP_LO(%a0), %d0      # fetch old lo(man)
22444        lsl.l           %d1, %d0                # left shift lo(man)
22445
22446        mov.l           %d0, FTEMP_HI(%a0)      # store new hi(man)
22447        clr.l           FTEMP_LO(%a0)           # lo(man) = 0
22448
22449        and.w           &0x8000, FTEMP_EX(%a0)  # set exp = 0
22450
22451        mov.b           &DENORM, %d0            # return new optype tag
22452        rts
22453
22454#
22455# whole mantissa is zero so this UNNORM is actually a zero
22456#
22457unnorm_zero:
22458        and.w           &0x8000, FTEMP_EX(%a0)  # force exponent to zero
22459
22460        mov.b           &ZERO, %d0              # fix optype tag
22461        rts
22462
22463#########################################################################
22464# XDEF **************************************************************** #
22465#       set_tag_x(): return the optype of the input ext fp number       #
22466#                                                                       #
22467# XREF **************************************************************** #
22468#       None                                                            #
22469#                                                                       #
22470# INPUT *************************************************************** #
22471#       a0 = pointer to extended precision operand                      #
22472#                                                                       #
22473# OUTPUT ************************************************************** #
22474#       d0 = value of type tag                                          #
22475#               one of: NORM, INF, QNAN, SNAN, DENORM, UNNORM, ZERO     #
22476#                                                                       #
22477# ALGORITHM *********************************************************** #
22478#       Simply test the exponent, j-bit, and mantissa values to         #
22479# determine the type of operand.                                        #
22480#       If it's an unnormalized zero, alter the operand and force it    #
22481# to be a normal zero.                                                  #
22482#                                                                       #
22483#########################################################################
22484
22485        global          set_tag_x
22486set_tag_x:
22487        mov.w           FTEMP_EX(%a0), %d0      # extract exponent
22488        andi.w          &0x7fff, %d0            # strip off sign
22489        cmpi.w          %d0, &0x7fff            # is (EXP == MAX)?
22490        beq.b           inf_or_nan_x
22491not_inf_or_nan_x:
22492        btst            &0x7,FTEMP_HI(%a0)
22493        beq.b           not_norm_x
22494is_norm_x:
22495        mov.b           &NORM, %d0
22496        rts
22497not_norm_x:
22498        tst.w           %d0                     # is exponent = 0?
22499        bne.b           is_unnorm_x
22500not_unnorm_x:
22501        tst.l           FTEMP_HI(%a0)
22502        bne.b           is_denorm_x
22503        tst.l           FTEMP_LO(%a0)
22504        bne.b           is_denorm_x
22505is_zero_x:
22506        mov.b           &ZERO, %d0
22507        rts
22508is_denorm_x:
22509        mov.b           &DENORM, %d0
22510        rts
22511# must distinguish now "Unnormalized zeroes" which we
22512# must convert to zero.
22513is_unnorm_x:
22514        tst.l           FTEMP_HI(%a0)
22515        bne.b           is_unnorm_reg_x
22516        tst.l           FTEMP_LO(%a0)
22517        bne.b           is_unnorm_reg_x
22518# it's an "unnormalized zero". let's convert it to an actual zero...
22519        andi.w          &0x8000,FTEMP_EX(%a0)   # clear exponent
22520        mov.b           &ZERO, %d0
22521        rts
22522is_unnorm_reg_x:
22523        mov.b           &UNNORM, %d0
22524        rts
22525inf_or_nan_x:
22526        tst.l           FTEMP_LO(%a0)
22527        bne.b           is_nan_x
22528        mov.l           FTEMP_HI(%a0), %d0
22529        and.l           &0x7fffffff, %d0        # msb is a don't care!
22530        bne.b           is_nan_x
22531is_inf_x:
22532        mov.b           &INF, %d0
22533        rts
22534is_nan_x:
22535        btst            &0x6, FTEMP_HI(%a0)
22536        beq.b           is_snan_x
22537        mov.b           &QNAN, %d0
22538        rts
22539is_snan_x:
22540        mov.b           &SNAN, %d0
22541        rts
22542
22543#########################################################################
22544# XDEF **************************************************************** #
22545#       set_tag_d(): return the optype of the input dbl fp number       #
22546#                                                                       #
22547# XREF **************************************************************** #
22548#       None                                                            #
22549#                                                                       #
22550# INPUT *************************************************************** #
22551#       a0 = points to double precision operand                         #
22552#                                                                       #
22553# OUTPUT ************************************************************** #
22554#       d0 = value of type tag                                          #
22555#               one of: NORM, INF, QNAN, SNAN, DENORM, ZERO             #
22556#                                                                       #
22557# ALGORITHM *********************************************************** #
22558#       Simply test the exponent, j-bit, and mantissa values to         #
22559# determine the type of operand.                                        #
22560#                                                                       #
22561#########################################################################
22562
22563        global          set_tag_d
22564set_tag_d:
22565        mov.l           FTEMP(%a0), %d0
22566        mov.l           %d0, %d1
22567
22568        andi.l          &0x7ff00000, %d0
22569        beq.b           zero_or_denorm_d
22570
22571        cmpi.l          %d0, &0x7ff00000
22572        beq.b           inf_or_nan_d
22573
22574is_norm_d:
22575        mov.b           &NORM, %d0
22576        rts
22577zero_or_denorm_d:
22578        and.l           &0x000fffff, %d1
22579        bne             is_denorm_d
22580        tst.l           4+FTEMP(%a0)
22581        bne             is_denorm_d
22582is_zero_d:
22583        mov.b           &ZERO, %d0
22584        rts
22585is_denorm_d:
22586        mov.b           &DENORM, %d0
22587        rts
22588inf_or_nan_d:
22589        and.l           &0x000fffff, %d1
22590        bne             is_nan_d
22591        tst.l           4+FTEMP(%a0)
22592        bne             is_nan_d
22593is_inf_d:
22594        mov.b           &INF, %d0
22595        rts
22596is_nan_d:
22597        btst            &19, %d1
22598        bne             is_qnan_d
22599is_snan_d:
22600        mov.b           &SNAN, %d0
22601        rts
22602is_qnan_d:
22603        mov.b           &QNAN, %d0
22604        rts
22605
22606#########################################################################
22607# XDEF **************************************************************** #
22608#       set_tag_s(): return the optype of the input sgl fp number       #
22609#                                                                       #
22610# XREF **************************************************************** #
22611#       None                                                            #
22612#                                                                       #
22613# INPUT *************************************************************** #
22614#       a0 = pointer to single precision operand                        #
22615#                                                                       #
22616# OUTPUT ************************************************************** #
22617#       d0 = value of type tag                                          #
22618#               one of: NORM, INF, QNAN, SNAN, DENORM, ZERO             #
22619#                                                                       #
22620# ALGORITHM *********************************************************** #
22621#       Simply test the exponent, j-bit, and mantissa values to         #
22622# determine the type of operand.                                        #
22623#                                                                       #
22624#########################################################################
22625
22626        global          set_tag_s
22627set_tag_s:
22628        mov.l           FTEMP(%a0), %d0
22629        mov.l           %d0, %d1
22630
22631        andi.l          &0x7f800000, %d0
22632        beq.b           zero_or_denorm_s
22633
22634        cmpi.l          %d0, &0x7f800000
22635        beq.b           inf_or_nan_s
22636
22637is_norm_s:
22638        mov.b           &NORM, %d0
22639        rts
22640zero_or_denorm_s:
22641        and.l           &0x007fffff, %d1
22642        bne             is_denorm_s
22643is_zero_s:
22644        mov.b           &ZERO, %d0
22645        rts
22646is_denorm_s:
22647        mov.b           &DENORM, %d0
22648        rts
22649inf_or_nan_s:
22650        and.l           &0x007fffff, %d1
22651        bne             is_nan_s
22652is_inf_s:
22653        mov.b           &INF, %d0
22654        rts
22655is_nan_s:
22656        btst            &22, %d1
22657        bne             is_qnan_s
22658is_snan_s:
22659        mov.b           &SNAN, %d0
22660        rts
22661is_qnan_s:
22662        mov.b           &QNAN, %d0
22663        rts
22664
22665#########################################################################
22666# XDEF **************************************************************** #
22667#       unf_res(): routine to produce default underflow result of a     #
22668#                  scaled extended precision number; this is used by    #
22669#                  fadd/fdiv/fmul/etc. emulation routines.              #
22670#       unf_res4(): same as above but for fsglmul/fsgldiv which use     #
22671#                   single round prec and extended prec mode.           #
22672#                                                                       #
22673# XREF **************************************************************** #
22674#       _denorm() - denormalize according to scale factor               #
22675#       _round() - round denormalized number according to rnd prec      #
22676#                                                                       #
22677# INPUT *************************************************************** #
22678#       a0 = pointer to extended precison operand                       #
22679#       d0 = scale factor                                               #
22680#       d1 = rounding precision/mode                                    #
22681#                                                                       #
22682# OUTPUT ************************************************************** #
22683#       a0 = pointer to default underflow result in extended precision  #
22684#       d0.b = result FPSR_cc which caller may or may not want to save  #
22685#                                                                       #
22686# ALGORITHM *********************************************************** #
22687#       Convert the input operand to "internal format" which means the  #
22688# exponent is extended to 16 bits and the sign is stored in the unused  #
22689# portion of the extended precison operand. Denormalize the number      #
22690# according to the scale factor passed in d0. Then, round the           #
22691# denormalized result.                                                  #
22692#       Set the FPSR_exc bits as appropriate but return the cc bits in  #
22693# d0 in case the caller doesn't want to save them (as is the case for   #
22694# fmove out).                                                           #
22695#       unf_res4() for fsglmul/fsgldiv forces the denorm to extended    #
22696# precision and the rounding mode to single.                            #
22697#                                                                       #
22698#########################################################################
22699        global          unf_res
22700unf_res:
22701        mov.l           %d1, -(%sp)             # save rnd prec,mode on stack
22702
22703        btst            &0x7, FTEMP_EX(%a0)     # make "internal" format
22704        sne             FTEMP_SGN(%a0)
22705
22706        mov.w           FTEMP_EX(%a0), %d1      # extract exponent
22707        and.w           &0x7fff, %d1
22708        sub.w           %d0, %d1
22709        mov.w           %d1, FTEMP_EX(%a0)      # insert 16 bit exponent
22710
22711        mov.l           %a0, -(%sp)             # save operand ptr during calls
22712
22713        mov.l           0x4(%sp),%d0            # pass rnd prec.
22714        andi.w          &0x00c0,%d0
22715        lsr.w           &0x4,%d0
22716        bsr.l           _denorm                 # denorm result
22717
22718        mov.l           (%sp),%a0
22719        mov.w           0x6(%sp),%d1            # load prec:mode into %d1
22720        andi.w          &0xc0,%d1               # extract rnd prec
22721        lsr.w           &0x4,%d1
22722        swap            %d1
22723        mov.w           0x6(%sp),%d1
22724        andi.w          &0x30,%d1
22725        lsr.w           &0x4,%d1
22726        bsr.l           _round                  # round the denorm
22727
22728        mov.l           (%sp)+, %a0
22729
22730# result is now rounded properly. convert back to normal format
22731        bclr            &0x7, FTEMP_EX(%a0)     # clear sgn first; may have residue
22732        tst.b           FTEMP_SGN(%a0)          # is "internal result" sign set?
22733        beq.b           unf_res_chkifzero       # no; result is positive
22734        bset            &0x7, FTEMP_EX(%a0)     # set result sgn
22735        clr.b           FTEMP_SGN(%a0)          # clear temp sign
22736
22737# the number may have become zero after rounding. set ccodes accordingly.
22738unf_res_chkifzero:
22739        clr.l           %d0
22740        tst.l           FTEMP_HI(%a0)           # is value now a zero?
22741        bne.b           unf_res_cont            # no
22742        tst.l           FTEMP_LO(%a0)
22743        bne.b           unf_res_cont            # no
22744#       bset            &z_bit, FPSR_CC(%a6)    # yes; set zero ccode bit
22745        bset            &z_bit, %d0             # yes; set zero ccode bit
22746
22747unf_res_cont:
22748
22749#
22750# can inex1 also be set along with unfl and inex2???
22751#
22752# we know that underflow has occurred. aunfl should be set if INEX2 is also set.
22753#
22754        btst            &inex2_bit, FPSR_EXCEPT(%a6) # is INEX2 set?
22755        beq.b           unf_res_end             # no
22756        bset            &aunfl_bit, FPSR_AEXCEPT(%a6) # yes; set aunfl
22757
22758unf_res_end:
22759        add.l           &0x4, %sp               # clear stack
22760        rts
22761
22762# unf_res() for fsglmul() and fsgldiv().
22763        global          unf_res4
22764unf_res4:
22765        mov.l           %d1,-(%sp)              # save rnd prec,mode on stack
22766
22767        btst            &0x7,FTEMP_EX(%a0)      # make "internal" format
22768        sne             FTEMP_SGN(%a0)
22769
22770        mov.w           FTEMP_EX(%a0),%d1       # extract exponent
22771        and.w           &0x7fff,%d1
22772        sub.w           %d0,%d1
22773        mov.w           %d1,FTEMP_EX(%a0)       # insert 16 bit exponent
22774
22775        mov.l           %a0,-(%sp)              # save operand ptr during calls
22776
22777        clr.l           %d0                     # force rnd prec = ext
22778        bsr.l           _denorm                 # denorm result
22779
22780        mov.l           (%sp),%a0
22781        mov.w           &s_mode,%d1             # force rnd prec = sgl
22782        swap            %d1
22783        mov.w           0x6(%sp),%d1            # load rnd mode
22784        andi.w          &0x30,%d1               # extract rnd prec
22785        lsr.w           &0x4,%d1
22786        bsr.l           _round                  # round the denorm
22787
22788        mov.l           (%sp)+,%a0
22789
22790# result is now rounded properly. convert back to normal format
22791        bclr            &0x7,FTEMP_EX(%a0)      # clear sgn first; may have residue
22792        tst.b           FTEMP_SGN(%a0)          # is "internal result" sign set?
22793        beq.b           unf_res4_chkifzero      # no; result is positive
22794        bset            &0x7,FTEMP_EX(%a0)      # set result sgn
22795        clr.b           FTEMP_SGN(%a0)          # clear temp sign
22796
22797# the number may have become zero after rounding. set ccodes accordingly.
22798unf_res4_chkifzero:
22799        clr.l           %d0
22800        tst.l           FTEMP_HI(%a0)           # is value now a zero?
22801        bne.b           unf_res4_cont           # no
22802        tst.l           FTEMP_LO(%a0)
22803        bne.b           unf_res4_cont           # no
22804#       bset            &z_bit,FPSR_CC(%a6)     # yes; set zero ccode bit
22805        bset            &z_bit,%d0              # yes; set zero ccode bit
22806
22807unf_res4_cont:
22808
22809#
22810# can inex1 also be set along with unfl and inex2???
22811#
22812# we know that underflow has occurred. aunfl should be set if INEX2 is also set.
22813#
22814        btst            &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
22815        beq.b           unf_res4_end            # no
22816        bset            &aunfl_bit,FPSR_AEXCEPT(%a6) # yes; set aunfl
22817
22818unf_res4_end:
22819        add.l           &0x4,%sp                # clear stack
22820        rts
22821
22822#########################################################################
22823# XDEF **************************************************************** #
22824#       ovf_res(): routine to produce the default overflow result of    #
22825#                  an overflowing number.                               #
22826#       ovf_res2(): same as above but the rnd mode/prec are passed      #
22827#                   differently.                                        #
22828#                                                                       #
22829# XREF **************************************************************** #
22830#       none                                                            #
22831#                                                                       #
22832# INPUT *************************************************************** #
22833#       d1.b    = '-1' => (-); '0' => (+)                               #
22834#   ovf_res():                                                          #
22835#       d0      = rnd mode/prec                                         #
22836#   ovf_res2():                                                         #
22837#       hi(d0)  = rnd prec                                              #
22838#       lo(d0)  = rnd mode                                              #
22839#                                                                       #
22840# OUTPUT ************************************************************** #
22841#       a0      = points to extended precision result                   #
22842#       d0.b    = condition code bits                                   #
22843#                                                                       #
22844# ALGORITHM *********************************************************** #
22845#       The default overflow result can be determined by the sign of    #
22846# the result and the rounding mode/prec in effect. These bits are       #
22847# concatenated together to create an index into the default result      #
22848# table. A pointer to the correct result is returned in a0. The         #
22849# resulting condition codes are returned in d0 in case the caller       #
22850# doesn't want FPSR_cc altered (as is the case for fmove out).          #
22851#                                                                       #
22852#########################################################################
22853
22854        global          ovf_res
22855ovf_res:
22856        andi.w          &0x10,%d1               # keep result sign
22857        lsr.b           &0x4,%d0                # shift prec/mode
22858        or.b            %d0,%d1                 # concat the two
22859        mov.w           %d1,%d0                 # make a copy
22860        lsl.b           &0x1,%d1                # multiply d1 by 2
22861        bra.b           ovf_res_load
22862
22863        global          ovf_res2
22864ovf_res2:
22865        and.w           &0x10, %d1              # keep result sign
22866        or.b            %d0, %d1                # insert rnd mode
22867        swap            %d0
22868        or.b            %d0, %d1                # insert rnd prec
22869        mov.w           %d1, %d0                # make a copy
22870        lsl.b           &0x1, %d1               # shift left by 1
22871
22872#
22873# use the rounding mode, precision, and result sign as in index into the
22874# two tables below to fetch the default result and the result ccodes.
22875#
22876ovf_res_load:
22877        mov.b           (tbl_ovfl_cc.b,%pc,%d0.w*1), %d0 # fetch result ccodes
22878        lea             (tbl_ovfl_result.b,%pc,%d1.w*8), %a0 # return result ptr
22879
22880        rts
22881
22882tbl_ovfl_cc:
22883        byte            0x2, 0x0, 0x0, 0x2
22884        byte            0x2, 0x0, 0x0, 0x2
22885        byte            0x2, 0x0, 0x0, 0x2
22886        byte            0x0, 0x0, 0x0, 0x0
22887        byte            0x2+0x8, 0x8, 0x2+0x8, 0x8
22888        byte            0x2+0x8, 0x8, 0x2+0x8, 0x8
22889        byte            0x2+0x8, 0x8, 0x2+0x8, 0x8
22890
22891tbl_ovfl_result:
22892        long            0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
22893        long            0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RZ
22894        long            0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RM
22895        long            0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP
22896
22897        long            0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
22898        long            0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RZ
22899        long            0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RM
22900        long            0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP
22901
22902        long            0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
22903        long            0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RZ
22904        long            0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RM
22905        long            0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP
22906
22907        long            0x00000000,0x00000000,0x00000000,0x00000000
22908        long            0x00000000,0x00000000,0x00000000,0x00000000
22909        long            0x00000000,0x00000000,0x00000000,0x00000000
22910        long            0x00000000,0x00000000,0x00000000,0x00000000
22911
22912        long            0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
22913        long            0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RZ
22914        long            0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
22915        long            0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RP
22916
22917        long            0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
22918        long            0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RZ
22919        long            0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
22920        long            0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RP
22921
22922        long            0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
22923        long            0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RZ
22924        long            0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
22925        long            0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RP
22926
22927#########################################################################
22928# XDEF **************************************************************** #
22929#       get_packed(): fetch a packed operand from memory and then       #
22930#                     convert it to a floating-point binary number.     #
22931#                                                                       #
22932# XREF **************************************************************** #
22933#       _dcalc_ea() - calculate the correct <ea>                        #
22934#       _mem_read() - fetch the packed operand from memory              #
22935#       facc_in_x() - the fetch failed so jump to special exit code     #
22936#       decbin()    - convert packed to binary extended precision       #
22937#                                                                       #
22938# INPUT *************************************************************** #
22939#       None                                                            #
22940#                                                                       #
22941# OUTPUT ************************************************************** #
22942#       If no failure on _mem_read():                                   #
22943#       FP_SRC(a6) = packed operand now as a binary FP number           #
22944#                                                                       #
22945# ALGORITHM *********************************************************** #
22946#       Get the correct <ea> which is the value on the exception stack  #
22947# frame w/ maybe a correction factor if the <ea> is -(an) or (an)+.     #
22948# Then, fetch the operand from memory. If the fetch fails, exit         #
22949# through facc_in_x().                                                  #
22950#       If the packed operand is a ZERO,NAN, or INF, convert it to      #
22951# its binary representation here. Else, call decbin() which will        #
22952# convert the packed value to an extended precision binary value.       #
22953#                                                                       #
22954#########################################################################
22955
22956# the stacked <ea> for packed is correct except for -(An).
22957# the base reg must be updated for both -(An) and (An)+.
22958        global          get_packed
22959get_packed:
22960        mov.l           &0xc,%d0                # packed is 12 bytes
22961        bsr.l           _dcalc_ea               # fetch <ea>; correct An
22962
22963        lea             FP_SRC(%a6),%a1         # pass: ptr to super dst
22964        mov.l           &0xc,%d0                # pass: 12 bytes
22965        bsr.l           _dmem_read              # read packed operand
22966
22967        tst.l           %d1                     # did dfetch fail?
22968        bne.l           facc_in_x               # yes
22969
22970# The packed operand is an INF or a NAN if the exponent field is all ones.
22971        bfextu          FP_SRC(%a6){&1:&15},%d0 # get exp
22972        cmpi.w          %d0,&0x7fff             # INF or NAN?
22973        bne.b           gp_try_zero             # no
22974        rts                                     # operand is an INF or NAN
22975
22976# The packed operand is a zero if the mantissa is all zero, else it's
22977# a normal packed op.
22978gp_try_zero:
22979        mov.b           3+FP_SRC(%a6),%d0       # get byte 4
22980        andi.b          &0x0f,%d0               # clear all but last nybble
22981        bne.b           gp_not_spec             # not a zero
22982        tst.l           FP_SRC_HI(%a6)          # is lw 2 zero?
22983        bne.b           gp_not_spec             # not a zero
22984        tst.l           FP_SRC_LO(%a6)          # is lw 3 zero?
22985        bne.b           gp_not_spec             # not a zero
22986        rts                                     # operand is a ZERO
22987gp_not_spec:
22988        lea             FP_SRC(%a6),%a0         # pass: ptr to packed op
22989        bsr.l           decbin                  # convert to extended
22990        fmovm.x         &0x80,FP_SRC(%a6)       # make this the srcop
22991        rts
22992
22993#########################################################################
22994# decbin(): Converts normalized packed bcd value pointed to by register #
22995#           a0 to extended-precision value in fp0.                      #
22996#                                                                       #
22997# INPUT *************************************************************** #
22998#       a0 = pointer to normalized packed bcd value                     #
22999#                                                                       #
23000# OUTPUT ************************************************************** #
23001#       fp0 = exact fp representation of the packed bcd value.          #
23002#                                                                       #
23003# ALGORITHM *********************************************************** #
23004#       Expected is a normal bcd (i.e. non-exceptional; all inf, zero,  #
23005#       and NaN operands are dispatched without entering this routine)  #
23006#       value in 68881/882 format at location (a0).                     #
23007#                                                                       #
23008#       A1. Convert the bcd exponent to binary by successive adds and   #
23009#       muls. Set the sign according to SE. Subtract 16 to compensate   #
23010#       for the mantissa which is to be interpreted as 17 integer       #
23011#       digits, rather than 1 integer and 16 fraction digits.           #
23012#       Note: this operation can never overflow.                        #
23013#                                                                       #
23014#       A2. Convert the bcd mantissa to binary by successive            #
23015#       adds and muls in FP0. Set the sign according to SM.             #
23016#       The mantissa digits will be converted with the decimal point    #
23017#       assumed following the least-significant digit.                  #
23018#       Note: this operation can never overflow.                        #
23019#                                                                       #
23020#       A3. Count the number of leading/trailing zeros in the           #
23021#       bcd string.  If SE is positive, count the leading zeros;        #
23022#       if negative, count the trailing zeros.  Set the adjusted        #
23023#       exponent equal to the exponent from A1 and the zero count       #
23024#       added if SM = 1 and subtracted if SM = 0.  Scale the            #
23025#       mantissa the equivalent of forcing in the bcd value:            #
23026#                                                                       #
23027#       SM = 0  a non-zero digit in the integer position                #
23028#       SM = 1  a non-zero digit in Mant0, lsd of the fraction          #
23029#                                                                       #
23030#       this will insure that any value, regardless of its              #
23031#       representation (ex. 0.1E2, 1E1, 10E0, 100E-1), is converted     #
23032#       consistently.                                                   #
23033#                                                                       #
23034#       A4. Calculate the factor 10^exp in FP1 using a table of         #
23035#       10^(2^n) values.  To reduce the error in forming factors        #
23036#       greater than 10^27, a directed rounding scheme is used with     #
23037#       tables rounded to RN, RM, and RP, according to the table        #
23038#       in the comments of the pwrten section.                          #
23039#                                                                       #
23040#       A5. Form the final binary number by scaling the mantissa by     #
23041#       the exponent factor.  This is done by multiplying the           #
23042#       mantissa in FP0 by the factor in FP1 if the adjusted            #
23043#       exponent sign is positive, and dividing FP0 by FP1 if           #
23044#       it is negative.                                                 #
23045#                                                                       #
23046#       Clean up and return. Check if the final mul or div was inexact. #
23047#       If so, set INEX1 in USER_FPSR.                                  #
23048#                                                                       #
23049#########################################################################
23050
23051#
23052#       PTENRN, PTENRM, and PTENRP are arrays of powers of 10 rounded
23053#       to nearest, minus, and plus, respectively.  The tables include
23054#       10**{1,2,4,8,16,32,64,128,256,512,1024,2048,4096}.  No rounding
23055#       is required until the power is greater than 27, however, all
23056#       tables include the first 5 for ease of indexing.
23057#
23058RTABLE:
23059        byte            0,0,0,0
23060        byte            2,3,2,3
23061        byte            2,3,3,2
23062        byte            3,2,2,3
23063
23064        set             FNIBS,7
23065        set             FSTRT,0
23066
23067        set             ESTRT,4
23068        set             EDIGITS,2
23069
23070        global          decbin
23071decbin:
23072        mov.l           0x0(%a0),FP_SCR0_EX(%a6) # make a copy of input
23073        mov.l           0x4(%a0),FP_SCR0_HI(%a6) # so we don't alter it
23074        mov.l           0x8(%a0),FP_SCR0_LO(%a6)
23075
23076        lea             FP_SCR0(%a6),%a0
23077
23078        movm.l          &0x3c00,-(%sp)          # save d2-d5
23079        fmovm.x         &0x1,-(%sp)             # save fp1
23080#
23081# Calculate exponent:
23082#  1. Copy bcd value in memory for use as a working copy.
23083#  2. Calculate absolute value of exponent in d1 by mul and add.
23084#  3. Correct for exponent sign.
23085#  4. Subtract 16 to compensate for interpreting the mant as all integer digits.
23086#     (i.e., all digits assumed left of the decimal point.)
23087#
23088# Register usage:
23089#
23090#  calc_e:
23091#       (*)  d0: temp digit storage
23092#       (*)  d1: accumulator for binary exponent
23093#       (*)  d2: digit count
23094#       (*)  d3: offset pointer
23095#       ( )  d4: first word of bcd
23096#       ( )  a0: pointer to working bcd value
23097#       ( )  a6: pointer to original bcd value
23098#       (*)  FP_SCR1: working copy of original bcd value
23099#       (*)  L_SCR1: copy of original exponent word
23100#
23101calc_e:
23102        mov.l           &EDIGITS,%d2            # # of nibbles (digits) in fraction part
23103        mov.l           &ESTRT,%d3              # counter to pick up digits
23104        mov.l           (%a0),%d4               # get first word of bcd
23105        clr.l           %d1                     # zero d1 for accumulator
23106e_gd:
23107        mulu.l          &0xa,%d1                # mul partial product by one digit place
23108        bfextu          %d4{%d3:&4},%d0         # get the digit and zero extend into d0
23109        add.l           %d0,%d1                 # d1 = d1 + d0
23110        addq.b          &4,%d3                  # advance d3 to the next digit
23111        dbf.w           %d2,e_gd                # if we have used all 3 digits, exit loop
23112        btst            &30,%d4                 # get SE
23113        beq.b           e_pos                   # don't negate if pos
23114        neg.l           %d1                     # negate before subtracting
23115e_pos:
23116        sub.l           &16,%d1                 # sub to compensate for shift of mant
23117        bge.b           e_save                  # if still pos, do not neg
23118        neg.l           %d1                     # now negative, make pos and set SE
23119        or.l            &0x40000000,%d4         # set SE in d4,
23120        or.l            &0x40000000,(%a0)       # and in working bcd
23121e_save:
23122        mov.l           %d1,-(%sp)              # save exp on stack
23123#
23124#
23125# Calculate mantissa:
23126#  1. Calculate absolute value of mantissa in fp0 by mul and add.
23127#  2. Correct for mantissa sign.
23128#     (i.e., all digits assumed left of the decimal point.)
23129#
23130# Register usage:
23131#
23132#  calc_m:
23133#       (*)  d0: temp digit storage
23134#       (*)  d1: lword counter
23135#       (*)  d2: digit count
23136#       (*)  d3: offset pointer
23137#       ( )  d4: words 2 and 3 of bcd
23138#       ( )  a0: pointer to working bcd value
23139#       ( )  a6: pointer to original bcd value
23140#       (*) fp0: mantissa accumulator
23141#       ( )  FP_SCR1: working copy of original bcd value
23142#       ( )  L_SCR1: copy of original exponent word
23143#
23144calc_m:
23145        mov.l           &1,%d1                  # word counter, init to 1
23146        fmov.s          &0x00000000,%fp0        # accumulator
23147#
23148#
23149#  Since the packed number has a long word between the first & second parts,
23150#  get the integer digit then skip down & get the rest of the
23151#  mantissa.  We will unroll the loop once.
23152#
23153        bfextu          (%a0){&28:&4},%d0       # integer part is ls digit in long word
23154        fadd.b          %d0,%fp0                # add digit to sum in fp0
23155#
23156#
23157#  Get the rest of the mantissa.
23158#
23159loadlw:
23160        mov.l           (%a0,%d1.L*4),%d4       # load mantissa lonqword into d4
23161        mov.l           &FSTRT,%d3              # counter to pick up digits
23162        mov.l           &FNIBS,%d2              # reset number of digits per a0 ptr
23163md2b:
23164        fmul.s          &0x41200000,%fp0        # fp0 = fp0 * 10
23165        bfextu          %d4{%d3:&4},%d0         # get the digit and zero extend
23166        fadd.b          %d0,%fp0                # fp0 = fp0 + digit
23167#
23168#
23169#  If all the digits (8) in that long word have been converted (d2=0),
23170#  then inc d1 (=2) to point to the next long word and reset d3 to 0
23171#  to initialize the digit offset, and set d2 to 7 for the digit count;
23172#  else continue with this long word.
23173#
23174        addq.b          &4,%d3                  # advance d3 to the next digit
23175        dbf.w           %d2,md2b                # check for last digit in this lw
23176nextlw:
23177        addq.l          &1,%d1                  # inc lw pointer in mantissa
23178        cmp.l           %d1,&2                  # test for last lw
23179        ble.b           loadlw                  # if not, get last one
23180#
23181#  Check the sign of the mant and make the value in fp0 the same sign.
23182#
23183m_sign:
23184        btst            &31,(%a0)               # test sign of the mantissa
23185        beq.b           ap_st_z                 # if clear, go to append/strip zeros
23186        fneg.x          %fp0                    # if set, negate fp0
23187#
23188# Append/strip zeros:
23189#
23190#  For adjusted exponents which have an absolute value greater than 27*,
23191#  this routine calculates the amount needed to normalize the mantissa
23192#  for the adjusted exponent.  That number is subtracted from the exp
23193#  if the exp was positive, and added if it was negative.  The purpose
23194#  of this is to reduce the value of the exponent and the possibility
23195#  of error in calculation of pwrten.
23196#
23197#  1. Branch on the sign of the adjusted exponent.
23198#  2p.(positive exp)
23199#   2. Check M16 and the digits in lwords 2 and 3 in descending order.
23200#   3. Add one for each zero encountered until a non-zero digit.
23201#   4. Subtract the count from the exp.
23202#   5. Check if the exp has crossed zero in #3 above; make the exp abs
23203#          and set SE.
23204#       6. Multiply the mantissa by 10**count.
23205#  2n.(negative exp)
23206#   2. Check the digits in lwords 3 and 2 in descending order.
23207#   3. Add one for each zero encountered until a non-zero digit.
23208#   4. Add the count to the exp.
23209#   5. Check if the exp has crossed zero in #3 above; clear SE.
23210#   6. Divide the mantissa by 10**count.
23211#
23212#  *Why 27?  If the adjusted exponent is within -28 < expA < 28, than
23213#   any adjustment due to append/strip zeros will drive the resultane
23214#   exponent towards zero.  Since all pwrten constants with a power
23215#   of 27 or less are exact, there is no need to use this routine to
23216#   attempt to lessen the resultant exponent.
23217#
23218# Register usage:
23219#
23220#  ap_st_z:
23221#       (*)  d0: temp digit storage
23222#       (*)  d1: zero count
23223#       (*)  d2: digit count
23224#       (*)  d3: offset pointer
23225#       ( )  d4: first word of bcd
23226#       (*)  d5: lword counter
23227#       ( )  a0: pointer to working bcd value
23228#       ( )  FP_SCR1: working copy of original bcd value
23229#       ( )  L_SCR1: copy of original exponent word
23230#
23231#
23232# First check the absolute value of the exponent to see if this
23233# routine is necessary.  If so, then check the sign of the exponent
23234# and do append (+) or strip (-) zeros accordingly.
23235# This section handles a positive adjusted exponent.
23236#
23237ap_st_z:
23238        mov.l           (%sp),%d1               # load expA for range test
23239        cmp.l           %d1,&27                 # test is with 27
23240        ble.w           pwrten                  # if abs(expA) <28, skip ap/st zeros
23241        btst            &30,(%a0)               # check sign of exp
23242        bne.b           ap_st_n                 # if neg, go to neg side
23243        clr.l           %d1                     # zero count reg
23244        mov.l           (%a0),%d4               # load lword 1 to d4
23245        bfextu          %d4{&28:&4},%d0         # get M16 in d0
23246        bne.b           ap_p_fx                 # if M16 is non-zero, go fix exp
23247        addq.l          &1,%d1                  # inc zero count
23248        mov.l           &1,%d5                  # init lword counter
23249        mov.l           (%a0,%d5.L*4),%d4       # get lword 2 to d4
23250        bne.b           ap_p_cl                 # if lw 2 is zero, skip it
23251        addq.l          &8,%d1                  # and inc count by 8
23252        addq.l          &1,%d5                  # inc lword counter
23253        mov.l           (%a0,%d5.L*4),%d4       # get lword 3 to d4
23254ap_p_cl:
23255        clr.l           %d3                     # init offset reg
23256        mov.l           &7,%d2                  # init digit counter
23257ap_p_gd:
23258        bfextu          %d4{%d3:&4},%d0         # get digit
23259        bne.b           ap_p_fx                 # if non-zero, go to fix exp
23260        addq.l          &4,%d3                  # point to next digit
23261        addq.l          &1,%d1                  # inc digit counter
23262        dbf.w           %d2,ap_p_gd             # get next digit
23263ap_p_fx:
23264        mov.l           %d1,%d0                 # copy counter to d2
23265        mov.l           (%sp),%d1               # get adjusted exp from memory
23266        sub.l           %d0,%d1                 # subtract count from exp
23267        bge.b           ap_p_fm                 # if still pos, go to pwrten
23268        neg.l           %d1                     # now its neg; get abs
23269        mov.l           (%a0),%d4               # load lword 1 to d4
23270        or.l            &0x40000000,%d4         # and set SE in d4
23271        or.l            &0x40000000,(%a0)       # and in memory
23272#
23273# Calculate the mantissa multiplier to compensate for the striping of
23274# zeros from the mantissa.
23275#
23276ap_p_fm:
23277        lea.l           PTENRN(%pc),%a1         # get address of power-of-ten table
23278        clr.l           %d3                     # init table index
23279        fmov.s          &0x3f800000,%fp1        # init fp1 to 1
23280        mov.l           &3,%d2                  # init d2 to count bits in counter
23281ap_p_el:
23282        asr.l           &1,%d0                  # shift lsb into carry
23283        bcc.b           ap_p_en                 # if 1, mul fp1 by pwrten factor
23284        fmul.x          (%a1,%d3),%fp1          # mul by 10**(d3_bit_no)
23285ap_p_en:
23286        add.l           &12,%d3                 # inc d3 to next rtable entry
23287        tst.l           %d0                     # check if d0 is zero
23288        bne.b           ap_p_el                 # if not, get next bit
23289        fmul.x          %fp1,%fp0               # mul mantissa by 10**(no_bits_shifted)
23290        bra.b           pwrten                  # go calc pwrten
23291#
23292# This section handles a negative adjusted exponent.
23293#
23294ap_st_n:
23295        clr.l           %d1                     # clr counter
23296        mov.l           &2,%d5                  # set up d5 to point to lword 3
23297        mov.l           (%a0,%d5.L*4),%d4       # get lword 3
23298        bne.b           ap_n_cl                 # if not zero, check digits
23299        sub.l           &1,%d5                  # dec d5 to point to lword 2
23300        addq.l          &8,%d1                  # inc counter by 8
23301        mov.l           (%a0,%d5.L*4),%d4       # get lword 2
23302ap_n_cl:
23303        mov.l           &28,%d3                 # point to last digit
23304        mov.l           &7,%d2                  # init digit counter
23305ap_n_gd:
23306        bfextu          %d4{%d3:&4},%d0         # get digit
23307        bne.b           ap_n_fx                 # if non-zero, go to exp fix
23308        subq.l          &4,%d3                  # point to previous digit
23309        addq.l          &1,%d1                  # inc digit counter
23310        dbf.w           %d2,ap_n_gd             # get next digit
23311ap_n_fx:
23312        mov.l           %d1,%d0                 # copy counter to d0
23313        mov.l           (%sp),%d1               # get adjusted exp from memory
23314        sub.l           %d0,%d1                 # subtract count from exp
23315        bgt.b           ap_n_fm                 # if still pos, go fix mantissa
23316        neg.l           %d1                     # take abs of exp and clr SE
23317        mov.l           (%a0),%d4               # load lword 1 to d4
23318        and.l           &0xbfffffff,%d4         # and clr SE in d4
23319        and.l           &0xbfffffff,(%a0)       # and in memory
23320#
23321# Calculate the mantissa multiplier to compensate for the appending of
23322# zeros to the mantissa.
23323#
23324ap_n_fm:
23325        lea.l           PTENRN(%pc),%a1         # get address of power-of-ten table
23326        clr.l           %d3                     # init table index
23327        fmov.s          &0x3f800000,%fp1        # init fp1 to 1
23328        mov.l           &3,%d2                  # init d2 to count bits in counter
23329ap_n_el:
23330        asr.l           &1,%d0                  # shift lsb into carry
23331        bcc.b           ap_n_en                 # if 1, mul fp1 by pwrten factor
23332        fmul.x          (%a1,%d3),%fp1          # mul by 10**(d3_bit_no)
23333ap_n_en:
23334        add.l           &12,%d3                 # inc d3 to next rtable entry
23335        tst.l           %d0                     # check if d0 is zero
23336        bne.b           ap_n_el                 # if not, get next bit
23337        fdiv.x          %fp1,%fp0               # div mantissa by 10**(no_bits_shifted)
23338#
23339#
23340# Calculate power-of-ten factor from adjusted and shifted exponent.
23341#
23342# Register usage:
23343#
23344#  pwrten:
23345#       (*)  d0: temp
23346#       ( )  d1: exponent
23347#       (*)  d2: {FPCR[6:5],SM,SE} as index in RTABLE; temp
23348#       (*)  d3: FPCR work copy
23349#       ( )  d4: first word of bcd
23350#       (*)  a1: RTABLE pointer
23351#  calc_p:
23352#       (*)  d0: temp
23353#       ( )  d1: exponent
23354#       (*)  d3: PWRTxx table index
23355#       ( )  a0: pointer to working copy of bcd
23356#       (*)  a1: PWRTxx pointer
23357#       (*) fp1: power-of-ten accumulator
23358#
23359# Pwrten calculates the exponent factor in the selected rounding mode
23360# according to the following table:
23361#
23362#       Sign of Mant  Sign of Exp  Rounding Mode  PWRTEN Rounding Mode
23363#
23364#       ANY       ANY   RN      RN
23365#
23366#        +         +    RP      RP
23367#        -         +    RP      RM
23368#        +         -    RP      RM
23369#        -         -    RP      RP
23370#
23371#        +         +    RM      RM
23372#        -         +    RM      RP
23373#        +         -    RM      RP
23374#        -         -    RM      RM
23375#
23376#        +         +    RZ      RM
23377#        -         +    RZ      RM
23378#        +         -    RZ      RP
23379#        -         -    RZ      RP
23380#
23381#
23382pwrten:
23383        mov.l           USER_FPCR(%a6),%d3      # get user's FPCR
23384        bfextu          %d3{&26:&2},%d2         # isolate rounding mode bits
23385        mov.l           (%a0),%d4               # reload 1st bcd word to d4
23386        asl.l           &2,%d2                  # format d2 to be
23387        bfextu          %d4{&0:&2},%d0          # {FPCR[6],FPCR[5],SM,SE}
23388        add.l           %d0,%d2                 # in d2 as index into RTABLE
23389        lea.l           RTABLE(%pc),%a1         # load rtable base
23390        mov.b           (%a1,%d2),%d0           # load new rounding bits from table
23391        clr.l           %d3                     # clear d3 to force no exc and extended
23392        bfins           %d0,%d3{&26:&2}         # stuff new rounding bits in FPCR
23393        fmov.l          %d3,%fpcr               # write new FPCR
23394        asr.l           &1,%d0                  # write correct PTENxx table
23395        bcc.b           not_rp                  # to a1
23396        lea.l           PTENRP(%pc),%a1         # it is RP
23397        bra.b           calc_p                  # go to init section
23398not_rp:
23399        asr.l           &1,%d0                  # keep checking
23400        bcc.b           not_rm
23401        lea.l           PTENRM(%pc),%a1         # it is RM
23402        bra.b           calc_p                  # go to init section
23403not_rm:
23404        lea.l           PTENRN(%pc),%a1         # it is RN
23405calc_p:
23406        mov.l           %d1,%d0                 # copy exp to d0;use d0
23407        bpl.b           no_neg                  # if exp is negative,
23408        neg.l           %d0                     # invert it
23409        or.l            &0x40000000,(%a0)       # and set SE bit
23410no_neg:
23411        clr.l           %d3                     # table index
23412        fmov.s          &0x3f800000,%fp1        # init fp1 to 1
23413e_loop:
23414        asr.l           &1,%d0                  # shift next bit into carry
23415        bcc.b           e_next                  # if zero, skip the mul
23416        fmul.x          (%a1,%d3),%fp1          # mul by 10**(d3_bit_no)
23417e_next:
23418        add.l           &12,%d3                 # inc d3 to next rtable entry
23419        tst.l           %d0                     # check if d0 is zero
23420        bne.b           e_loop                  # not zero, continue shifting
23421#
23422#
23423#  Check the sign of the adjusted exp and make the value in fp0 the
23424#  same sign. If the exp was pos then multiply fp1*fp0;
23425#  else divide fp0/fp1.
23426#
23427# Register Usage:
23428#  norm:
23429#       ( )  a0: pointer to working bcd value
23430#       (*) fp0: mantissa accumulator
23431#       ( ) fp1: scaling factor - 10**(abs(exp))
23432#
23433pnorm:
23434        btst            &30,(%a0)               # test the sign of the exponent
23435        beq.b           mul                     # if clear, go to multiply
23436div:
23437        fdiv.x          %fp1,%fp0               # exp is negative, so divide mant by exp
23438        bra.b           end_dec
23439mul:
23440        fmul.x          %fp1,%fp0               # exp is positive, so multiply by exp
23441#
23442#
23443# Clean up and return with result in fp0.
23444#
23445# If the final mul/div in decbin incurred an inex exception,
23446# it will be inex2, but will be reported as inex1 by get_op.
23447#
23448end_dec:
23449        fmov.l          %fpsr,%d0               # get status register
23450        bclr            &inex2_bit+8,%d0        # test for inex2 and clear it
23451        beq.b           no_exc                  # skip this if no exc
23452        ori.w           &inx1a_mask,2+USER_FPSR(%a6) # set INEX1/AINEX
23453no_exc:
23454        add.l           &0x4,%sp                # clear 1 lw param
23455        fmovm.x         (%sp)+,&0x40            # restore fp1
23456        movm.l          (%sp)+,&0x3c            # restore d2-d5
23457        fmov.l          &0x0,%fpcr
23458        fmov.l          &0x0,%fpsr
23459        rts
23460
23461#########################################################################
23462# bindec(): Converts an input in extended precision format to bcd format#
23463#                                                                       #
23464# INPUT *************************************************************** #
23465#       a0 = pointer to the input extended precision value in memory.   #
23466#            the input may be either normalized, unnormalized, or       #
23467#            denormalized.                                              #
23468#       d0 = contains the k-factor sign-extended to 32-bits.            #
23469#                                                                       #
23470# OUTPUT ************************************************************** #
23471#       FP_SCR0(a6) = bcd format result on the stack.                   #
23472#                                                                       #
23473# ALGORITHM *********************************************************** #
23474#                                                                       #
23475#       A1.     Set RM and size ext;  Set SIGMA = sign of input.        #
23476#               The k-factor is saved for use in d7. Clear the          #
23477#               BINDEC_FLG for separating normalized/denormalized       #
23478#               input.  If input is unnormalized or denormalized,       #
23479#               normalize it.                                           #
23480#                                                                       #
23481#       A2.     Set X = abs(input).                                     #
23482#                                                                       #
23483#       A3.     Compute ILOG.                                           #
23484#               ILOG is the log base 10 of the input value.  It is      #
23485#               approximated by adding e + 0.f when the original        #
23486#               value is viewed as 2^^e * 1.f in extended precision.    #
23487#               This value is stored in d6.                             #
23488#                                                                       #
23489#       A4.     Clr INEX bit.                                           #
23490#               The operation in A3 above may have set INEX2.           #
23491#                                                                       #
23492#       A5.     Set ICTR = 0;                                           #
23493#               ICTR is a flag used in A13.  It must be set before the  #
23494#               loop entry A6.                                          #
23495#                                                                       #
23496#       A6.     Calculate LEN.                                          #
23497#               LEN is the number of digits to be displayed.  The       #
23498#               k-factor can dictate either the total number of digits, #
23499#               if it is a positive number, or the number of digits     #
23500#               after the decimal point which are to be included as     #
23501#               significant.  See the 68882 manual for examples.        #
23502#               If LEN is computed to be greater than 17, set OPERR in  #
23503#               USER_FPSR.  LEN is stored in d4.                        #
23504#                                                                       #
23505#       A7.     Calculate SCALE.                                        #
23506#               SCALE is equal to 10^ISCALE, where ISCALE is the number #
23507#               of decimal places needed to insure LEN integer digits   #
23508#               in the output before conversion to bcd. LAMBDA is the   #
23509#               sign of ISCALE, used in A9. Fp1 contains                #
23510#               10^^(abs(ISCALE)) using a rounding mode which is a      #
23511#               function of the original rounding mode and the signs    #
23512#               of ISCALE and X.  A table is given in the code.         #
23513#                                                                       #
23514#       A8.     Clr INEX; Force RZ.                                     #
23515#               The operation in A3 above may have set INEX2.           #
23516#               RZ mode is forced for the scaling operation to insure   #
23517#               only one rounding error.  The grs bits are collected in #
23518#               the INEX flag for use in A10.                           #
23519#                                                                       #
23520#       A9.     Scale X -> Y.                                           #
23521#               The mantissa is scaled to the desired number of         #
23522#               significant digits.  The excess digits are collected    #
23523#               in INEX2.                                               #
23524#                                                                       #
23525#       A10.    Or in INEX.                                             #
23526#               If INEX is set, round error occurred.  This is          #
23527#               compensated for by 'or-ing' in the INEX2 flag to        #
23528#               the lsb of Y.                                           #
23529#                                                                       #
23530#       A11.    Restore original FPCR; set size ext.                    #
23531#               Perform FINT operation in the user's rounding mode.     #
23532#               Keep the size to extended.                              #
23533#                                                                       #
23534#       A12.    Calculate YINT = FINT(Y) according to user's rounding   #
23535#               mode.  The FPSP routine sintd0 is used.  The output     #
23536#               is in fp0.                                              #
23537#                                                                       #
23538#       A13.    Check for LEN digits.                                   #
23539#               If the int operation results in more than LEN digits,   #
23540#               or less than LEN -1 digits, adjust ILOG and repeat from #
23541#               A6.  This test occurs only on the first pass.  If the   #
23542#               result is exactly 10^LEN, decrement ILOG and divide     #
23543#               the mantissa by 10.                                     #
23544#                                                                       #
23545#       A14.    Convert the mantissa to bcd.                            #
23546#               The binstr routine is used to convert the LEN digit     #
23547#               mantissa to bcd in memory.  The input to binstr is      #
23548#               to be a fraction; i.e. (mantissa)/10^LEN and adjusted   #
23549#               such that the decimal point is to the left of bit 63.   #
23550#               The bcd digits are stored in the correct position in    #
23551#               the final string area in memory.                        #
23552#                                                                       #
23553#       A15.    Convert the exponent to bcd.                            #
23554#               As in A14 above, the exp is converted to bcd and the    #
23555#               digits are stored in the final string.                  #
23556#               Test the length of the final exponent string.  If the   #
23557#               length is 4, set operr.                                 #
23558#                                                                       #
23559#       A16.    Write sign bits to final string.                        #
23560#                                                                       #
23561#########################################################################
23562
23563set     BINDEC_FLG,     EXC_TEMP        # DENORM flag
23564
23565# Constants in extended precision
23566PLOG2:
23567        long            0x3FFD0000,0x9A209A84,0xFBCFF798,0x00000000
23568PLOG2UP1:
23569        long            0x3FFD0000,0x9A209A84,0xFBCFF799,0x00000000
23570
23571# Constants in single precision
23572FONE:
23573        long            0x3F800000,0x00000000,0x00000000,0x00000000
23574FTWO:
23575        long            0x40000000,0x00000000,0x00000000,0x00000000
23576FTEN:
23577        long            0x41200000,0x00000000,0x00000000,0x00000000
23578F4933:
23579        long            0x459A2800,0x00000000,0x00000000,0x00000000
23580
23581RBDTBL:
23582        byte            0,0,0,0
23583        byte            3,3,2,2
23584        byte            3,2,2,3
23585        byte            2,3,3,2
23586
23587#       Implementation Notes:
23588#
23589#       The registers are used as follows:
23590#
23591#               d0: scratch; LEN input to binstr
23592#               d1: scratch
23593#               d2: upper 32-bits of mantissa for binstr
23594#               d3: scratch;lower 32-bits of mantissa for binstr
23595#               d4: LEN
23596#               d5: LAMBDA/ICTR
23597#               d6: ILOG
23598#               d7: k-factor
23599#               a0: ptr for original operand/final result
23600#               a1: scratch pointer
23601#               a2: pointer to FP_X; abs(original value) in ext
23602#               fp0: scratch
23603#               fp1: scratch
23604#               fp2: scratch
23605#               F_SCR1:
23606#               F_SCR2:
23607#               L_SCR1:
23608#               L_SCR2:
23609
23610        global          bindec
23611bindec:
23612        movm.l          &0x3f20,-(%sp)  #  {%d2-%d7/%a2}
23613        fmovm.x         &0x7,-(%sp)     #  {%fp0-%fp2}
23614
23615# A1. Set RM and size ext. Set SIGMA = sign input;
23616#     The k-factor is saved for use in d7.  Clear BINDEC_FLG for
23617#     separating  normalized/denormalized input.  If the input
23618#     is a denormalized number, set the BINDEC_FLG memory word
23619#     to signal denorm.  If the input is unnormalized, normalize
23620#     the input and test for denormalized result.
23621#
23622        fmov.l          &rm_mode*0x10,%fpcr     # set RM and ext
23623        mov.l           (%a0),L_SCR2(%a6)       # save exponent for sign check
23624        mov.l           %d0,%d7         # move k-factor to d7
23625
23626        clr.b           BINDEC_FLG(%a6) # clr norm/denorm flag
23627        cmpi.b          STAG(%a6),&DENORM # is input a DENORM?
23628        bne.w           A2_str          # no; input is a NORM
23629
23630#
23631# Normalize the denorm
23632#
23633un_de_norm:
23634        mov.w           (%a0),%d0
23635        and.w           &0x7fff,%d0     # strip sign of normalized exp
23636        mov.l           4(%a0),%d1
23637        mov.l           8(%a0),%d2
23638norm_loop:
23639        sub.w           &1,%d0
23640        lsl.l           &1,%d2
23641        roxl.l          &1,%d1
23642        tst.l           %d1
23643        bge.b           norm_loop
23644#
23645# Test if the normalized input is denormalized
23646#
23647        tst.w           %d0
23648        bgt.b           pos_exp         # if greater than zero, it is a norm
23649        st              BINDEC_FLG(%a6) # set flag for denorm
23650pos_exp:
23651        and.w           &0x7fff,%d0     # strip sign of normalized exp
23652        mov.w           %d0,(%a0)
23653        mov.l           %d1,4(%a0)
23654        mov.l           %d2,8(%a0)
23655
23656# A2. Set X = abs(input).
23657#
23658A2_str:
23659        mov.l           (%a0),FP_SCR1(%a6)      # move input to work space
23660        mov.l           4(%a0),FP_SCR1+4(%a6)   # move input to work space
23661        mov.l           8(%a0),FP_SCR1+8(%a6)   # move input to work space
23662        and.l           &0x7fffffff,FP_SCR1(%a6)        # create abs(X)
23663
23664# A3. Compute ILOG.
23665#     ILOG is the log base 10 of the input value.  It is approx-
23666#     imated by adding e + 0.f when the original value is viewed
23667#     as 2^^e * 1.f in extended precision.  This value is stored
23668#     in d6.
23669#
23670# Register usage:
23671#       Input/Output
23672#       d0: k-factor/exponent
23673#       d2: x/x
23674#       d3: x/x
23675#       d4: x/x
23676#       d5: x/x
23677#       d6: x/ILOG
23678#       d7: k-factor/Unchanged
23679#       a0: ptr for original operand/final result
23680#       a1: x/x
23681#       a2: x/x
23682#       fp0: x/float(ILOG)
23683#       fp1: x/x
23684#       fp2: x/x
23685#       F_SCR1:x/x
23686#       F_SCR2:Abs(X)/Abs(X) with $3fff exponent
23687#       L_SCR1:x/x
23688#       L_SCR2:first word of X packed/Unchanged
23689
23690        tst.b           BINDEC_FLG(%a6) # check for denorm
23691        beq.b           A3_cont         # if clr, continue with norm
23692        mov.l           &-4933,%d6      # force ILOG = -4933
23693        bra.b           A4_str
23694A3_cont:
23695        mov.w           FP_SCR1(%a6),%d0        # move exp to d0
23696        mov.w           &0x3fff,FP_SCR1(%a6)    # replace exponent with 0x3fff
23697        fmov.x          FP_SCR1(%a6),%fp0       # now fp0 has 1.f
23698        sub.w           &0x3fff,%d0     # strip off bias
23699        fadd.w          %d0,%fp0        # add in exp
23700        fsub.s          FONE(%pc),%fp0  # subtract off 1.0
23701        fbge.w          pos_res         # if pos, branch
23702        fmul.x          PLOG2UP1(%pc),%fp0      # if neg, mul by LOG2UP1
23703        fmov.l          %fp0,%d6        # put ILOG in d6 as a lword
23704        bra.b           A4_str          # go move out ILOG
23705pos_res:
23706        fmul.x          PLOG2(%pc),%fp0 # if pos, mul by LOG2
23707        fmov.l          %fp0,%d6        # put ILOG in d6 as a lword
23708
23709
23710# A4. Clr INEX bit.
23711#     The operation in A3 above may have set INEX2.
23712
23713A4_str:
23714        fmov.l          &0,%fpsr        # zero all of fpsr - nothing needed
23715
23716
23717# A5. Set ICTR = 0;
23718#     ICTR is a flag used in A13.  It must be set before the
23719#     loop entry A6. The lower word of d5 is used for ICTR.
23720
23721        clr.w           %d5             # clear ICTR
23722
23723# A6. Calculate LEN.
23724#     LEN is the number of digits to be displayed.  The k-factor
23725#     can dictate either the total number of digits, if it is
23726#     a positive number, or the number of digits after the
23727#     original decimal point which are to be included as
23728#     significant.  See the 68882 manual for examples.
23729#     If LEN is computed to be greater than 17, set OPERR in
23730#     USER_FPSR.  LEN is stored in d4.
23731#
23732# Register usage:
23733#       Input/Output
23734#       d0: exponent/Unchanged
23735#       d2: x/x/scratch
23736#       d3: x/x
23737#       d4: exc picture/LEN
23738#       d5: ICTR/Unchanged
23739#       d6: ILOG/Unchanged
23740#       d7: k-factor/Unchanged
23741#       a0: ptr for original operand/final result
23742#       a1: x/x
23743#       a2: x/x
23744#       fp0: float(ILOG)/Unchanged
23745#       fp1: x/x
23746#       fp2: x/x
23747#       F_SCR1:x/x
23748#       F_SCR2:Abs(X) with $3fff exponent/Unchanged
23749#       L_SCR1:x/x
23750#       L_SCR2:first word of X packed/Unchanged
23751
23752A6_str:
23753        tst.l           %d7             # branch on sign of k
23754        ble.b           k_neg           # if k <= 0, LEN = ILOG + 1 - k
23755        mov.l           %d7,%d4         # if k > 0, LEN = k
23756        bra.b           len_ck          # skip to LEN check
23757k_neg:
23758        mov.l           %d6,%d4         # first load ILOG to d4
23759        sub.l           %d7,%d4         # subtract off k
23760        addq.l          &1,%d4          # add in the 1
23761len_ck:
23762        tst.l           %d4             # LEN check: branch on sign of LEN
23763        ble.b           LEN_ng          # if neg, set LEN = 1
23764        cmp.l           %d4,&17         # test if LEN > 17
23765        ble.b           A7_str          # if not, forget it
23766        mov.l           &17,%d4         # set max LEN = 17
23767        tst.l           %d7             # if negative, never set OPERR
23768        ble.b           A7_str          # if positive, continue
23769        or.l            &opaop_mask,USER_FPSR(%a6)      # set OPERR & AIOP in USER_FPSR
23770        bra.b           A7_str          # finished here
23771LEN_ng:
23772        mov.l           &1,%d4          # min LEN is 1
23773
23774
23775# A7. Calculate SCALE.
23776#     SCALE is equal to 10^ISCALE, where ISCALE is the number
23777#     of decimal places needed to insure LEN integer digits
23778#     in the output before conversion to bcd. LAMBDA is the sign
23779#     of ISCALE, used in A9.  Fp1 contains 10^^(abs(ISCALE)) using
23780#     the rounding mode as given in the following table (see
23781#     Coonen, p. 7.23 as ref.; however, the SCALE variable is
23782#     of opposite sign in bindec.sa from Coonen).
23783#
23784#       Initial                                 USE
23785#       FPCR[6:5]       LAMBDA  SIGN(X)         FPCR[6:5]
23786#       ----------------------------------------------
23787#        RN     00         0       0            00/0    RN
23788#        RN     00         0       1            00/0    RN
23789#        RN     00         1       0            00/0    RN
23790#        RN     00         1       1            00/0    RN
23791#        RZ     01         0       0            11/3    RP
23792#        RZ     01         0       1            11/3    RP
23793#        RZ     01         1       0            10/2    RM
23794#        RZ     01         1       1            10/2    RM
23795#        RM     10         0       0            11/3    RP
23796#        RM     10         0       1            10/2    RM
23797#        RM     10         1       0            10/2    RM
23798#        RM     10         1       1            11/3    RP
23799#        RP     11         0       0            10/2    RM
23800#        RP     11         0       1            11/3    RP
23801#        RP     11         1       0            11/3    RP
23802#        RP     11         1       1            10/2    RM
23803#
23804# Register usage:
23805#       Input/Output
23806#       d0: exponent/scratch - final is 0
23807#       d2: x/0 or 24 for A9
23808#       d3: x/scratch - offset ptr into PTENRM array
23809#       d4: LEN/Unchanged
23810#       d5: 0/ICTR:LAMBDA
23811#       d6: ILOG/ILOG or k if ((k<=0)&(ILOG<k))
23812#       d7: k-factor/Unchanged
23813#       a0: ptr for original operand/final result
23814#       a1: x/ptr to PTENRM array
23815#       a2: x/x
23816#       fp0: float(ILOG)/Unchanged
23817#       fp1: x/10^ISCALE
23818#       fp2: x/x
23819#       F_SCR1:x/x
23820#       F_SCR2:Abs(X) with $3fff exponent/Unchanged
23821#       L_SCR1:x/x
23822#       L_SCR2:first word of X packed/Unchanged
23823
23824A7_str:
23825        tst.l           %d7             # test sign of k
23826        bgt.b           k_pos           # if pos and > 0, skip this
23827        cmp.l           %d7,%d6         # test k - ILOG
23828        blt.b           k_pos           # if ILOG >= k, skip this
23829        mov.l           %d7,%d6         # if ((k<0) & (ILOG < k)) ILOG = k
23830k_pos:
23831        mov.l           %d6,%d0         # calc ILOG + 1 - LEN in d0
23832        addq.l          &1,%d0          # add the 1
23833        sub.l           %d4,%d0         # sub off LEN
23834        swap            %d5             # use upper word of d5 for LAMBDA
23835        clr.w           %d5             # set it zero initially
23836        clr.w           %d2             # set up d2 for very small case
23837        tst.l           %d0             # test sign of ISCALE
23838        bge.b           iscale          # if pos, skip next inst
23839        addq.w          &1,%d5          # if neg, set LAMBDA true
23840        cmp.l           %d0,&0xffffecd4 # test iscale <= -4908
23841        bgt.b           no_inf          # if false, skip rest
23842        add.l           &24,%d0         # add in 24 to iscale
23843        mov.l           &24,%d2         # put 24 in d2 for A9
23844no_inf:
23845        neg.l           %d0             # and take abs of ISCALE
23846iscale:
23847        fmov.s          FONE(%pc),%fp1  # init fp1 to 1
23848        bfextu          USER_FPCR(%a6){&26:&2},%d1      # get initial rmode bits
23849        lsl.w           &1,%d1          # put them in bits 2:1
23850        add.w           %d5,%d1         # add in LAMBDA
23851        lsl.w           &1,%d1          # put them in bits 3:1
23852        tst.l           L_SCR2(%a6)     # test sign of original x
23853        bge.b           x_pos           # if pos, don't set bit 0
23854        addq.l          &1,%d1          # if neg, set bit 0
23855x_pos:
23856        lea.l           RBDTBL(%pc),%a2 # load rbdtbl base
23857        mov.b           (%a2,%d1),%d3   # load d3 with new rmode
23858        lsl.l           &4,%d3          # put bits in proper position
23859        fmov.l          %d3,%fpcr       # load bits into fpu
23860        lsr.l           &4,%d3          # put bits in proper position
23861        tst.b           %d3             # decode new rmode for pten table
23862        bne.b           not_rn          # if zero, it is RN
23863        lea.l           PTENRN(%pc),%a1 # load a1 with RN table base
23864        bra.b           rmode           # exit decode
23865not_rn:
23866        lsr.b           &1,%d3          # get lsb in carry
23867        bcc.b           not_rp2         # if carry clear, it is RM
23868        lea.l           PTENRP(%pc),%a1 # load a1 with RP table base
23869        bra.b           rmode           # exit decode
23870not_rp2:
23871        lea.l           PTENRM(%pc),%a1 # load a1 with RM table base
23872rmode:
23873        clr.l           %d3             # clr table index
23874e_loop2:
23875        lsr.l           &1,%d0          # shift next bit into carry
23876        bcc.b           e_next2         # if zero, skip the mul
23877        fmul.x          (%a1,%d3),%fp1  # mul by 10**(d3_bit_no)
23878e_next2:
23879        add.l           &12,%d3         # inc d3 to next pwrten table entry
23880        tst.l           %d0             # test if ISCALE is zero
23881        bne.b           e_loop2         # if not, loop
23882
23883# A8. Clr INEX; Force RZ.
23884#     The operation in A3 above may have set INEX2.
23885#     RZ mode is forced for the scaling operation to insure
23886#     only one rounding error.  The grs bits are collected in
23887#     the INEX flag for use in A10.
23888#
23889# Register usage:
23890#       Input/Output
23891
23892        fmov.l          &0,%fpsr        # clr INEX
23893        fmov.l          &rz_mode*0x10,%fpcr     # set RZ rounding mode
23894
23895# A9. Scale X -> Y.
23896#     The mantissa is scaled to the desired number of significant
23897#     digits.  The excess digits are collected in INEX2. If mul,
23898#     Check d2 for excess 10 exponential value.  If not zero,
23899#     the iscale value would have caused the pwrten calculation
23900#     to overflow.  Only a negative iscale can cause this, so
23901#     multiply by 10^(d2), which is now only allowed to be 24,
23902#     with a multiply by 10^8 and 10^16, which is exact since
23903#     10^24 is exact.  If the input was denormalized, we must
23904#     create a busy stack frame with the mul command and the
23905#     two operands, and allow the fpu to complete the multiply.
23906#
23907# Register usage:
23908#       Input/Output
23909#       d0: FPCR with RZ mode/Unchanged
23910#       d2: 0 or 24/unchanged
23911#       d3: x/x
23912#       d4: LEN/Unchanged
23913#       d5: ICTR:LAMBDA
23914#       d6: ILOG/Unchanged
23915#       d7: k-factor/Unchanged
23916#       a0: ptr for original operand/final result
23917#       a1: ptr to PTENRM array/Unchanged
23918#       a2: x/x
23919#       fp0: float(ILOG)/X adjusted for SCALE (Y)
23920#       fp1: 10^ISCALE/Unchanged
23921#       fp2: x/x
23922#       F_SCR1:x/x
23923#       F_SCR2:Abs(X) with $3fff exponent/Unchanged
23924#       L_SCR1:x/x
23925#       L_SCR2:first word of X packed/Unchanged
23926
23927A9_str:
23928        fmov.x          (%a0),%fp0      # load X from memory
23929        fabs.x          %fp0            # use abs(X)
23930        tst.w           %d5             # LAMBDA is in lower word of d5
23931        bne.b           sc_mul          # if neg (LAMBDA = 1), scale by mul
23932        fdiv.x          %fp1,%fp0       # calculate X / SCALE -> Y to fp0
23933        bra.w           A10_st          # branch to A10
23934
23935sc_mul:
23936        tst.b           BINDEC_FLG(%a6) # check for denorm
23937        beq.w           A9_norm         # if norm, continue with mul
23938
23939# for DENORM, we must calculate:
23940#       fp0 = input_op * 10^ISCALE * 10^24
23941# since the input operand is a DENORM, we can't multiply it directly.
23942# so, we do the multiplication of the exponents and mantissas separately.
23943# in this way, we avoid underflow on intermediate stages of the
23944# multiplication and guarantee a result without exception.
23945        fmovm.x         &0x2,-(%sp)     # save 10^ISCALE to stack
23946
23947        mov.w           (%sp),%d3       # grab exponent
23948        andi.w          &0x7fff,%d3     # clear sign
23949        ori.w           &0x8000,(%a0)   # make DENORM exp negative
23950        add.w           (%a0),%d3       # add DENORM exp to 10^ISCALE exp
23951        subi.w          &0x3fff,%d3     # subtract BIAS
23952        add.w           36(%a1),%d3
23953        subi.w          &0x3fff,%d3     # subtract BIAS
23954        add.w           48(%a1),%d3
23955        subi.w          &0x3fff,%d3     # subtract BIAS
23956
23957        bmi.w           sc_mul_err      # is result is DENORM, punt!!!
23958
23959        andi.w          &0x8000,(%sp)   # keep sign
23960        or.w            %d3,(%sp)       # insert new exponent
23961        andi.w          &0x7fff,(%a0)   # clear sign bit on DENORM again
23962        mov.l           0x8(%a0),-(%sp) # put input op mantissa on stk
23963        mov.l           0x4(%a0),-(%sp)
23964        mov.l           &0x3fff0000,-(%sp) # force exp to zero
23965        fmovm.x         (%sp)+,&0x80    # load normalized DENORM into fp0
23966        fmul.x          (%sp)+,%fp0
23967
23968#       fmul.x  36(%a1),%fp0    # multiply fp0 by 10^8
23969#       fmul.x  48(%a1),%fp0    # multiply fp0 by 10^16
23970        mov.l           36+8(%a1),-(%sp) # get 10^8 mantissa
23971        mov.l           36+4(%a1),-(%sp)
23972        mov.l           &0x3fff0000,-(%sp) # force exp to zero
23973        mov.l           48+8(%a1),-(%sp) # get 10^16 mantissa
23974        mov.l           48+4(%a1),-(%sp)
23975        mov.l           &0x3fff0000,-(%sp)# force exp to zero
23976        fmul.x          (%sp)+,%fp0     # multiply fp0 by 10^8
23977        fmul.x          (%sp)+,%fp0     # multiply fp0 by 10^16
23978        bra.b           A10_st
23979
23980sc_mul_err:
23981        bra.b           sc_mul_err
23982
23983A9_norm:
23984        tst.w           %d2             # test for small exp case
23985        beq.b           A9_con          # if zero, continue as normal
23986        fmul.x          36(%a1),%fp0    # multiply fp0 by 10^8
23987        fmul.x          48(%a1),%fp0    # multiply fp0 by 10^16
23988A9_con:
23989        fmul.x          %fp1,%fp0       # calculate X * SCALE -> Y to fp0
23990
23991# A10. Or in INEX.
23992#      If INEX is set, round error occurred.  This is compensated
23993#      for by 'or-ing' in the INEX2 flag to the lsb of Y.
23994#
23995# Register usage:
23996#       Input/Output
23997#       d0: FPCR with RZ mode/FPSR with INEX2 isolated
23998#       d2: x/x
23999#       d3: x/x
24000#       d4: LEN/Unchanged
24001#       d5: ICTR:LAMBDA
24002#       d6: ILOG/Unchanged
24003#       d7: k-factor/Unchanged
24004#       a0: ptr for original operand/final result
24005#       a1: ptr to PTENxx array/Unchanged
24006#       a2: x/ptr to FP_SCR1(a6)
24007#       fp0: Y/Y with lsb adjusted
24008#       fp1: 10^ISCALE/Unchanged
24009#       fp2: x/x
24010
24011A10_st:
24012        fmov.l          %fpsr,%d0       # get FPSR
24013        fmov.x          %fp0,FP_SCR1(%a6)       # move Y to memory
24014        lea.l           FP_SCR1(%a6),%a2        # load a2 with ptr to FP_SCR1
24015        btst            &9,%d0          # check if INEX2 set
24016        beq.b           A11_st          # if clear, skip rest
24017        or.l            &1,8(%a2)       # or in 1 to lsb of mantissa
24018        fmov.x          FP_SCR1(%a6),%fp0       # write adjusted Y back to fpu
24019
24020
24021# A11. Restore original FPCR; set size ext.
24022#      Perform FINT operation in the user's rounding mode.  Keep
24023#      the size to extended.  The sintdo entry point in the sint
24024#      routine expects the FPCR value to be in USER_FPCR for
24025#      mode and precision.  The original FPCR is saved in L_SCR1.
24026
24027A11_st:
24028        mov.l           USER_FPCR(%a6),L_SCR1(%a6)      # save it for later
24029        and.l           &0x00000030,USER_FPCR(%a6)      # set size to ext,
24030#                                       ;block exceptions
24031
24032
24033# A12. Calculate YINT = FINT(Y) according to user's rounding mode.
24034#      The FPSP routine sintd0 is used.  The output is in fp0.
24035#
24036# Register usage:
24037#       Input/Output
24038#       d0: FPSR with AINEX cleared/FPCR with size set to ext
24039#       d2: x/x/scratch
24040#       d3: x/x
24041#       d4: LEN/Unchanged
24042#       d5: ICTR:LAMBDA/Unchanged
24043#       d6: ILOG/Unchanged
24044#       d7: k-factor/Unchanged
24045#       a0: ptr for original operand/src ptr for sintdo
24046#       a1: ptr to PTENxx array/Unchanged
24047#       a2: ptr to FP_SCR1(a6)/Unchanged
24048#       a6: temp pointer to FP_SCR1(a6) - orig value saved and restored
24049#       fp0: Y/YINT
24050#       fp1: 10^ISCALE/Unchanged
24051#       fp2: x/x
24052#       F_SCR1:x/x
24053#       F_SCR2:Y adjusted for inex/Y with original exponent
24054#       L_SCR1:x/original USER_FPCR
24055#       L_SCR2:first word of X packed/Unchanged
24056
24057A12_st:
24058        movm.l  &0xc0c0,-(%sp)  # save regs used by sintd0       {%d0-%d1/%a0-%a1}
24059        mov.l   L_SCR1(%a6),-(%sp)
24060        mov.l   L_SCR2(%a6),-(%sp)
24061
24062        lea.l           FP_SCR1(%a6),%a0        # a0 is ptr to FP_SCR1(a6)
24063        fmov.x          %fp0,(%a0)      # move Y to memory at FP_SCR1(a6)
24064        tst.l           L_SCR2(%a6)     # test sign of original operand
24065        bge.b           do_fint12               # if pos, use Y
24066        or.l            &0x80000000,(%a0)       # if neg, use -Y
24067do_fint12:
24068        mov.l   USER_FPSR(%a6),-(%sp)
24069#       bsr     sintdo          # sint routine returns int in fp0
24070
24071        fmov.l  USER_FPCR(%a6),%fpcr
24072        fmov.l  &0x0,%fpsr                      # clear the AEXC bits!!!
24073##      mov.l           USER_FPCR(%a6),%d0      # ext prec/keep rnd mode
24074##      andi.l          &0x00000030,%d0
24075##      fmov.l          %d0,%fpcr
24076        fint.x          FP_SCR1(%a6),%fp0       # do fint()
24077        fmov.l  %fpsr,%d0
24078        or.w    %d0,FPSR_EXCEPT(%a6)
24079##      fmov.l          &0x0,%fpcr
24080##      fmov.l          %fpsr,%d0               # don't keep ccodes
24081##      or.w            %d0,FPSR_EXCEPT(%a6)
24082
24083        mov.b   (%sp),USER_FPSR(%a6)
24084        add.l   &4,%sp
24085
24086        mov.l   (%sp)+,L_SCR2(%a6)
24087        mov.l   (%sp)+,L_SCR1(%a6)
24088        movm.l  (%sp)+,&0x303   # restore regs used by sint      {%d0-%d1/%a0-%a1}
24089
24090        mov.l   L_SCR2(%a6),FP_SCR1(%a6)        # restore original exponent
24091        mov.l   L_SCR1(%a6),USER_FPCR(%a6)      # restore user's FPCR
24092
24093# A13. Check for LEN digits.
24094#      If the int operation results in more than LEN digits,
24095#      or less than LEN -1 digits, adjust ILOG and repeat from
24096#      A6.  This test occurs only on the first pass.  If the
24097#      result is exactly 10^LEN, decrement ILOG and divide
24098#      the mantissa by 10.  The calculation of 10^LEN cannot
24099#      be inexact, since all powers of ten up to 10^27 are exact
24100#      in extended precision, so the use of a previous power-of-ten
24101#      table will introduce no error.
24102#
24103#
24104# Register usage:
24105#       Input/Output
24106#       d0: FPCR with size set to ext/scratch final = 0
24107#       d2: x/x
24108#       d3: x/scratch final = x
24109#       d4: LEN/LEN adjusted
24110#       d5: ICTR:LAMBDA/LAMBDA:ICTR
24111#       d6: ILOG/ILOG adjusted
24112#       d7: k-factor/Unchanged
24113#       a0: pointer into memory for packed bcd string formation
24114#       a1: ptr to PTENxx array/Unchanged
24115#       a2: ptr to FP_SCR1(a6)/Unchanged
24116#       fp0: int portion of Y/abs(YINT) adjusted
24117#       fp1: 10^ISCALE/Unchanged
24118#       fp2: x/10^LEN
24119#       F_SCR1:x/x
24120#       F_SCR2:Y with original exponent/Unchanged
24121#       L_SCR1:original USER_FPCR/Unchanged
24122#       L_SCR2:first word of X packed/Unchanged
24123
24124A13_st:
24125        swap            %d5             # put ICTR in lower word of d5
24126        tst.w           %d5             # check if ICTR = 0
24127        bne             not_zr          # if non-zero, go to second test
24128#
24129# Compute 10^(LEN-1)
24130#
24131        fmov.s          FONE(%pc),%fp2  # init fp2 to 1.0
24132        mov.l           %d4,%d0         # put LEN in d0
24133        subq.l          &1,%d0          # d0 = LEN -1
24134        clr.l           %d3             # clr table index
24135l_loop:
24136        lsr.l           &1,%d0          # shift next bit into carry
24137        bcc.b           l_next          # if zero, skip the mul
24138        fmul.x          (%a1,%d3),%fp2  # mul by 10**(d3_bit_no)
24139l_next:
24140        add.l           &12,%d3         # inc d3 to next pwrten table entry
24141        tst.l           %d0             # test if LEN is zero
24142        bne.b           l_loop          # if not, loop
24143#
24144# 10^LEN-1 is computed for this test and A14.  If the input was
24145# denormalized, check only the case in which YINT > 10^LEN.
24146#
24147        tst.b           BINDEC_FLG(%a6) # check if input was norm
24148        beq.b           A13_con         # if norm, continue with checking
24149        fabs.x          %fp0            # take abs of YINT
24150        bra             test_2
24151#
24152# Compare abs(YINT) to 10^(LEN-1) and 10^LEN
24153#
24154A13_con:
24155        fabs.x          %fp0            # take abs of YINT
24156        fcmp.x          %fp0,%fp2       # compare abs(YINT) with 10^(LEN-1)
24157        fbge.w          test_2          # if greater, do next test
24158        subq.l          &1,%d6          # subtract 1 from ILOG
24159        mov.w           &1,%d5          # set ICTR
24160        fmov.l          &rm_mode*0x10,%fpcr     # set rmode to RM
24161        fmul.s          FTEN(%pc),%fp2  # compute 10^LEN
24162        bra.w           A6_str          # return to A6 and recompute YINT
24163test_2:
24164        fmul.s          FTEN(%pc),%fp2  # compute 10^LEN
24165        fcmp.x          %fp0,%fp2       # compare abs(YINT) with 10^LEN
24166        fblt.w          A14_st          # if less, all is ok, go to A14
24167        fbgt.w          fix_ex          # if greater, fix and redo
24168        fdiv.s          FTEN(%pc),%fp0  # if equal, divide by 10
24169        addq.l          &1,%d6          # and inc ILOG
24170        bra.b           A14_st          # and continue elsewhere
24171fix_ex:
24172        addq.l          &1,%d6          # increment ILOG by 1
24173        mov.w           &1,%d5          # set ICTR
24174        fmov.l          &rm_mode*0x10,%fpcr     # set rmode to RM
24175        bra.w           A6_str          # return to A6 and recompute YINT
24176#
24177# Since ICTR <> 0, we have already been through one adjustment,
24178# and shouldn't have another; this is to check if abs(YINT) = 10^LEN
24179# 10^LEN is again computed using whatever table is in a1 since the
24180# value calculated cannot be inexact.
24181#
24182not_zr:
24183        fmov.s          FONE(%pc),%fp2  # init fp2 to 1.0
24184        mov.l           %d4,%d0         # put LEN in d0
24185        clr.l           %d3             # clr table index
24186z_loop:
24187        lsr.l           &1,%d0          # shift next bit into carry
24188        bcc.b           z_next          # if zero, skip the mul
24189        fmul.x          (%a1,%d3),%fp2  # mul by 10**(d3_bit_no)
24190z_next:
24191        add.l           &12,%d3         # inc d3 to next pwrten table entry
24192        tst.l           %d0             # test if LEN is zero
24193        bne.b           z_loop          # if not, loop
24194        fabs.x          %fp0            # get abs(YINT)
24195        fcmp.x          %fp0,%fp2       # check if abs(YINT) = 10^LEN
24196        fbneq.w         A14_st          # if not, skip this
24197        fdiv.s          FTEN(%pc),%fp0  # divide abs(YINT) by 10
24198        addq.l          &1,%d6          # and inc ILOG by 1
24199        addq.l          &1,%d4          # and inc LEN
24200        fmul.s          FTEN(%pc),%fp2  # if LEN++, the get 10^^LEN
24201
24202# A14. Convert the mantissa to bcd.
24203#      The binstr routine is used to convert the LEN digit
24204#      mantissa to bcd in memory.  The input to binstr is
24205#      to be a fraction; i.e. (mantissa)/10^LEN and adjusted
24206#      such that the decimal point is to the left of bit 63.
24207#      The bcd digits are stored in the correct position in
24208#      the final string area in memory.
24209#
24210#
24211# Register usage:
24212#       Input/Output
24213#       d0: x/LEN call to binstr - final is 0
24214#       d1: x/0
24215#       d2: x/ms 32-bits of mant of abs(YINT)
24216#       d3: x/ls 32-bits of mant of abs(YINT)
24217#       d4: LEN/Unchanged
24218#       d5: ICTR:LAMBDA/LAMBDA:ICTR
24219#       d6: ILOG
24220#       d7: k-factor/Unchanged
24221#       a0: pointer into memory for packed bcd string formation
24222#           /ptr to first mantissa byte in result string
24223#       a1: ptr to PTENxx array/Unchanged
24224#       a2: ptr to FP_SCR1(a6)/Unchanged
24225#       fp0: int portion of Y/abs(YINT) adjusted
24226#       fp1: 10^ISCALE/Unchanged
24227#       fp2: 10^LEN/Unchanged
24228#       F_SCR1:x/Work area for final result
24229#       F_SCR2:Y with original exponent/Unchanged
24230#       L_SCR1:original USER_FPCR/Unchanged
24231#       L_SCR2:first word of X packed/Unchanged
24232
24233A14_st:
24234        fmov.l          &rz_mode*0x10,%fpcr     # force rz for conversion
24235        fdiv.x          %fp2,%fp0       # divide abs(YINT) by 10^LEN
24236        lea.l           FP_SCR0(%a6),%a0
24237        fmov.x          %fp0,(%a0)      # move abs(YINT)/10^LEN to memory
24238        mov.l           4(%a0),%d2      # move 2nd word of FP_RES to d2
24239        mov.l           8(%a0),%d3      # move 3rd word of FP_RES to d3
24240        clr.l           4(%a0)          # zero word 2 of FP_RES
24241        clr.l           8(%a0)          # zero word 3 of FP_RES
24242        mov.l           (%a0),%d0       # move exponent to d0
24243        swap            %d0             # put exponent in lower word
24244        beq.b           no_sft          # if zero, don't shift
24245        sub.l           &0x3ffd,%d0     # sub bias less 2 to make fract
24246        tst.l           %d0             # check if > 1
24247        bgt.b           no_sft          # if so, don't shift
24248        neg.l           %d0             # make exp positive
24249m_loop:
24250        lsr.l           &1,%d2          # shift d2:d3 right, add 0s
24251        roxr.l          &1,%d3          # the number of places
24252        dbf.w           %d0,m_loop      # given in d0
24253no_sft:
24254        tst.l           %d2             # check for mantissa of zero
24255        bne.b           no_zr           # if not, go on
24256        tst.l           %d3             # continue zero check
24257        beq.b           zer_m           # if zero, go directly to binstr
24258no_zr:
24259        clr.l           %d1             # put zero in d1 for addx
24260        add.l           &0x00000080,%d3 # inc at bit 7
24261        addx.l          %d1,%d2         # continue inc
24262        and.l           &0xffffff80,%d3 # strip off lsb not used by 882
24263zer_m:
24264        mov.l           %d4,%d0         # put LEN in d0 for binstr call
24265        addq.l          &3,%a0          # a0 points to M16 byte in result
24266        bsr             binstr          # call binstr to convert mant
24267
24268
24269# A15. Convert the exponent to bcd.
24270#      As in A14 above, the exp is converted to bcd and the
24271#      digits are stored in the final string.
24272#
24273#      Digits are stored in L_SCR1(a6) on return from BINDEC as:
24274#
24275#        32               16 15                0
24276#       -----------------------------------------
24277#       |  0 | e3 | e2 | e1 | e4 |  X |  X |  X |
24278#       -----------------------------------------
24279#
24280# And are moved into their proper places in FP_SCR0.  If digit e4
24281# is non-zero, OPERR is signaled.  In all cases, all 4 digits are
24282# written as specified in the 881/882 manual for packed decimal.
24283#
24284# Register usage:
24285#       Input/Output
24286#       d0: x/LEN call to binstr - final is 0
24287#       d1: x/scratch (0);shift count for final exponent packing
24288#       d2: x/ms 32-bits of exp fraction/scratch
24289#       d3: x/ls 32-bits of exp fraction
24290#       d4: LEN/Unchanged
24291#       d5: ICTR:LAMBDA/LAMBDA:ICTR
24292#       d6: ILOG
24293#       d7: k-factor/Unchanged
24294#       a0: ptr to result string/ptr to L_SCR1(a6)
24295#       a1: ptr to PTENxx array/Unchanged
24296#       a2: ptr to FP_SCR1(a6)/Unchanged
24297#       fp0: abs(YINT) adjusted/float(ILOG)
24298#       fp1: 10^ISCALE/Unchanged
24299#       fp2: 10^LEN/Unchanged
24300#       F_SCR1:Work area for final result/BCD result
24301#       F_SCR2:Y with original exponent/ILOG/10^4
24302#       L_SCR1:original USER_FPCR/Exponent digits on return from binstr
24303#       L_SCR2:first word of X packed/Unchanged
24304
24305A15_st:
24306        tst.b           BINDEC_FLG(%a6) # check for denorm
24307        beq.b           not_denorm
24308        ftest.x         %fp0            # test for zero
24309        fbeq.w          den_zero        # if zero, use k-factor or 4933
24310        fmov.l          %d6,%fp0        # float ILOG
24311        fabs.x          %fp0            # get abs of ILOG
24312        bra.b           convrt
24313den_zero:
24314        tst.l           %d7             # check sign of the k-factor
24315        blt.b           use_ilog        # if negative, use ILOG
24316        fmov.s          F4933(%pc),%fp0 # force exponent to 4933
24317        bra.b           convrt          # do it
24318use_ilog:
24319        fmov.l          %d6,%fp0        # float ILOG
24320        fabs.x          %fp0            # get abs of ILOG
24321        bra.b           convrt
24322not_denorm:
24323        ftest.x         %fp0            # test for zero
24324        fbneq.w         not_zero        # if zero, force exponent
24325        fmov.s          FONE(%pc),%fp0  # force exponent to 1
24326        bra.b           convrt          # do it
24327not_zero:
24328        fmov.l          %d6,%fp0        # float ILOG
24329        fabs.x          %fp0            # get abs of ILOG
24330convrt:
24331        fdiv.x          24(%a1),%fp0    # compute ILOG/10^4
24332        fmov.x          %fp0,FP_SCR1(%a6)       # store fp0 in memory
24333        mov.l           4(%a2),%d2      # move word 2 to d2
24334        mov.l           8(%a2),%d3      # move word 3 to d3
24335        mov.w           (%a2),%d0       # move exp to d0
24336        beq.b           x_loop_fin      # if zero, skip the shift
24337        sub.w           &0x3ffd,%d0     # subtract off bias
24338        neg.w           %d0             # make exp positive
24339x_loop:
24340        lsr.l           &1,%d2          # shift d2:d3 right
24341        roxr.l          &1,%d3          # the number of places
24342        dbf.w           %d0,x_loop      # given in d0
24343x_loop_fin:
24344        clr.l           %d1             # put zero in d1 for addx
24345        add.l           &0x00000080,%d3 # inc at bit 6
24346        addx.l          %d1,%d2         # continue inc
24347        and.l           &0xffffff80,%d3 # strip off lsb not used by 882
24348        mov.l           &4,%d0          # put 4 in d0 for binstr call
24349        lea.l           L_SCR1(%a6),%a0 # a0 is ptr to L_SCR1 for exp digits
24350        bsr             binstr          # call binstr to convert exp
24351        mov.l           L_SCR1(%a6),%d0 # load L_SCR1 lword to d0
24352        mov.l           &12,%d1         # use d1 for shift count
24353        lsr.l           %d1,%d0         # shift d0 right by 12
24354        bfins           %d0,FP_SCR0(%a6){&4:&12}        # put e3:e2:e1 in FP_SCR0
24355        lsr.l           %d1,%d0         # shift d0 right by 12
24356        bfins           %d0,FP_SCR0(%a6){&16:&4}        # put e4 in FP_SCR0
24357        tst.b           %d0             # check if e4 is zero
24358        beq.b           A16_st          # if zero, skip rest
24359        or.l            &opaop_mask,USER_FPSR(%a6)      # set OPERR & AIOP in USER_FPSR
24360
24361
24362# A16. Write sign bits to final string.
24363#          Sigma is bit 31 of initial value; RHO is bit 31 of d6 (ILOG).
24364#
24365# Register usage:
24366#       Input/Output
24367#       d0: x/scratch - final is x
24368#       d2: x/x
24369#       d3: x/x
24370#       d4: LEN/Unchanged
24371#       d5: ICTR:LAMBDA/LAMBDA:ICTR
24372#       d6: ILOG/ILOG adjusted
24373#       d7: k-factor/Unchanged
24374#       a0: ptr to L_SCR1(a6)/Unchanged
24375#       a1: ptr to PTENxx array/Unchanged
24376#       a2: ptr to FP_SCR1(a6)/Unchanged
24377#       fp0: float(ILOG)/Unchanged
24378#       fp1: 10^ISCALE/Unchanged
24379#       fp2: 10^LEN/Unchanged
24380#       F_SCR1:BCD result with correct signs
24381#       F_SCR2:ILOG/10^4
24382#       L_SCR1:Exponent digits on return from binstr
24383#       L_SCR2:first word of X packed/Unchanged
24384
24385A16_st:
24386        clr.l           %d0             # clr d0 for collection of signs
24387        and.b           &0x0f,FP_SCR0(%a6)      # clear first nibble of FP_SCR0
24388        tst.l           L_SCR2(%a6)     # check sign of original mantissa
24389        bge.b           mant_p          # if pos, don't set SM
24390        mov.l           &2,%d0          # move 2 in to d0 for SM
24391mant_p:
24392        tst.l           %d6             # check sign of ILOG
24393        bge.b           wr_sgn          # if pos, don't set SE
24394        addq.l          &1,%d0          # set bit 0 in d0 for SE
24395wr_sgn:
24396        bfins           %d0,FP_SCR0(%a6){&0:&2} # insert SM and SE into FP_SCR0
24397
24398# Clean up and restore all registers used.
24399
24400        fmov.l          &0,%fpsr        # clear possible inex2/ainex bits
24401        fmovm.x         (%sp)+,&0xe0    #  {%fp0-%fp2}
24402        movm.l          (%sp)+,&0x4fc   #  {%d2-%d7/%a2}
24403        rts
24404
24405        global          PTENRN
24406PTENRN:
24407        long            0x40020000,0xA0000000,0x00000000        # 10 ^ 1
24408        long            0x40050000,0xC8000000,0x00000000        # 10 ^ 2
24409        long            0x400C0000,0x9C400000,0x00000000        # 10 ^ 4
24410        long            0x40190000,0xBEBC2000,0x00000000        # 10 ^ 8
24411        long            0x40340000,0x8E1BC9BF,0x04000000        # 10 ^ 16
24412        long            0x40690000,0x9DC5ADA8,0x2B70B59E        # 10 ^ 32
24413        long            0x40D30000,0xC2781F49,0xFFCFA6D5        # 10 ^ 64
24414        long            0x41A80000,0x93BA47C9,0x80E98CE0        # 10 ^ 128
24415        long            0x43510000,0xAA7EEBFB,0x9DF9DE8E        # 10 ^ 256
24416        long            0x46A30000,0xE319A0AE,0xA60E91C7        # 10 ^ 512
24417        long            0x4D480000,0xC9767586,0x81750C17        # 10 ^ 1024
24418        long            0x5A920000,0x9E8B3B5D,0xC53D5DE5        # 10 ^ 2048
24419        long            0x75250000,0xC4605202,0x8A20979B        # 10 ^ 4096
24420
24421        global          PTENRP
24422PTENRP:
24423        long            0x40020000,0xA0000000,0x00000000        # 10 ^ 1
24424        long            0x40050000,0xC8000000,0x00000000        # 10 ^ 2
24425        long            0x400C0000,0x9C400000,0x00000000        # 10 ^ 4
24426        long            0x40190000,0xBEBC2000,0x00000000        # 10 ^ 8
24427        long            0x40340000,0x8E1BC9BF,0x04000000        # 10 ^ 16
24428        long            0x40690000,0x9DC5ADA8,0x2B70B59E        # 10 ^ 32
24429        long            0x40D30000,0xC2781F49,0xFFCFA6D6        # 10 ^ 64
24430        long            0x41A80000,0x93BA47C9,0x80E98CE0        # 10 ^ 128
24431        long            0x43510000,0xAA7EEBFB,0x9DF9DE8E        # 10 ^ 256
24432        long            0x46A30000,0xE319A0AE,0xA60E91C7        # 10 ^ 512
24433        long            0x4D480000,0xC9767586,0x81750C18        # 10 ^ 1024
24434        long            0x5A920000,0x9E8B3B5D,0xC53D5DE5        # 10 ^ 2048
24435        long            0x75250000,0xC4605202,0x8A20979B        # 10 ^ 4096
24436
24437        global          PTENRM
24438PTENRM:
24439        long            0x40020000,0xA0000000,0x00000000        # 10 ^ 1
24440        long            0x40050000,0xC8000000,0x00000000        # 10 ^ 2
24441        long            0x400C0000,0x9C400000,0x00000000        # 10 ^ 4
24442        long            0x40190000,0xBEBC2000,0x00000000        # 10 ^ 8
24443        long            0x40340000,0x8E1BC9BF,0x04000000        # 10 ^ 16
24444        long            0x40690000,0x9DC5ADA8,0x2B70B59D        # 10 ^ 32
24445        long            0x40D30000,0xC2781F49,0xFFCFA6D5        # 10 ^ 64
24446        long            0x41A80000,0x93BA47C9,0x80E98CDF        # 10 ^ 128
24447        long            0x43510000,0xAA7EEBFB,0x9DF9DE8D        # 10 ^ 256
24448        long            0x46A30000,0xE319A0AE,0xA60E91C6        # 10 ^ 512
24449        long            0x4D480000,0xC9767586,0x81750C17        # 10 ^ 1024
24450        long            0x5A920000,0x9E8B3B5D,0xC53D5DE4        # 10 ^ 2048
24451        long            0x75250000,0xC4605202,0x8A20979A        # 10 ^ 4096
24452
24453#########################################################################
24454# binstr(): Converts a 64-bit binary integer to bcd.                    #
24455#                                                                       #
24456# INPUT *************************************************************** #
24457#       d2:d3 = 64-bit binary integer                                   #
24458#       d0    = desired length (LEN)                                    #
24459#       a0    = pointer to start in memory for bcd characters           #
24460#               (This pointer must point to byte 4 of the first         #
24461#                lword of the packed decimal memory string.)            #
24462#                                                                       #
24463# OUTPUT ************************************************************** #
24464#       a0 = pointer to LEN bcd digits representing the 64-bit integer. #
24465#                                                                       #
24466# ALGORITHM *********************************************************** #
24467#       The 64-bit binary is assumed to have a decimal point before     #
24468#       bit 63.  The fraction is multiplied by 10 using a mul by 2      #
24469#       shift and a mul by 8 shift.  The bits shifted out of the        #
24470#       msb form a decimal digit.  This process is iterated until       #
24471#       LEN digits are formed.                                          #
24472#                                                                       #
24473# A1. Init d7 to 1.  D7 is the byte digit counter, and if 1, the        #
24474#     digit formed will be assumed the least significant.  This is      #
24475#     to force the first byte formed to have a 0 in the upper 4 bits.   #
24476#                                                                       #
24477# A2. Beginning of the loop:                                            #
24478#     Copy the fraction in d2:d3 to d4:d5.                              #
24479#                                                                       #
24480# A3. Multiply the fraction in d2:d3 by 8 using bit-field               #
24481#     extracts and shifts.  The three msbs from d2 will go into d1.     #
24482#                                                                       #
24483# A4. Multiply the fraction in d4:d5 by 2 using shifts.  The msb        #
24484#     will be collected by the carry.                                   #
24485#                                                                       #
24486# A5. Add using the carry the 64-bit quantities in d2:d3 and d4:d5      #
24487#     into d2:d3.  D1 will contain the bcd digit formed.                #
24488#                                                                       #
24489# A6. Test d7.  If zero, the digit formed is the ms digit.  If non-     #
24490#     zero, it is the ls digit.  Put the digit in its place in the      #
24491#     upper word of d0.  If it is the ls digit, write the word          #
24492#     from d0 to memory.                                                #
24493#                                                                       #
24494# A7. Decrement d6 (LEN counter) and repeat the loop until zero.        #
24495#                                                                       #
24496#########################################################################
24497
24498#       Implementation Notes:
24499#
24500#       The registers are used as follows:
24501#
24502#               d0: LEN counter
24503#               d1: temp used to form the digit
24504#               d2: upper 32-bits of fraction for mul by 8
24505#               d3: lower 32-bits of fraction for mul by 8
24506#               d4: upper 32-bits of fraction for mul by 2
24507#               d5: lower 32-bits of fraction for mul by 2
24508#               d6: temp for bit-field extracts
24509#               d7: byte digit formation word;digit count {0,1}
24510#               a0: pointer into memory for packed bcd string formation
24511#
24512
24513        global          binstr
24514binstr:
24515        movm.l          &0xff00,-(%sp)  #  {%d0-%d7}
24516
24517#
24518# A1: Init d7
24519#
24520        mov.l           &1,%d7          # init d7 for second digit
24521        subq.l          &1,%d0          # for dbf d0 would have LEN+1 passes
24522#
24523# A2. Copy d2:d3 to d4:d5.  Start loop.
24524#
24525loop:
24526        mov.l           %d2,%d4         # copy the fraction before muls
24527        mov.l           %d3,%d5         # to d4:d5
24528#
24529# A3. Multiply d2:d3 by 8; extract msbs into d1.
24530#
24531        bfextu          %d2{&0:&3},%d1  # copy 3 msbs of d2 into d1
24532        asl.l           &3,%d2          # shift d2 left by 3 places
24533        bfextu          %d3{&0:&3},%d6  # copy 3 msbs of d3 into d6
24534        asl.l           &3,%d3          # shift d3 left by 3 places
24535        or.l            %d6,%d2         # or in msbs from d3 into d2
24536#
24537# A4. Multiply d4:d5 by 2; add carry out to d1.
24538#
24539        asl.l           &1,%d5          # mul d5 by 2
24540        roxl.l          &1,%d4          # mul d4 by 2
24541        swap            %d6             # put 0 in d6 lower word
24542        addx.w          %d6,%d1         # add in extend from mul by 2
24543#
24544# A5. Add mul by 8 to mul by 2.  D1 contains the digit formed.
24545#
24546        add.l           %d5,%d3         # add lower 32 bits
24547        nop                             # ERRATA FIX #13 (Rev. 1.2 6/6/90)
24548        addx.l          %d4,%d2         # add with extend upper 32 bits
24549        nop                             # ERRATA FIX #13 (Rev. 1.2 6/6/90)
24550        addx.w          %d6,%d1         # add in extend from add to d1
24551        swap            %d6             # with d6 = 0; put 0 in upper word
24552#
24553# A6. Test d7 and branch.
24554#
24555        tst.w           %d7             # if zero, store digit & to loop
24556        beq.b           first_d         # if non-zero, form byte & write
24557sec_d:
24558        swap            %d7             # bring first digit to word d7b
24559        asl.w           &4,%d7          # first digit in upper 4 bits d7b
24560        add.w           %d1,%d7         # add in ls digit to d7b
24561        mov.b           %d7,(%a0)+      # store d7b byte in memory
24562        swap            %d7             # put LEN counter in word d7a
24563        clr.w           %d7             # set d7a to signal no digits done
24564        dbf.w           %d0,loop        # do loop some more!
24565        bra.b           end_bstr        # finished, so exit
24566first_d:
24567        swap            %d7             # put digit word in d7b
24568        mov.w           %d1,%d7         # put new digit in d7b
24569        swap            %d7             # put LEN counter in word d7a
24570        addq.w          &1,%d7          # set d7a to signal first digit done
24571        dbf.w           %d0,loop        # do loop some more!
24572        swap            %d7             # put last digit in string
24573        lsl.w           &4,%d7          # move it to upper 4 bits
24574        mov.b           %d7,(%a0)+      # store it in memory string
24575#
24576# Clean up and return with result in fp0.
24577#
24578end_bstr:
24579        movm.l          (%sp)+,&0xff    #  {%d0-%d7}
24580        rts
24581
24582#########################################################################
24583# XDEF **************************************************************** #
24584#       facc_in_b(): dmem_read_byte failed                              #
24585#       facc_in_w(): dmem_read_word failed                              #
24586#       facc_in_l(): dmem_read_long failed                              #
24587#       facc_in_d(): dmem_read of dbl prec failed                       #
24588#       facc_in_x(): dmem_read of ext prec failed                       #
24589#                                                                       #
24590#       facc_out_b(): dmem_write_byte failed                            #
24591#       facc_out_w(): dmem_write_word failed                            #
24592#       facc_out_l(): dmem_write_long failed                            #
24593#       facc_out_d(): dmem_write of dbl prec failed                     #
24594#       facc_out_x(): dmem_write of ext prec failed                     #
24595#                                                                       #
24596# XREF **************************************************************** #
24597#       _real_access() - exit through access error handler              #
24598#                                                                       #
24599# INPUT *************************************************************** #
24600#       None                                                            #
24601#                                                                       #
24602# OUTPUT ************************************************************** #
24603#       None                                                            #
24604#                                                                       #
24605# ALGORITHM *********************************************************** #
24606#       Flow jumps here when an FP data fetch call gets an error        #
24607# result. This means the operating system wants an access error frame   #
24608# made out of the current exception stack frame.                        #
24609#       So, we first call restore() which makes sure that any updated   #
24610# -(an)+ register gets returned to its pre-exception value and then     #
24611# we change the stack to an access error stack frame.                   #
24612#                                                                       #
24613#########################################################################
24614
24615facc_in_b:
24616        movq.l          &0x1,%d0                        # one byte
24617        bsr.w           restore                         # fix An
24618
24619        mov.w           &0x0121,EXC_VOFF(%a6)           # set FSLW
24620        bra.w           facc_finish
24621
24622facc_in_w:
24623        movq.l          &0x2,%d0                        # two bytes
24624        bsr.w           restore                         # fix An
24625
24626        mov.w           &0x0141,EXC_VOFF(%a6)           # set FSLW
24627        bra.b           facc_finish
24628
24629facc_in_l:
24630        movq.l          &0x4,%d0                        # four bytes
24631        bsr.w           restore                         # fix An
24632
24633        mov.w           &0x0101,EXC_VOFF(%a6)           # set FSLW
24634        bra.b           facc_finish
24635
24636facc_in_d:
24637        movq.l          &0x8,%d0                        # eight bytes
24638        bsr.w           restore                         # fix An
24639
24640        mov.w           &0x0161,EXC_VOFF(%a6)           # set FSLW
24641        bra.b           facc_finish
24642
24643facc_in_x:
24644        movq.l          &0xc,%d0                        # twelve bytes
24645        bsr.w           restore                         # fix An
24646
24647        mov.w           &0x0161,EXC_VOFF(%a6)           # set FSLW
24648        bra.b           facc_finish
24649
24650################################################################
24651
24652facc_out_b:
24653        movq.l          &0x1,%d0                        # one byte
24654        bsr.w           restore                         # restore An
24655
24656        mov.w           &0x00a1,EXC_VOFF(%a6)           # set FSLW
24657        bra.b           facc_finish
24658
24659facc_out_w:
24660        movq.l          &0x2,%d0                        # two bytes
24661        bsr.w           restore                         # restore An
24662
24663        mov.w           &0x00c1,EXC_VOFF(%a6)           # set FSLW
24664        bra.b           facc_finish
24665
24666facc_out_l:
24667        movq.l          &0x4,%d0                        # four bytes
24668        bsr.w           restore                         # restore An
24669
24670        mov.w           &0x0081,EXC_VOFF(%a6)           # set FSLW
24671        bra.b           facc_finish
24672
24673facc_out_d:
24674        movq.l          &0x8,%d0                        # eight bytes
24675        bsr.w           restore                         # restore An
24676
24677        mov.w           &0x00e1,EXC_VOFF(%a6)           # set FSLW
24678        bra.b           facc_finish
24679
24680facc_out_x:
24681        mov.l           &0xc,%d0                        # twelve bytes
24682        bsr.w           restore                         # restore An
24683
24684        mov.w           &0x00e1,EXC_VOFF(%a6)           # set FSLW
24685
24686# here's where we actually create the access error frame from the
24687# current exception stack frame.
24688facc_finish:
24689        mov.l           USER_FPIAR(%a6),EXC_PC(%a6) # store current PC
24690
24691        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
24692        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
24693        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
24694
24695        unlk            %a6
24696
24697        mov.l           (%sp),-(%sp)            # store SR, hi(PC)
24698        mov.l           0x8(%sp),0x4(%sp)       # store lo(PC)
24699        mov.l           0xc(%sp),0x8(%sp)       # store EA
24700        mov.l           &0x00000001,0xc(%sp)    # store FSLW
24701        mov.w           0x6(%sp),0xc(%sp)       # fix FSLW (size)
24702        mov.w           &0x4008,0x6(%sp)        # store voff
24703
24704        btst            &0x5,(%sp)              # supervisor or user mode?
24705        beq.b           facc_out2               # user
24706        bset            &0x2,0xd(%sp)           # set supervisor TM bit
24707
24708facc_out2:
24709        bra.l           _real_access
24710
24711##################################################################
24712
24713# if the effective addressing mode was predecrement or postincrement,
24714# the emulation has already changed its value to the correct post-
24715# instruction value. but since we're exiting to the access error
24716# handler, then AN must be returned to its pre-instruction value.
24717# we do that here.
24718restore:
24719        mov.b           EXC_OPWORD+0x1(%a6),%d1
24720        andi.b          &0x38,%d1               # extract opmode
24721        cmpi.b          %d1,&0x18               # postinc?
24722        beq.w           rest_inc
24723        cmpi.b          %d1,&0x20               # predec?
24724        beq.w           rest_dec
24725        rts
24726
24727rest_inc:
24728        mov.b           EXC_OPWORD+0x1(%a6),%d1
24729        andi.w          &0x0007,%d1             # fetch An
24730
24731        mov.w           (tbl_rest_inc.b,%pc,%d1.w*2),%d1
24732        jmp             (tbl_rest_inc.b,%pc,%d1.w*1)
24733
24734tbl_rest_inc:
24735        short           ri_a0 - tbl_rest_inc
24736        short           ri_a1 - tbl_rest_inc
24737        short           ri_a2 - tbl_rest_inc
24738        short           ri_a3 - tbl_rest_inc
24739        short           ri_a4 - tbl_rest_inc
24740        short           ri_a5 - tbl_rest_inc
24741        short           ri_a6 - tbl_rest_inc
24742        short           ri_a7 - tbl_rest_inc
24743
24744ri_a0:
24745        sub.l           %d0,EXC_DREGS+0x8(%a6)  # fix stacked a0
24746        rts
24747ri_a1:
24748        sub.l           %d0,EXC_DREGS+0xc(%a6)  # fix stacked a1
24749        rts
24750ri_a2:
24751        sub.l           %d0,%a2                 # fix a2
24752        rts
24753ri_a3:
24754        sub.l           %d0,%a3                 # fix a3
24755        rts
24756ri_a4:
24757        sub.l           %d0,%a4                 # fix a4
24758        rts
24759ri_a5:
24760        sub.l           %d0,%a5                 # fix a5
24761        rts
24762ri_a6:
24763        sub.l           %d0,(%a6)               # fix stacked a6
24764        rts
24765# if it's a fmove out instruction, we don't have to fix a7
24766# because we hadn't changed it yet. if it's an opclass two
24767# instruction (data moved in) and the exception was in supervisor
24768# mode, then also also wasn't updated. if it was user mode, then
24769# restore the correct a7 which is in the USP currently.
24770ri_a7:
24771        cmpi.b          EXC_VOFF(%a6),&0x30     # move in or out?
24772        bne.b           ri_a7_done              # out
24773
24774        btst            &0x5,EXC_SR(%a6)        # user or supervisor?
24775        bne.b           ri_a7_done              # supervisor
24776        movc            %usp,%a0                # restore USP
24777        sub.l           %d0,%a0
24778        movc            %a0,%usp
24779ri_a7_done:
24780        rts
24781
24782# need to invert adjustment value if the <ea> was predec
24783rest_dec:
24784        neg.l           %d0
24785        bra.b           rest_inc
24786