linux/arch/m68k/ifpsp060/src/pfpsp.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# freal.s:
  30#       This file is appended to the top of the 060FPSP package
  31# and contains the entry points into the package. The user, in
  32# effect, branches to one of the branch table entries located
  33# after _060FPSP_TABLE.
  34#       Also, subroutine stubs exist in this file (_fpsp_done for
  35# example) that are referenced by the FPSP package itself in order
  36# to call a given routine. The stub routine actually performs the
  37# callout. The FPSP code does a "bsr" to the stub routine. This
  38# extra layer of hierarchy adds a slight performance penalty but
  39# it makes the FPSP code easier to read and more mainatinable.
  40#
  41
  42set     _off_bsun,      0x00
  43set     _off_snan,      0x04
  44set     _off_operr,     0x08
  45set     _off_ovfl,      0x0c
  46set     _off_unfl,      0x10
  47set     _off_dz,        0x14
  48set     _off_inex,      0x18
  49set     _off_fline,     0x1c
  50set     _off_fpu_dis,   0x20
  51set     _off_trap,      0x24
  52set     _off_trace,     0x28
  53set     _off_access,    0x2c
  54set     _off_done,      0x30
  55
  56set     _off_imr,       0x40
  57set     _off_dmr,       0x44
  58set     _off_dmw,       0x48
  59set     _off_irw,       0x4c
  60set     _off_irl,       0x50
  61set     _off_drb,       0x54
  62set     _off_drw,       0x58
  63set     _off_drl,       0x5c
  64set     _off_dwb,       0x60
  65set     _off_dww,       0x64
  66set     _off_dwl,       0x68
  67
  68_060FPSP_TABLE:
  69
  70###############################################################
  71
  72# Here's the table of ENTRY POINTS for those linking the package.
  73        bra.l           _fpsp_snan
  74        short           0x0000
  75        bra.l           _fpsp_operr
  76        short           0x0000
  77        bra.l           _fpsp_ovfl
  78        short           0x0000
  79        bra.l           _fpsp_unfl
  80        short           0x0000
  81        bra.l           _fpsp_dz
  82        short           0x0000
  83        bra.l           _fpsp_inex
  84        short           0x0000
  85        bra.l           _fpsp_fline
  86        short           0x0000
  87        bra.l           _fpsp_unsupp
  88        short           0x0000
  89        bra.l           _fpsp_effadd
  90        short           0x0000
  91
  92        space           56
  93
  94###############################################################
  95        global          _fpsp_done
  96_fpsp_done:
  97        mov.l           %d0,-(%sp)
  98        mov.l           (_060FPSP_TABLE-0x80+_off_done,%pc),%d0
  99        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 100        mov.l           0x4(%sp),%d0
 101        rtd             &0x4
 102
 103        global          _real_ovfl
 104_real_ovfl:
 105        mov.l           %d0,-(%sp)
 106        mov.l           (_060FPSP_TABLE-0x80+_off_ovfl,%pc),%d0
 107        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 108        mov.l           0x4(%sp),%d0
 109        rtd             &0x4
 110
 111        global          _real_unfl
 112_real_unfl:
 113        mov.l           %d0,-(%sp)
 114        mov.l           (_060FPSP_TABLE-0x80+_off_unfl,%pc),%d0
 115        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 116        mov.l           0x4(%sp),%d0
 117        rtd             &0x4
 118
 119        global          _real_inex
 120_real_inex:
 121        mov.l           %d0,-(%sp)
 122        mov.l           (_060FPSP_TABLE-0x80+_off_inex,%pc),%d0
 123        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 124        mov.l           0x4(%sp),%d0
 125        rtd             &0x4
 126
 127        global          _real_bsun
 128_real_bsun:
 129        mov.l           %d0,-(%sp)
 130        mov.l           (_060FPSP_TABLE-0x80+_off_bsun,%pc),%d0
 131        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 132        mov.l           0x4(%sp),%d0
 133        rtd             &0x4
 134
 135        global          _real_operr
 136_real_operr:
 137        mov.l           %d0,-(%sp)
 138        mov.l           (_060FPSP_TABLE-0x80+_off_operr,%pc),%d0
 139        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 140        mov.l           0x4(%sp),%d0
 141        rtd             &0x4
 142
 143        global          _real_snan
 144_real_snan:
 145        mov.l           %d0,-(%sp)
 146        mov.l           (_060FPSP_TABLE-0x80+_off_snan,%pc),%d0
 147        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 148        mov.l           0x4(%sp),%d0
 149        rtd             &0x4
 150
 151        global          _real_dz
 152_real_dz:
 153        mov.l           %d0,-(%sp)
 154        mov.l           (_060FPSP_TABLE-0x80+_off_dz,%pc),%d0
 155        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 156        mov.l           0x4(%sp),%d0
 157        rtd             &0x4
 158
 159        global          _real_fline
 160_real_fline:
 161        mov.l           %d0,-(%sp)
 162        mov.l           (_060FPSP_TABLE-0x80+_off_fline,%pc),%d0
 163        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 164        mov.l           0x4(%sp),%d0
 165        rtd             &0x4
 166
 167        global          _real_fpu_disabled
 168_real_fpu_disabled:
 169        mov.l           %d0,-(%sp)
 170        mov.l           (_060FPSP_TABLE-0x80+_off_fpu_dis,%pc),%d0
 171        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 172        mov.l           0x4(%sp),%d0
 173        rtd             &0x4
 174
 175        global          _real_trap
 176_real_trap:
 177        mov.l           %d0,-(%sp)
 178        mov.l           (_060FPSP_TABLE-0x80+_off_trap,%pc),%d0
 179        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 180        mov.l           0x4(%sp),%d0
 181        rtd             &0x4
 182
 183        global          _real_trace
 184_real_trace:
 185        mov.l           %d0,-(%sp)
 186        mov.l           (_060FPSP_TABLE-0x80+_off_trace,%pc),%d0
 187        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 188        mov.l           0x4(%sp),%d0
 189        rtd             &0x4
 190
 191        global          _real_access
 192_real_access:
 193        mov.l           %d0,-(%sp)
 194        mov.l           (_060FPSP_TABLE-0x80+_off_access,%pc),%d0
 195        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 196        mov.l           0x4(%sp),%d0
 197        rtd             &0x4
 198
 199#######################################
 200
 201        global          _imem_read
 202_imem_read:
 203        mov.l           %d0,-(%sp)
 204        mov.l           (_060FPSP_TABLE-0x80+_off_imr,%pc),%d0
 205        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 206        mov.l           0x4(%sp),%d0
 207        rtd             &0x4
 208
 209        global          _dmem_read
 210_dmem_read:
 211        mov.l           %d0,-(%sp)
 212        mov.l           (_060FPSP_TABLE-0x80+_off_dmr,%pc),%d0
 213        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 214        mov.l           0x4(%sp),%d0
 215        rtd             &0x4
 216
 217        global          _dmem_write
 218_dmem_write:
 219        mov.l           %d0,-(%sp)
 220        mov.l           (_060FPSP_TABLE-0x80+_off_dmw,%pc),%d0
 221        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 222        mov.l           0x4(%sp),%d0
 223        rtd             &0x4
 224
 225        global          _imem_read_word
 226_imem_read_word:
 227        mov.l           %d0,-(%sp)
 228        mov.l           (_060FPSP_TABLE-0x80+_off_irw,%pc),%d0
 229        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 230        mov.l           0x4(%sp),%d0
 231        rtd             &0x4
 232
 233        global          _imem_read_long
 234_imem_read_long:
 235        mov.l           %d0,-(%sp)
 236        mov.l           (_060FPSP_TABLE-0x80+_off_irl,%pc),%d0
 237        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 238        mov.l           0x4(%sp),%d0
 239        rtd             &0x4
 240
 241        global          _dmem_read_byte
 242_dmem_read_byte:
 243        mov.l           %d0,-(%sp)
 244        mov.l           (_060FPSP_TABLE-0x80+_off_drb,%pc),%d0
 245        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 246        mov.l           0x4(%sp),%d0
 247        rtd             &0x4
 248
 249        global          _dmem_read_word
 250_dmem_read_word:
 251        mov.l           %d0,-(%sp)
 252        mov.l           (_060FPSP_TABLE-0x80+_off_drw,%pc),%d0
 253        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 254        mov.l           0x4(%sp),%d0
 255        rtd             &0x4
 256
 257        global          _dmem_read_long
 258_dmem_read_long:
 259        mov.l           %d0,-(%sp)
 260        mov.l           (_060FPSP_TABLE-0x80+_off_drl,%pc),%d0
 261        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 262        mov.l           0x4(%sp),%d0
 263        rtd             &0x4
 264
 265        global          _dmem_write_byte
 266_dmem_write_byte:
 267        mov.l           %d0,-(%sp)
 268        mov.l           (_060FPSP_TABLE-0x80+_off_dwb,%pc),%d0
 269        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 270        mov.l           0x4(%sp),%d0
 271        rtd             &0x4
 272
 273        global          _dmem_write_word
 274_dmem_write_word:
 275        mov.l           %d0,-(%sp)
 276        mov.l           (_060FPSP_TABLE-0x80+_off_dww,%pc),%d0
 277        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 278        mov.l           0x4(%sp),%d0
 279        rtd             &0x4
 280
 281        global          _dmem_write_long
 282_dmem_write_long:
 283        mov.l           %d0,-(%sp)
 284        mov.l           (_060FPSP_TABLE-0x80+_off_dwl,%pc),%d0
 285        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 286        mov.l           0x4(%sp),%d0
 287        rtd             &0x4
 288
 289#
 290# This file contains a set of define statements for constants
 291# in order to promote readability within the corecode itself.
 292#
 293
 294set LOCAL_SIZE,         192                     # stack frame size(bytes)
 295set LV,                 -LOCAL_SIZE             # stack offset
 296
 297set EXC_SR,             0x4                     # stack status register
 298set EXC_PC,             0x6                     # stack pc
 299set EXC_VOFF,           0xa                     # stacked vector offset
 300set EXC_EA,             0xc                     # stacked <ea>
 301
 302set EXC_FP,             0x0                     # frame pointer
 303
 304set EXC_AREGS,          -68                     # offset of all address regs
 305set EXC_DREGS,          -100                    # offset of all data regs
 306set EXC_FPREGS,         -36                     # offset of all fp regs
 307
 308set EXC_A7,             EXC_AREGS+(7*4)         # offset of saved a7
 309set OLD_A7,             EXC_AREGS+(6*4)         # extra copy of saved a7
 310set EXC_A6,             EXC_AREGS+(6*4)         # offset of saved a6
 311set EXC_A5,             EXC_AREGS+(5*4)
 312set EXC_A4,             EXC_AREGS+(4*4)
 313set EXC_A3,             EXC_AREGS+(3*4)
 314set EXC_A2,             EXC_AREGS+(2*4)
 315set EXC_A1,             EXC_AREGS+(1*4)
 316set EXC_A0,             EXC_AREGS+(0*4)
 317set EXC_D7,             EXC_DREGS+(7*4)
 318set EXC_D6,             EXC_DREGS+(6*4)
 319set EXC_D5,             EXC_DREGS+(5*4)
 320set EXC_D4,             EXC_DREGS+(4*4)
 321set EXC_D3,             EXC_DREGS+(3*4)
 322set EXC_D2,             EXC_DREGS+(2*4)
 323set EXC_D1,             EXC_DREGS+(1*4)
 324set EXC_D0,             EXC_DREGS+(0*4)
 325
 326set EXC_FP0,            EXC_FPREGS+(0*12)       # offset of saved fp0
 327set EXC_FP1,            EXC_FPREGS+(1*12)       # offset of saved fp1
 328set EXC_FP2,            EXC_FPREGS+(2*12)       # offset of saved fp2 (not used)
 329
 330set FP_SCR1,            LV+80                   # fp scratch 1
 331set FP_SCR1_EX,         FP_SCR1+0
 332set FP_SCR1_SGN,        FP_SCR1+2
 333set FP_SCR1_HI,         FP_SCR1+4
 334set FP_SCR1_LO,         FP_SCR1+8
 335
 336set FP_SCR0,            LV+68                   # fp scratch 0
 337set FP_SCR0_EX,         FP_SCR0+0
 338set FP_SCR0_SGN,        FP_SCR0+2
 339set FP_SCR0_HI,         FP_SCR0+4
 340set FP_SCR0_LO,         FP_SCR0+8
 341
 342set FP_DST,             LV+56                   # fp destination operand
 343set FP_DST_EX,          FP_DST+0
 344set FP_DST_SGN,         FP_DST+2
 345set FP_DST_HI,          FP_DST+4
 346set FP_DST_LO,          FP_DST+8
 347
 348set FP_SRC,             LV+44                   # fp source operand
 349set FP_SRC_EX,          FP_SRC+0
 350set FP_SRC_SGN,         FP_SRC+2
 351set FP_SRC_HI,          FP_SRC+4
 352set FP_SRC_LO,          FP_SRC+8
 353
 354set USER_FPIAR,         LV+40                   # FP instr address register
 355
 356set USER_FPSR,          LV+36                   # FP status register
 357set FPSR_CC,            USER_FPSR+0             # FPSR condition codes
 358set FPSR_QBYTE,         USER_FPSR+1             # FPSR qoutient byte
 359set FPSR_EXCEPT,        USER_FPSR+2             # FPSR exception status byte
 360set FPSR_AEXCEPT,       USER_FPSR+3             # FPSR accrued exception byte
 361
 362set USER_FPCR,          LV+32                   # FP control register
 363set FPCR_ENABLE,        USER_FPCR+2             # FPCR exception enable
 364set FPCR_MODE,          USER_FPCR+3             # FPCR rounding mode control
 365
 366set L_SCR3,             LV+28                   # integer scratch 3
 367set L_SCR2,             LV+24                   # integer scratch 2
 368set L_SCR1,             LV+20                   # integer scratch 1
 369
 370set STORE_FLG,          LV+19                   # flag: operand store (ie. not fcmp/ftst)
 371
 372set EXC_TEMP2,          LV+24                   # temporary space
 373set EXC_TEMP,           LV+16                   # temporary space
 374
 375set DTAG,               LV+15                   # destination operand type
 376set STAG,               LV+14                   # source operand type
 377
 378set SPCOND_FLG,         LV+10                   # flag: special case (see below)
 379
 380set EXC_CC,             LV+8                    # saved condition codes
 381set EXC_EXTWPTR,        LV+4                    # saved current PC (active)
 382set EXC_EXTWORD,        LV+2                    # saved extension word
 383set EXC_CMDREG,         LV+2                    # saved extension word
 384set EXC_OPWORD,         LV+0                    # saved operation word
 385
 386################################
 387
 388# Helpful macros
 389
 390set FTEMP,              0                       # offsets within an
 391set FTEMP_EX,           0                       # extended precision
 392set FTEMP_SGN,          2                       # value saved in memory.
 393set FTEMP_HI,           4
 394set FTEMP_LO,           8
 395set FTEMP_GRS,          12
 396
 397set LOCAL,              0                       # offsets within an
 398set LOCAL_EX,           0                       # extended precision
 399set LOCAL_SGN,          2                       # value saved in memory.
 400set LOCAL_HI,           4
 401set LOCAL_LO,           8
 402set LOCAL_GRS,          12
 403
 404set DST,                0                       # offsets within an
 405set DST_EX,             0                       # extended precision
 406set DST_HI,             4                       # value saved in memory.
 407set DST_LO,             8
 408
 409set SRC,                0                       # offsets within an
 410set SRC_EX,             0                       # extended precision
 411set SRC_HI,             4                       # value saved in memory.
 412set SRC_LO,             8
 413
 414set SGL_LO,             0x3f81                  # min sgl prec exponent
 415set SGL_HI,             0x407e                  # max sgl prec exponent
 416set DBL_LO,             0x3c01                  # min dbl prec exponent
 417set DBL_HI,             0x43fe                  # max dbl prec exponent
 418set EXT_LO,             0x0                     # min ext prec exponent
 419set EXT_HI,             0x7ffe                  # max ext prec exponent
 420
 421set EXT_BIAS,           0x3fff                  # extended precision bias
 422set SGL_BIAS,           0x007f                  # single precision bias
 423set DBL_BIAS,           0x03ff                  # double precision bias
 424
 425set NORM,               0x00                    # operand type for STAG/DTAG
 426set ZERO,               0x01                    # operand type for STAG/DTAG
 427set INF,                0x02                    # operand type for STAG/DTAG
 428set QNAN,               0x03                    # operand type for STAG/DTAG
 429set DENORM,             0x04                    # operand type for STAG/DTAG
 430set SNAN,               0x05                    # operand type for STAG/DTAG
 431set UNNORM,             0x06                    # operand type for STAG/DTAG
 432
 433##################
 434# FPSR/FPCR bits #
 435##################
 436set neg_bit,            0x3                     # negative result
 437set z_bit,              0x2                     # zero result
 438set inf_bit,            0x1                     # infinite result
 439set nan_bit,            0x0                     # NAN result
 440
 441set q_sn_bit,           0x7                     # sign bit of quotient byte
 442
 443set bsun_bit,           7                       # branch on unordered
 444set snan_bit,           6                       # signalling NAN
 445set operr_bit,          5                       # operand error
 446set ovfl_bit,           4                       # overflow
 447set unfl_bit,           3                       # underflow
 448set dz_bit,             2                       # divide by zero
 449set inex2_bit,          1                       # inexact result 2
 450set inex1_bit,          0                       # inexact result 1
 451
 452set aiop_bit,           7                       # accrued inexact operation bit
 453set aovfl_bit,          6                       # accrued overflow bit
 454set aunfl_bit,          5                       # accrued underflow bit
 455set adz_bit,            4                       # accrued dz bit
 456set ainex_bit,          3                       # accrued inexact bit
 457
 458#############################
 459# FPSR individual bit masks #
 460#############################
 461set neg_mask,           0x08000000              # negative bit mask (lw)
 462set inf_mask,           0x02000000              # infinity bit mask (lw)
 463set z_mask,             0x04000000              # zero bit mask (lw)
 464set nan_mask,           0x01000000              # nan bit mask (lw)
 465
 466set neg_bmask,          0x08                    # negative bit mask (byte)
 467set inf_bmask,          0x02                    # infinity bit mask (byte)
 468set z_bmask,            0x04                    # zero bit mask (byte)
 469set nan_bmask,          0x01                    # nan bit mask (byte)
 470
 471set bsun_mask,          0x00008000              # bsun exception mask
 472set snan_mask,          0x00004000              # snan exception mask
 473set operr_mask,         0x00002000              # operr exception mask
 474set ovfl_mask,          0x00001000              # overflow exception mask
 475set unfl_mask,          0x00000800              # underflow exception mask
 476set dz_mask,            0x00000400              # dz exception mask
 477set inex2_mask,         0x00000200              # inex2 exception mask
 478set inex1_mask,         0x00000100              # inex1 exception mask
 479
 480set aiop_mask,          0x00000080              # accrued illegal operation
 481set aovfl_mask,         0x00000040              # accrued overflow
 482set aunfl_mask,         0x00000020              # accrued underflow
 483set adz_mask,           0x00000010              # accrued divide by zero
 484set ainex_mask,         0x00000008              # accrued inexact
 485
 486######################################
 487# FPSR combinations used in the FPSP #
 488######################################
 489set dzinf_mask,         inf_mask+dz_mask+adz_mask
 490set opnan_mask,         nan_mask+operr_mask+aiop_mask
 491set nzi_mask,           0x01ffffff              #clears N, Z, and I
 492set unfinx_mask,        unfl_mask+inex2_mask+aunfl_mask+ainex_mask
 493set unf2inx_mask,       unfl_mask+inex2_mask+ainex_mask
 494set ovfinx_mask,        ovfl_mask+inex2_mask+aovfl_mask+ainex_mask
 495set inx1a_mask,         inex1_mask+ainex_mask
 496set inx2a_mask,         inex2_mask+ainex_mask
 497set snaniop_mask,       nan_mask+snan_mask+aiop_mask
 498set snaniop2_mask,      snan_mask+aiop_mask
 499set naniop_mask,        nan_mask+aiop_mask
 500set neginf_mask,        neg_mask+inf_mask
 501set infaiop_mask,       inf_mask+aiop_mask
 502set negz_mask,          neg_mask+z_mask
 503set opaop_mask,         operr_mask+aiop_mask
 504set unfl_inx_mask,      unfl_mask+aunfl_mask+ainex_mask
 505set ovfl_inx_mask,      ovfl_mask+aovfl_mask+ainex_mask
 506
 507#########
 508# misc. #
 509#########
 510set rnd_stky_bit,       29                      # stky bit pos in longword
 511
 512set sign_bit,           0x7                     # sign bit
 513set signan_bit,         0x6                     # signalling nan bit
 514
 515set sgl_thresh,         0x3f81                  # minimum sgl exponent
 516set dbl_thresh,         0x3c01                  # minimum dbl exponent
 517
 518set x_mode,             0x0                     # extended precision
 519set s_mode,             0x4                     # single precision
 520set d_mode,             0x8                     # double precision
 521
 522set rn_mode,            0x0                     # round-to-nearest
 523set rz_mode,            0x1                     # round-to-zero
 524set rm_mode,            0x2                     # round-tp-minus-infinity
 525set rp_mode,            0x3                     # round-to-plus-infinity
 526
 527set mantissalen,        64                      # length of mantissa in bits
 528
 529set BYTE,               1                       # len(byte) == 1 byte
 530set WORD,               2                       # len(word) == 2 bytes
 531set LONG,               4                       # len(longword) == 2 bytes
 532
 533set BSUN_VEC,           0xc0                    # bsun    vector offset
 534set INEX_VEC,           0xc4                    # inexact vector offset
 535set DZ_VEC,             0xc8                    # dz      vector offset
 536set UNFL_VEC,           0xcc                    # unfl    vector offset
 537set OPERR_VEC,          0xd0                    # operr   vector offset
 538set OVFL_VEC,           0xd4                    # ovfl    vector offset
 539set SNAN_VEC,           0xd8                    # snan    vector offset
 540
 541###########################
 542# SPecial CONDition FLaGs #
 543###########################
 544set ftrapcc_flg,        0x01                    # flag bit: ftrapcc exception
 545set fbsun_flg,          0x02                    # flag bit: bsun exception
 546set mia7_flg,           0x04                    # flag bit: (a7)+ <ea>
 547set mda7_flg,           0x08                    # flag bit: -(a7) <ea>
 548set fmovm_flg,          0x40                    # flag bit: fmovm instruction
 549set immed_flg,          0x80                    # flag bit: &<data> <ea>
 550
 551set ftrapcc_bit,        0x0
 552set fbsun_bit,          0x1
 553set mia7_bit,           0x2
 554set mda7_bit,           0x3
 555set immed_bit,          0x7
 556
 557##################################
 558# TRANSCENDENTAL "LAST-OP" FLAGS #
 559##################################
 560set FMUL_OP,            0x0                     # fmul instr performed last
 561set FDIV_OP,            0x1                     # fdiv performed last
 562set FADD_OP,            0x2                     # fadd performed last
 563set FMOV_OP,            0x3                     # fmov performed last
 564
 565#############
 566# CONSTANTS #
 567#############
 568T1:     long            0x40C62D38,0xD3D64634   # 16381 LOG2 LEAD
 569T2:     long            0x3D6F90AE,0xB1E75CC7   # 16381 LOG2 TRAIL
 570
 571PI:     long            0x40000000,0xC90FDAA2,0x2168C235,0x00000000
 572PIBY2:  long            0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000
 573
 574TWOBYPI:
 575        long            0x3FE45F30,0x6DC9C883
 576
 577#########################################################################
 578# XDEF **************************************************************** #
 579#       _fpsp_ovfl(): 060FPSP entry point for FP Overflow exception.    #
 580#                                                                       #
 581#       This handler should be the first code executed upon taking the  #
 582#       FP Overflow exception in an operating system.                   #
 583#                                                                       #
 584# XREF **************************************************************** #
 585#       _imem_read_long() - read instruction longword                   #
 586#       fix_skewed_ops() - adjust src operand in fsave frame            #
 587#       set_tag_x() - determine optype of src/dst operands              #
 588#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
 589#       unnorm_fix() - change UNNORM operands to NORM or ZERO           #
 590#       load_fpn2() - load dst operand from FP regfile                  #
 591#       fout() - emulate an opclass 3 instruction                       #
 592#       tbl_unsupp - add of table of emulation routines for opclass 0,2 #
 593#       _fpsp_done() - "callout" for 060FPSP exit (all work done!)      #
 594#       _real_ovfl() - "callout" for Overflow exception enabled code    #
 595#       _real_inex() - "callout" for Inexact exception enabled code     #
 596#       _real_trace() - "callout" for Trace exception code              #
 597#                                                                       #
 598# INPUT *************************************************************** #
 599#       - The system stack contains the FP Ovfl exception stack frame   #
 600#       - The fsave frame contains the source operand                   #
 601#                                                                       #
 602# OUTPUT ************************************************************** #
 603#       Overflow Exception enabled:                                     #
 604#       - The system stack is unchanged                                 #
 605#       - The fsave frame contains the adjusted src op for opclass 0,2  #
 606#       Overflow Exception disabled:                                    #
 607#       - The system stack is unchanged                                 #
 608#       - The "exception present" flag in the fsave frame is cleared    #
 609#                                                                       #
 610# ALGORITHM *********************************************************** #
 611#       On the 060, if an FP overflow is present as the result of any   #
 612# instruction, the 060 will take an overflow exception whether the      #
 613# exception is enabled or disabled in the FPCR. For the disabled case,  #
 614# This handler emulates the instruction to determine what the correct   #
 615# default result should be for the operation. This default result is    #
 616# then stored in either the FP regfile, data regfile, or memory.        #
 617# Finally, the handler exits through the "callout" _fpsp_done()         #
 618# denoting that no exceptional conditions exist within the machine.     #
 619#       If the exception is enabled, then this handler must create the  #
 620# exceptional operand and plave it in the fsave state frame, and store  #
 621# the default result (only if the instruction is opclass 3). For        #
 622# exceptions enabled, this handler must exit through the "callout"      #
 623# _real_ovfl() so that the operating system enabled overflow handler    #
 624# can handle this case.                                                 #
 625#       Two other conditions exist. First, if overflow was disabled     #
 626# but the inexact exception was enabled, this handler must exit         #
 627# through the "callout" _real_inex() regardless of whether the result   #
 628# was inexact.                                                          #
 629#       Also, in the case of an opclass three instruction where         #
 630# overflow was disabled and the trace exception was enabled, this       #
 631# handler must exit through the "callout" _real_trace().                #
 632#                                                                       #
 633#########################################################################
 634
 635        global          _fpsp_ovfl
 636_fpsp_ovfl:
 637
 638#$#     sub.l           &24,%sp                 # make room for src/dst
 639
 640        link.w          %a6,&-LOCAL_SIZE        # init stack frame
 641
 642        fsave           FP_SRC(%a6)             # grab the "busy" frame
 643
 644        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
 645        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
 646        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
 647
 648# the FPIAR holds the "current PC" of the faulting instruction
 649        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
 650        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
 651        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
 652        bsr.l           _imem_read_long         # fetch the instruction words
 653        mov.l           %d0,EXC_OPWORD(%a6)
 654
 655##############################################################################
 656
 657        btst            &0x5,EXC_CMDREG(%a6)    # is instr an fmove out?
 658        bne.w           fovfl_out
 659
 660
 661        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
 662        bsr.l           fix_skewed_ops          # fix src op
 663
 664# since, I believe, only NORMs and DENORMs can come through here,
 665# maybe we can avoid the subroutine call.
 666        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
 667        bsr.l           set_tag_x               # tag the operand type
 668        mov.b           %d0,STAG(%a6)           # maybe NORM,DENORM
 669
 670# bit five of the fp extension word separates the monadic and dyadic operations
 671# that can pass through fpsp_ovfl(). remember that fcmp, ftst, and fsincos
 672# will never take this exception.
 673        btst            &0x5,1+EXC_CMDREG(%a6)  # is operation monadic or dyadic?
 674        beq.b           fovfl_extract           # monadic
 675
 676        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
 677        bsr.l           load_fpn2               # load dst into FP_DST
 678
 679        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
 680        bsr.l           set_tag_x               # tag the operand type
 681        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
 682        bne.b           fovfl_op2_done          # no
 683        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
 684fovfl_op2_done:
 685        mov.b           %d0,DTAG(%a6)           # save dst optype tag
 686
 687fovfl_extract:
 688
 689#$#     mov.l           FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
 690#$#     mov.l           FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
 691#$#     mov.l           FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
 692#$#     mov.l           FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6)
 693#$#     mov.l           FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6)
 694#$#     mov.l           FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6)
 695
 696        clr.l           %d0
 697        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec/mode
 698
 699        mov.b           1+EXC_CMDREG(%a6),%d1
 700        andi.w          &0x007f,%d1             # extract extension
 701
 702        andi.l          &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field
 703
 704        fmov.l          &0x0,%fpcr              # zero current control regs
 705        fmov.l          &0x0,%fpsr
 706
 707        lea             FP_SRC(%a6),%a0
 708        lea             FP_DST(%a6),%a1
 709
 710# maybe we can make these entry points ONLY the OVFL entry points of each routine.
 711        mov.l           (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
 712        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
 713
 714# the operation has been emulated. the result is in fp0.
 715# the EXOP, if an exception occurred, is in fp1.
 716# we must save the default result regardless of whether
 717# traps are enabled or disabled.
 718        bfextu          EXC_CMDREG(%a6){&6:&3},%d0
 719        bsr.l           store_fpreg
 720
 721# the exceptional possibilities we have left ourselves with are ONLY overflow
 722# and inexact. and, the inexact is such that overflow occurred and was disabled
 723# but inexact was enabled.
 724        btst            &ovfl_bit,FPCR_ENABLE(%a6)
 725        bne.b           fovfl_ovfl_on
 726
 727        btst            &inex2_bit,FPCR_ENABLE(%a6)
 728        bne.b           fovfl_inex_on
 729
 730        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
 731        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 732        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
 733
 734        unlk            %a6
 735#$#     add.l           &24,%sp
 736        bra.l           _fpsp_done
 737
 738# overflow is enabled AND overflow, of course, occurred. so, we have the EXOP
 739# in fp1. now, simply jump to _real_ovfl()!
 740fovfl_ovfl_on:
 741        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP (fp1) to stack
 742
 743        mov.w           &0xe005,2+FP_SRC(%a6)   # save exc status
 744
 745        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
 746        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 747        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
 748
 749        frestore        FP_SRC(%a6)             # do this after fmovm,other f<op>s!
 750
 751        unlk            %a6
 752
 753        bra.l           _real_ovfl
 754
 755# overflow occurred but is disabled. meanwhile, inexact is enabled. Therefore,
 756# we must jump to real_inex().
 757fovfl_inex_on:
 758
 759        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP (fp1) to stack
 760
 761        mov.b           &0xc4,1+EXC_VOFF(%a6)   # vector offset = 0xc4
 762        mov.w           &0xe001,2+FP_SRC(%a6)   # save exc status
 763
 764        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
 765        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 766        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
 767
 768        frestore        FP_SRC(%a6)             # do this after fmovm,other f<op>s!
 769
 770        unlk            %a6
 771
 772        bra.l           _real_inex
 773
 774########################################################################
 775fovfl_out:
 776
 777
 778#$#     mov.l           FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
 779#$#     mov.l           FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
 780#$#     mov.l           FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
 781
 782# the src operand is definitely a NORM(!), so tag it as such
 783        mov.b           &NORM,STAG(%a6)         # set src optype tag
 784
 785        clr.l           %d0
 786        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec/mode
 787
 788        and.l           &0xffff00ff,USER_FPSR(%a6) # zero all but accured field
 789
 790        fmov.l          &0x0,%fpcr              # zero current control regs
 791        fmov.l          &0x0,%fpsr
 792
 793        lea             FP_SRC(%a6),%a0         # pass ptr to src operand
 794
 795        bsr.l           fout
 796
 797        btst            &ovfl_bit,FPCR_ENABLE(%a6)
 798        bne.w           fovfl_ovfl_on
 799
 800        btst            &inex2_bit,FPCR_ENABLE(%a6)
 801        bne.w           fovfl_inex_on
 802
 803        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
 804        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 805        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
 806
 807        unlk            %a6
 808#$#     add.l           &24,%sp
 809
 810        btst            &0x7,(%sp)              # is trace on?
 811        beq.l           _fpsp_done              # no
 812
 813        fmov.l          %fpiar,0x8(%sp)         # "Current PC" is in FPIAR
 814        mov.w           &0x2024,0x6(%sp)        # stk fmt = 0x2; voff = 0x024
 815        bra.l           _real_trace
 816
 817#########################################################################
 818# XDEF **************************************************************** #
 819#       _fpsp_unfl(): 060FPSP entry point for FP Underflow exception.   #
 820#                                                                       #
 821#       This handler should be the first code executed upon taking the  #
 822#       FP Underflow exception in an operating system.                  #
 823#                                                                       #
 824# XREF **************************************************************** #
 825#       _imem_read_long() - read instruction longword                   #
 826#       fix_skewed_ops() - adjust src operand in fsave frame            #
 827#       set_tag_x() - determine optype of src/dst operands              #
 828#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
 829#       unnorm_fix() - change UNNORM operands to NORM or ZERO           #
 830#       load_fpn2() - load dst operand from FP regfile                  #
 831#       fout() - emulate an opclass 3 instruction                       #
 832#       tbl_unsupp - add of table of emulation routines for opclass 0,2 #
 833#       _fpsp_done() - "callout" for 060FPSP exit (all work done!)      #
 834#       _real_ovfl() - "callout" for Overflow exception enabled code    #
 835#       _real_inex() - "callout" for Inexact exception enabled code     #
 836#       _real_trace() - "callout" for Trace exception code              #
 837#                                                                       #
 838# INPUT *************************************************************** #
 839#       - The system stack contains the FP Unfl exception stack frame   #
 840#       - The fsave frame contains the source operand                   #
 841#                                                                       #
 842# OUTPUT ************************************************************** #
 843#       Underflow Exception enabled:                                    #
 844#       - The system stack is unchanged                                 #
 845#       - The fsave frame contains the adjusted src op for opclass 0,2  #
 846#       Underflow Exception disabled:                                   #
 847#       - The system stack is unchanged                                 #
 848#       - The "exception present" flag in the fsave frame is cleared    #
 849#                                                                       #
 850# ALGORITHM *********************************************************** #
 851#       On the 060, if an FP underflow is present as the result of any  #
 852# instruction, the 060 will take an underflow exception whether the     #
 853# exception is enabled or disabled in the FPCR. For the disabled case,  #
 854# This handler emulates the instruction to determine what the correct   #
 855# default result should be for the operation. This default result is    #
 856# then stored in either the FP regfile, data regfile, or memory.        #
 857# Finally, the handler exits through the "callout" _fpsp_done()         #
 858# denoting that no exceptional conditions exist within the machine.     #
 859#       If the exception is enabled, then this handler must create the  #
 860# exceptional operand and plave it in the fsave state frame, and store  #
 861# the default result (only if the instruction is opclass 3). For        #
 862# exceptions enabled, this handler must exit through the "callout"      #
 863# _real_unfl() so that the operating system enabled overflow handler    #
 864# can handle this case.                                                 #
 865#       Two other conditions exist. First, if underflow was disabled    #
 866# but the inexact exception was enabled and the result was inexact,     #
 867# this handler must exit through the "callout" _real_inex().            #
 868# was inexact.                                                          #
 869#       Also, in the case of an opclass three instruction where         #
 870# underflow was disabled and the trace exception was enabled, this      #
 871# handler must exit through the "callout" _real_trace().                #
 872#                                                                       #
 873#########################################################################
 874
 875        global          _fpsp_unfl
 876_fpsp_unfl:
 877
 878#$#     sub.l           &24,%sp                 # make room for src/dst
 879
 880        link.w          %a6,&-LOCAL_SIZE        # init stack frame
 881
 882        fsave           FP_SRC(%a6)             # grab the "busy" frame
 883
 884        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
 885        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
 886        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
 887
 888# the FPIAR holds the "current PC" of the faulting instruction
 889        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
 890        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
 891        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
 892        bsr.l           _imem_read_long         # fetch the instruction words
 893        mov.l           %d0,EXC_OPWORD(%a6)
 894
 895##############################################################################
 896
 897        btst            &0x5,EXC_CMDREG(%a6)    # is instr an fmove out?
 898        bne.w           funfl_out
 899
 900
 901        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
 902        bsr.l           fix_skewed_ops          # fix src op
 903
 904        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
 905        bsr.l           set_tag_x               # tag the operand type
 906        mov.b           %d0,STAG(%a6)           # maybe NORM,DENORM
 907
 908# bit five of the fp ext word separates the monadic and dyadic operations
 909# that can pass through fpsp_unfl(). remember that fcmp, and ftst
 910# will never take this exception.
 911        btst            &0x5,1+EXC_CMDREG(%a6)  # is op monadic or dyadic?
 912        beq.b           funfl_extract           # monadic
 913
 914# now, what's left that's not dyadic is fsincos. we can distinguish it
 915# from all dyadics by the '0110xxx pattern
 916        btst            &0x4,1+EXC_CMDREG(%a6)  # is op an fsincos?
 917        bne.b           funfl_extract           # yes
 918
 919        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
 920        bsr.l           load_fpn2               # load dst into FP_DST
 921
 922        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
 923        bsr.l           set_tag_x               # tag the operand type
 924        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
 925        bne.b           funfl_op2_done          # no
 926        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
 927funfl_op2_done:
 928        mov.b           %d0,DTAG(%a6)           # save dst optype tag
 929
 930funfl_extract:
 931
 932#$#     mov.l           FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
 933#$#     mov.l           FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
 934#$#     mov.l           FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
 935#$#     mov.l           FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6)
 936#$#     mov.l           FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6)
 937#$#     mov.l           FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6)
 938
 939        clr.l           %d0
 940        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec/mode
 941
 942        mov.b           1+EXC_CMDREG(%a6),%d1
 943        andi.w          &0x007f,%d1             # extract extension
 944
 945        andi.l          &0x00ff01ff,USER_FPSR(%a6)
 946
 947        fmov.l          &0x0,%fpcr              # zero current control regs
 948        fmov.l          &0x0,%fpsr
 949
 950        lea             FP_SRC(%a6),%a0
 951        lea             FP_DST(%a6),%a1
 952
 953# maybe we can make these entry points ONLY the OVFL entry points of each routine.
 954        mov.l           (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
 955        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
 956
 957        bfextu          EXC_CMDREG(%a6){&6:&3},%d0
 958        bsr.l           store_fpreg
 959
 960# The `060 FPU multiplier hardware is such that if the result of a
 961# multiply operation is the smallest possible normalized number
 962# (0x00000000_80000000_00000000), then the machine will take an
 963# underflow exception. Since this is incorrect, we need to check
 964# if our emulation, after re-doing the operation, decided that
 965# no underflow was called for. We do these checks only in
 966# funfl_{unfl,inex}_on() because w/ both exceptions disabled, this
 967# special case will simply exit gracefully with the correct result.
 968
 969# the exceptional possibilities we have left ourselves with are ONLY overflow
 970# and inexact. and, the inexact is such that overflow occurred and was disabled
 971# but inexact was enabled.
 972        btst            &unfl_bit,FPCR_ENABLE(%a6)
 973        bne.b           funfl_unfl_on
 974
 975funfl_chkinex:
 976        btst            &inex2_bit,FPCR_ENABLE(%a6)
 977        bne.b           funfl_inex_on
 978
 979funfl_exit:
 980        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
 981        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 982        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
 983
 984        unlk            %a6
 985#$#     add.l           &24,%sp
 986        bra.l           _fpsp_done
 987
 988# overflow is enabled AND overflow, of course, occurred. so, we have the EXOP
 989# in fp1 (don't forget to save fp0). what to do now?
 990# well, we simply have to get to go to _real_unfl()!
 991funfl_unfl_on:
 992
 993# The `060 FPU multiplier hardware is such that if the result of a
 994# multiply operation is the smallest possible normalized number
 995# (0x00000000_80000000_00000000), then the machine will take an
 996# underflow exception. Since this is incorrect, we check here to see
 997# if our emulation, after re-doing the operation, decided that
 998# no underflow was called for.
 999        btst            &unfl_bit,FPSR_EXCEPT(%a6)
1000        beq.w           funfl_chkinex
1001
1002funfl_unfl_on2:
1003        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP (fp1) to stack
1004
1005        mov.w           &0xe003,2+FP_SRC(%a6)   # save exc status
1006
1007        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
1008        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1009        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1010
1011        frestore        FP_SRC(%a6)             # do this after fmovm,other f<op>s!
1012
1013        unlk            %a6
1014
1015        bra.l           _real_unfl
1016
1017# underflow occurred but is disabled. meanwhile, inexact is enabled. Therefore,
1018# we must jump to real_inex().
1019funfl_inex_on:
1020
1021# The `060 FPU multiplier hardware is such that if the result of a
1022# multiply operation is the smallest possible normalized number
1023# (0x00000000_80000000_00000000), then the machine will take an
1024# underflow exception.
1025# But, whether bogus or not, if inexact is enabled AND it occurred,
1026# then we have to branch to real_inex.
1027
1028        btst            &inex2_bit,FPSR_EXCEPT(%a6)
1029        beq.w           funfl_exit
1030
1031funfl_inex_on2:
1032
1033        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP to stack
1034
1035        mov.b           &0xc4,1+EXC_VOFF(%a6)   # vector offset = 0xc4
1036        mov.w           &0xe001,2+FP_SRC(%a6)   # save exc status
1037
1038        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
1039        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1040        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1041
1042        frestore        FP_SRC(%a6)             # do this after fmovm,other f<op>s!
1043
1044        unlk            %a6
1045
1046        bra.l           _real_inex
1047
1048#######################################################################
1049funfl_out:
1050
1051
1052#$#     mov.l           FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
1053#$#     mov.l           FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
1054#$#     mov.l           FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
1055
1056# the src operand is definitely a NORM(!), so tag it as such
1057        mov.b           &NORM,STAG(%a6)         # set src optype tag
1058
1059        clr.l           %d0
1060        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec/mode
1061
1062        and.l           &0xffff00ff,USER_FPSR(%a6) # zero all but accured field
1063
1064        fmov.l          &0x0,%fpcr              # zero current control regs
1065        fmov.l          &0x0,%fpsr
1066
1067        lea             FP_SRC(%a6),%a0         # pass ptr to src operand
1068
1069        bsr.l           fout
1070
1071        btst            &unfl_bit,FPCR_ENABLE(%a6)
1072        bne.w           funfl_unfl_on2
1073
1074        btst            &inex2_bit,FPCR_ENABLE(%a6)
1075        bne.w           funfl_inex_on2
1076
1077        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
1078        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1079        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1080
1081        unlk            %a6
1082#$#     add.l           &24,%sp
1083
1084        btst            &0x7,(%sp)              # is trace on?
1085        beq.l           _fpsp_done              # no
1086
1087        fmov.l          %fpiar,0x8(%sp)         # "Current PC" is in FPIAR
1088        mov.w           &0x2024,0x6(%sp)        # stk fmt = 0x2; voff = 0x024
1089        bra.l           _real_trace
1090
1091#########################################################################
1092# XDEF **************************************************************** #
1093#       _fpsp_unsupp(): 060FPSP entry point for FP "Unimplemented       #
1094#                       Data Type" exception.                           #
1095#                                                                       #
1096#       This handler should be the first code executed upon taking the  #
1097#       FP Unimplemented Data Type exception in an operating system.    #
1098#                                                                       #
1099# XREF **************************************************************** #
1100#       _imem_read_{word,long}() - read instruction word/longword       #
1101#       fix_skewed_ops() - adjust src operand in fsave frame            #
1102#       set_tag_x() - determine optype of src/dst operands              #
1103#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
1104#       unnorm_fix() - change UNNORM operands to NORM or ZERO           #
1105#       load_fpn2() - load dst operand from FP regfile                  #
1106#       load_fpn1() - load src operand from FP regfile                  #
1107#       fout() - emulate an opclass 3 instruction                       #
1108#       tbl_unsupp - add of table of emulation routines for opclass 0,2 #
1109#       _real_inex() - "callout" to operating system inexact handler    #
1110#       _fpsp_done() - "callout" for exit; work all done                #
1111#       _real_trace() - "callout" for Trace enabled exception           #
1112#       funimp_skew() - adjust fsave src ops to "incorrect" value       #
1113#       _real_snan() - "callout" for SNAN exception                     #
1114#       _real_operr() - "callout" for OPERR exception                   #
1115#       _real_ovfl() - "callout" for OVFL exception                     #
1116#       _real_unfl() - "callout" for UNFL exception                     #
1117#       get_packed() - fetch packed operand from memory                 #
1118#                                                                       #
1119# INPUT *************************************************************** #
1120#       - The system stack contains the "Unimp Data Type" stk frame     #
1121#       - The fsave frame contains the ssrc op (for UNNORM/DENORM)      #
1122#                                                                       #
1123# OUTPUT ************************************************************** #
1124#       If Inexact exception (opclass 3):                               #
1125#       - The system stack is changed to an Inexact exception stk frame #
1126#       If SNAN exception (opclass 3):                                  #
1127#       - The system stack is changed to an SNAN exception stk frame    #
1128#       If OPERR exception (opclass 3):                                 #
1129#       - The system stack is changed to an OPERR exception stk frame   #
1130#       If OVFL exception (opclass 3):                                  #
1131#       - The system stack is changed to an OVFL exception stk frame    #
1132#       If UNFL exception (opclass 3):                                  #
1133#       - The system stack is changed to an UNFL exception stack frame  #
1134#       If Trace exception enabled:                                     #
1135#       - The system stack is changed to a Trace exception stack frame  #
1136#       Else: (normal case)                                             #
1137#       - Correct result has been stored as appropriate                 #
1138#                                                                       #
1139# ALGORITHM *********************************************************** #
1140#       Two main instruction types can enter here: (1) DENORM or UNNORM #
1141# unimplemented data types. These can be either opclass 0,2 or 3        #
1142# instructions, and (2) PACKED unimplemented data format instructions   #
1143# also of opclasses 0,2, or 3.                                          #
1144#       For UNNORM/DENORM opclass 0 and 2, the handler fetches the src  #
1145# operand from the fsave state frame and the dst operand (if dyadic)    #
1146# from the FP register file. The instruction is then emulated by        #
1147# choosing an emulation routine from a table of routines indexed by     #
1148# instruction type. Once the instruction has been emulated and result   #
1149# saved, then we check to see if any enabled exceptions resulted from   #
1150# instruction emulation. If none, then we exit through the "callout"    #
1151# _fpsp_done(). If there is an enabled FP exception, then we insert     #
1152# this exception into the FPU in the fsave state frame and then exit    #
1153# through _fpsp_done().                                                 #
1154#       PACKED opclass 0 and 2 is similar in how the instruction is     #
1155# emulated and exceptions handled. The differences occur in how the     #
1156# handler loads the packed op (by calling get_packed() routine) and     #
1157# by the fact that a Trace exception could be pending for PACKED ops.   #
1158# If a Trace exception is pending, then the current exception stack     #
1159# frame is changed to a Trace exception stack frame and an exit is      #
1160# made through _real_trace().                                           #
1161#       For UNNORM/DENORM opclass 3, the actual move out to memory is   #
1162# performed by calling the routine fout(). If no exception should occur #
1163# as the result of emulation, then an exit either occurs through        #
1164# _fpsp_done() or through _real_trace() if a Trace exception is pending #
1165# (a Trace stack frame must be created here, too). If an FP exception   #
1166# should occur, then we must create an exception stack frame of that    #
1167# type and jump to either _real_snan(), _real_operr(), _real_inex(),    #
1168# _real_unfl(), or _real_ovfl() as appropriate. PACKED opclass 3        #
1169# emulation is performed in a similar manner.                           #
1170#                                                                       #
1171#########################################################################
1172
1173#
1174# (1) DENORM and UNNORM (unimplemented) data types:
1175#
1176#                               post-instruction
1177#                               *****************
1178#                               *      EA       *
1179#        pre-instruction        *               *
1180#       *****************       *****************
1181#       * 0x0 *  0x0dc  *       * 0x3 *  0x0dc  *
1182#       *****************       *****************
1183#       *     Next      *       *     Next      *
1184#       *      PC       *       *      PC       *
1185#       *****************       *****************
1186#       *      SR       *       *      SR       *
1187#       *****************       *****************
1188#
1189# (2) PACKED format (unsupported) opclasses two and three:
1190#       *****************
1191#       *      EA       *
1192#       *               *
1193#       *****************
1194#       * 0x2 *  0x0dc  *
1195#       *****************
1196#       *     Next      *
1197#       *      PC       *
1198#       *****************
1199#       *      SR       *
1200#       *****************
1201#
1202        global          _fpsp_unsupp
1203_fpsp_unsupp:
1204
1205        link.w          %a6,&-LOCAL_SIZE        # init stack frame
1206
1207        fsave           FP_SRC(%a6)             # save fp state
1208
1209        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
1210        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
1211        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
1212
1213        btst            &0x5,EXC_SR(%a6)        # user or supervisor mode?
1214        bne.b           fu_s
1215fu_u:
1216        mov.l           %usp,%a0                # fetch user stack pointer
1217        mov.l           %a0,EXC_A7(%a6)         # save on stack
1218        bra.b           fu_cont
1219# if the exception is an opclass zero or two unimplemented data type
1220# exception, then the a7' calculated here is wrong since it doesn't
1221# stack an ea. however, we don't need an a7' for this case anyways.
1222fu_s:
1223        lea             0x4+EXC_EA(%a6),%a0     # load old a7'
1224        mov.l           %a0,EXC_A7(%a6)         # save on stack
1225
1226fu_cont:
1227
1228# the FPIAR holds the "current PC" of the faulting instruction
1229# the FPIAR should be set correctly for ALL exceptions passing through
1230# this point.
1231        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
1232        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
1233        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
1234        bsr.l           _imem_read_long         # fetch the instruction words
1235        mov.l           %d0,EXC_OPWORD(%a6)     # store OPWORD and EXTWORD
1236
1237############################
1238
1239        clr.b           SPCOND_FLG(%a6)         # clear special condition flag
1240
1241# Separate opclass three (fpn-to-mem) ops since they have a different
1242# stack frame and protocol.
1243        btst            &0x5,EXC_CMDREG(%a6)    # is it an fmove out?
1244        bne.w           fu_out                  # yes
1245
1246# Separate packed opclass two instructions.
1247        bfextu          EXC_CMDREG(%a6){&0:&6},%d0
1248        cmpi.b          %d0,&0x13
1249        beq.w           fu_in_pack
1250
1251
1252# I'm not sure at this point what FPSR bits are valid for this instruction.
1253# so, since the emulation routines re-create them anyways, zero exception field
1254        andi.l          &0x00ff00ff,USER_FPSR(%a6) # zero exception field
1255
1256        fmov.l          &0x0,%fpcr              # zero current control regs
1257        fmov.l          &0x0,%fpsr
1258
1259# Opclass two w/ memory-to-fpn operation will have an incorrect extended
1260# precision format if the src format was single or double and the
1261# source data type was an INF, NAN, DENORM, or UNNORM
1262        lea             FP_SRC(%a6),%a0         # pass ptr to input
1263        bsr.l           fix_skewed_ops
1264
1265# we don't know whether the src operand or the dst operand (or both) is the
1266# UNNORM or DENORM. call the function that tags the operand type. if the
1267# input is an UNNORM, then convert it to a NORM, DENORM, or ZERO.
1268        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
1269        bsr.l           set_tag_x               # tag the operand type
1270        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
1271        bne.b           fu_op2                  # no
1272        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
1273
1274fu_op2:
1275        mov.b           %d0,STAG(%a6)           # save src optype tag
1276
1277        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1278
1279# bit five of the fp extension word separates the monadic and dyadic operations
1280# at this point
1281        btst            &0x5,1+EXC_CMDREG(%a6)  # is operation monadic or dyadic?
1282        beq.b           fu_extract              # monadic
1283        cmpi.b          1+EXC_CMDREG(%a6),&0x3a # is operation an ftst?
1284        beq.b           fu_extract              # yes, so it's monadic, too
1285
1286        bsr.l           load_fpn2               # load dst into FP_DST
1287
1288        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
1289        bsr.l           set_tag_x               # tag the operand type
1290        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
1291        bne.b           fu_op2_done             # no
1292        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
1293fu_op2_done:
1294        mov.b           %d0,DTAG(%a6)           # save dst optype tag
1295
1296fu_extract:
1297        clr.l           %d0
1298        mov.b           FPCR_MODE(%a6),%d0      # fetch rnd mode/prec
1299
1300        bfextu          1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension
1301
1302        lea             FP_SRC(%a6),%a0
1303        lea             FP_DST(%a6),%a1
1304
1305        mov.l           (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr
1306        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
1307
1308#
1309# Exceptions in order of precedence:
1310#       BSUN    : none
1311#       SNAN    : all dyadic ops
1312#       OPERR   : fsqrt(-NORM)
1313#       OVFL    : all except ftst,fcmp
1314#       UNFL    : all except ftst,fcmp
1315#       DZ      : fdiv
1316#       INEX2   : all except ftst,fcmp
1317#       INEX1   : none (packed doesn't go through here)
1318#
1319
1320# we determine the highest priority exception(if any) set by the
1321# emulation routine that has also been enabled by the user.
1322        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions set
1323        bne.b           fu_in_ena               # some are enabled
1324
1325fu_in_cont:
1326# fcmp and ftst do not store any result.
1327        mov.b           1+EXC_CMDREG(%a6),%d0   # fetch extension
1328        andi.b          &0x38,%d0               # extract bits 3-5
1329        cmpi.b          %d0,&0x38               # is instr fcmp or ftst?
1330        beq.b           fu_in_exit              # yes
1331
1332        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1333        bsr.l           store_fpreg             # store the result
1334
1335fu_in_exit:
1336
1337        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1338        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1339        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1340
1341        unlk            %a6
1342
1343        bra.l           _fpsp_done
1344
1345fu_in_ena:
1346        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enabled
1347        bfffo           %d0{&24:&8},%d0         # find highest priority exception
1348        bne.b           fu_in_exc               # there is at least one set
1349
1350#
1351# No exceptions occurred that were also enabled. Now:
1352#
1353#       if (OVFL && ovfl_disabled && inexact_enabled) {
1354#           branch to _real_inex() (even if the result was exact!);
1355#       } else {
1356#           save the result in the proper fp reg (unless the op is fcmp or ftst);
1357#           return;
1358#       }
1359#
1360        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
1361        beq.b           fu_in_cont              # no
1362
1363fu_in_ovflchk:
1364        btst            &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
1365        beq.b           fu_in_cont              # no
1366        bra.w           fu_in_exc_ovfl          # go insert overflow frame
1367
1368#
1369# An exception occurred and that exception was enabled:
1370#
1371#       shift enabled exception field into lo byte of d0;
1372#       if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) ||
1373#           ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) {
1374#               /*
1375#                * this is the case where we must call _real_inex() now or else
1376#                * there will be no other way to pass it the exceptional operand
1377#                */
1378#               call _real_inex();
1379#       } else {
1380#               restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU;
1381#       }
1382#
1383fu_in_exc:
1384        subi.l          &24,%d0                 # fix offset to be 0-8
1385        cmpi.b          %d0,&0x6                # is exception INEX? (6)
1386        bne.b           fu_in_exc_exit          # no
1387
1388# the enabled exception was inexact
1389        btst            &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur?
1390        bne.w           fu_in_exc_unfl          # yes
1391        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur?
1392        bne.w           fu_in_exc_ovfl          # yes
1393
1394# here, we insert the correct fsave status value into the fsave frame for the
1395# corresponding exception. the operand in the fsave frame should be the original
1396# src operand.
1397fu_in_exc_exit:
1398        mov.l           %d0,-(%sp)              # save d0
1399        bsr.l           funimp_skew             # skew sgl or dbl inputs
1400        mov.l           (%sp)+,%d0              # restore d0
1401
1402        mov.w           (tbl_except.b,%pc,%d0.w*2),2+FP_SRC(%a6) # create exc status
1403
1404        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1405        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1406        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1407
1408        frestore        FP_SRC(%a6)             # restore src op
1409
1410        unlk            %a6
1411
1412        bra.l           _fpsp_done
1413
1414tbl_except:
1415        short           0xe000,0xe006,0xe004,0xe005
1416        short           0xe003,0xe002,0xe001,0xe001
1417
1418fu_in_exc_unfl:
1419        mov.w           &0x4,%d0
1420        bra.b           fu_in_exc_exit
1421fu_in_exc_ovfl:
1422        mov.w           &0x03,%d0
1423        bra.b           fu_in_exc_exit
1424
1425# If the input operand to this operation was opclass two and a single
1426# or double precision denorm, inf, or nan, the operand needs to be
1427# "corrected" in order to have the proper equivalent extended precision
1428# number.
1429        global          fix_skewed_ops
1430fix_skewed_ops:
1431        bfextu          EXC_CMDREG(%a6){&0:&6},%d0 # extract opclass,src fmt
1432        cmpi.b          %d0,&0x11               # is class = 2 & fmt = sgl?
1433        beq.b           fso_sgl                 # yes
1434        cmpi.b          %d0,&0x15               # is class = 2 & fmt = dbl?
1435        beq.b           fso_dbl                 # yes
1436        rts                                     # no
1437
1438fso_sgl:
1439        mov.w           LOCAL_EX(%a0),%d0       # fetch src exponent
1440        andi.w          &0x7fff,%d0             # strip sign
1441        cmpi.w          %d0,&0x3f80             # is |exp| == $3f80?
1442        beq.b           fso_sgl_dnrm_zero       # yes
1443        cmpi.w          %d0,&0x407f             # no; is |exp| == $407f?
1444        beq.b           fso_infnan              # yes
1445        rts                                     # no
1446
1447fso_sgl_dnrm_zero:
1448        andi.l          &0x7fffffff,LOCAL_HI(%a0) # clear j-bit
1449        beq.b           fso_zero                # it's a skewed zero
1450fso_sgl_dnrm:
1451# here, we count on norm not to alter a0...
1452        bsr.l           norm                    # normalize mantissa
1453        neg.w           %d0                     # -shft amt
1454        addi.w          &0x3f81,%d0             # adjust new exponent
1455        andi.w          &0x8000,LOCAL_EX(%a0)   # clear old exponent
1456        or.w            %d0,LOCAL_EX(%a0)       # insert new exponent
1457        rts
1458
1459fso_zero:
1460        andi.w          &0x8000,LOCAL_EX(%a0)   # clear bogus exponent
1461        rts
1462
1463fso_infnan:
1464        andi.b          &0x7f,LOCAL_HI(%a0)     # clear j-bit
1465        ori.w           &0x7fff,LOCAL_EX(%a0)   # make exponent = $7fff
1466        rts
1467
1468fso_dbl:
1469        mov.w           LOCAL_EX(%a0),%d0       # fetch src exponent
1470        andi.w          &0x7fff,%d0             # strip sign
1471        cmpi.w          %d0,&0x3c00             # is |exp| == $3c00?
1472        beq.b           fso_dbl_dnrm_zero       # yes
1473        cmpi.w          %d0,&0x43ff             # no; is |exp| == $43ff?
1474        beq.b           fso_infnan              # yes
1475        rts                                     # no
1476
1477fso_dbl_dnrm_zero:
1478        andi.l          &0x7fffffff,LOCAL_HI(%a0) # clear j-bit
1479        bne.b           fso_dbl_dnrm            # it's a skewed denorm
1480        tst.l           LOCAL_LO(%a0)           # is it a zero?
1481        beq.b           fso_zero                # yes
1482fso_dbl_dnrm:
1483# here, we count on norm not to alter a0...
1484        bsr.l           norm                    # normalize mantissa
1485        neg.w           %d0                     # -shft amt
1486        addi.w          &0x3c01,%d0             # adjust new exponent
1487        andi.w          &0x8000,LOCAL_EX(%a0)   # clear old exponent
1488        or.w            %d0,LOCAL_EX(%a0)       # insert new exponent
1489        rts
1490
1491#################################################################
1492
1493# fmove out took an unimplemented data type exception.
1494# the src operand is in FP_SRC. Call _fout() to write out the result and
1495# to determine which exceptions, if any, to take.
1496fu_out:
1497
1498# Separate packed move outs from the UNNORM and DENORM move outs.
1499        bfextu          EXC_CMDREG(%a6){&3:&3},%d0
1500        cmpi.b          %d0,&0x3
1501        beq.w           fu_out_pack
1502        cmpi.b          %d0,&0x7
1503        beq.w           fu_out_pack
1504
1505
1506# I'm not sure at this point what FPSR bits are valid for this instruction.
1507# so, since the emulation routines re-create them anyways, zero exception field.
1508# fmove out doesn't affect ccodes.
1509        and.l           &0xffff00ff,USER_FPSR(%a6) # zero exception field
1510
1511        fmov.l          &0x0,%fpcr              # zero current control regs
1512        fmov.l          &0x0,%fpsr
1513
1514# the src can ONLY be a DENORM or an UNNORM! so, don't make any big subroutine
1515# call here. just figure out what it is...
1516        mov.w           FP_SRC_EX(%a6),%d0      # get exponent
1517        andi.w          &0x7fff,%d0             # strip sign
1518        beq.b           fu_out_denorm           # it's a DENORM
1519
1520        lea             FP_SRC(%a6),%a0
1521        bsr.l           unnorm_fix              # yes; fix it
1522
1523        mov.b           %d0,STAG(%a6)
1524
1525        bra.b           fu_out_cont
1526fu_out_denorm:
1527        mov.b           &DENORM,STAG(%a6)
1528fu_out_cont:
1529
1530        clr.l           %d0
1531        mov.b           FPCR_MODE(%a6),%d0      # fetch rnd mode/prec
1532
1533        lea             FP_SRC(%a6),%a0         # pass ptr to src operand
1534
1535        mov.l           (%a6),EXC_A6(%a6)       # in case a6 changes
1536        bsr.l           fout                    # call fmove out routine
1537
1538# Exceptions in order of precedence:
1539#       BSUN    : none
1540#       SNAN    : none
1541#       OPERR   : fmove.{b,w,l} out of large UNNORM
1542#       OVFL    : fmove.{s,d}
1543#       UNFL    : fmove.{s,d,x}
1544#       DZ      : none
1545#       INEX2   : all
1546#       INEX1   : none (packed doesn't travel through here)
1547
1548# determine the highest priority exception(if any) set by the
1549# emulation routine that has also been enabled by the user.
1550        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions enabled
1551        bne.w           fu_out_ena              # some are enabled
1552
1553fu_out_done:
1554
1555        mov.l           EXC_A6(%a6),(%a6)       # in case a6 changed
1556
1557# on extended precision opclass three instructions using pre-decrement or
1558# post-increment addressing mode, the address register is not updated. is the
1559# address register was the stack pointer used from user mode, then let's update
1560# it here. if it was used from supervisor mode, then we have to handle this
1561# as a special case.
1562        btst            &0x5,EXC_SR(%a6)
1563        bne.b           fu_out_done_s
1564
1565        mov.l           EXC_A7(%a6),%a0         # restore a7
1566        mov.l           %a0,%usp
1567
1568fu_out_done_cont:
1569        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1570        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1571        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1572
1573        unlk            %a6
1574
1575        btst            &0x7,(%sp)              # is trace on?
1576        bne.b           fu_out_trace            # yes
1577
1578        bra.l           _fpsp_done
1579
1580# is the ea mode pre-decrement of the stack pointer from supervisor mode?
1581# ("fmov.x fpm,-(a7)") if so,
1582fu_out_done_s:
1583        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
1584        bne.b           fu_out_done_cont
1585
1586# the extended precision result is still in fp0. but, we need to save it
1587# somewhere on the stack until we can copy it to its final resting place.
1588# here, we're counting on the top of the stack to be the old place-holders
1589# for fp0/fp1 which have already been restored. that way, we can write
1590# over those destinations with the shifted stack frame.
1591        fmovm.x         &0x80,FP_SRC(%a6)       # put answer on stack
1592
1593        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1594        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1595        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1596
1597        mov.l           (%a6),%a6               # restore frame pointer
1598
1599        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
1600        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
1601
1602# now, copy the result to the proper place on the stack
1603        mov.l           LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
1604        mov.l           LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
1605        mov.l           LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
1606
1607        add.l           &LOCAL_SIZE-0x8,%sp
1608
1609        btst            &0x7,(%sp)
1610        bne.b           fu_out_trace
1611
1612        bra.l           _fpsp_done
1613
1614fu_out_ena:
1615        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enabled
1616        bfffo           %d0{&24:&8},%d0         # find highest priority exception
1617        bne.b           fu_out_exc              # there is at least one set
1618
1619# no exceptions were set.
1620# if a disabled overflow occurred and inexact was enabled but the result
1621# was exact, then a branch to _real_inex() is made.
1622        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
1623        beq.w           fu_out_done             # no
1624
1625fu_out_ovflchk:
1626        btst            &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
1627        beq.w           fu_out_done             # no
1628        bra.w           fu_inex                 # yes
1629
1630#
1631# The fp move out that took the "Unimplemented Data Type" exception was
1632# being traced. Since the stack frames are similar, get the "current" PC
1633# from FPIAR and put it in the trace stack frame then jump to _real_trace().
1634#
1635#                 UNSUPP FRAME             TRACE FRAME
1636#               *****************       *****************
1637#               *      EA       *       *    Current    *
1638#               *               *       *      PC       *
1639#               *****************       *****************
1640#               * 0x3 *  0x0dc  *       * 0x2 *  0x024  *
1641#               *****************       *****************
1642#               *     Next      *       *     Next      *
1643#               *      PC       *       *      PC       *
1644#               *****************       *****************
1645#               *      SR       *       *      SR       *
1646#               *****************       *****************
1647#
1648fu_out_trace:
1649        mov.w           &0x2024,0x6(%sp)
1650        fmov.l          %fpiar,0x8(%sp)
1651        bra.l           _real_trace
1652
1653# an exception occurred and that exception was enabled.
1654fu_out_exc:
1655        subi.l          &24,%d0                 # fix offset to be 0-8
1656
1657# we don't mess with the existing fsave frame. just re-insert it and
1658# jump to the "_real_{}()" handler...
1659        mov.w           (tbl_fu_out.b,%pc,%d0.w*2),%d0
1660        jmp             (tbl_fu_out.b,%pc,%d0.w*1)
1661
1662        swbeg           &0x8
1663tbl_fu_out:
1664        short           tbl_fu_out      - tbl_fu_out    # BSUN can't happen
1665        short           tbl_fu_out      - tbl_fu_out    # SNAN can't happen
1666        short           fu_operr        - tbl_fu_out    # OPERR
1667        short           fu_ovfl         - tbl_fu_out    # OVFL
1668        short           fu_unfl         - tbl_fu_out    # UNFL
1669        short           tbl_fu_out      - tbl_fu_out    # DZ can't happen
1670        short           fu_inex         - tbl_fu_out    # INEX2
1671        short           tbl_fu_out      - tbl_fu_out    # INEX1 won't make it here
1672
1673# for snan,operr,ovfl,unfl, src op is still in FP_SRC so just
1674# frestore it.
1675fu_snan:
1676        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1677        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1678        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1679
1680        mov.w           &0x30d8,EXC_VOFF(%a6)   # vector offset = 0xd8
1681        mov.w           &0xe006,2+FP_SRC(%a6)
1682
1683        frestore        FP_SRC(%a6)
1684
1685        unlk            %a6
1686
1687
1688        bra.l           _real_snan
1689
1690fu_operr:
1691        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1692        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1693        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1694
1695        mov.w           &0x30d0,EXC_VOFF(%a6)   # vector offset = 0xd0
1696        mov.w           &0xe004,2+FP_SRC(%a6)
1697
1698        frestore        FP_SRC(%a6)
1699
1700        unlk            %a6
1701
1702
1703        bra.l           _real_operr
1704
1705fu_ovfl:
1706        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP to the stack
1707
1708        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1709        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1710        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1711
1712        mov.w           &0x30d4,EXC_VOFF(%a6)   # vector offset = 0xd4
1713        mov.w           &0xe005,2+FP_SRC(%a6)
1714
1715        frestore        FP_SRC(%a6)             # restore EXOP
1716
1717        unlk            %a6
1718
1719        bra.l           _real_ovfl
1720
1721# underflow can happen for extended precision. extended precision opclass
1722# three instruction exceptions don't update the stack pointer. so, if the
1723# exception occurred from user mode, then simply update a7 and exit normally.
1724# if the exception occurred from supervisor mode, check if
1725fu_unfl:
1726        mov.l           EXC_A6(%a6),(%a6)       # restore a6
1727
1728        btst            &0x5,EXC_SR(%a6)
1729        bne.w           fu_unfl_s
1730
1731        mov.l           EXC_A7(%a6),%a0         # restore a7 whether we need
1732        mov.l           %a0,%usp                # to or not...
1733
1734fu_unfl_cont:
1735        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP to the stack
1736
1737        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1738        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1739        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1740
1741        mov.w           &0x30cc,EXC_VOFF(%a6)   # vector offset = 0xcc
1742        mov.w           &0xe003,2+FP_SRC(%a6)
1743
1744        frestore        FP_SRC(%a6)             # restore EXOP
1745
1746        unlk            %a6
1747
1748        bra.l           _real_unfl
1749
1750fu_unfl_s:
1751        cmpi.b          SPCOND_FLG(%a6),&mda7_flg # was the <ea> mode -(sp)?
1752        bne.b           fu_unfl_cont
1753
1754# the extended precision result is still in fp0. but, we need to save it
1755# somewhere on the stack until we can copy it to its final resting place
1756# (where the exc frame is currently). make sure it's not at the top of the
1757# frame or it will get overwritten when the exc stack frame is shifted "down".
1758        fmovm.x         &0x80,FP_SRC(%a6)       # put answer on stack
1759        fmovm.x         &0x40,FP_DST(%a6)       # put EXOP on stack
1760
1761        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1762        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1763        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1764
1765        mov.w           &0x30cc,EXC_VOFF(%a6)   # vector offset = 0xcc
1766        mov.w           &0xe003,2+FP_DST(%a6)
1767
1768        frestore        FP_DST(%a6)             # restore EXOP
1769
1770        mov.l           (%a6),%a6               # restore frame pointer
1771
1772        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
1773        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
1774        mov.l           LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
1775
1776# now, copy the result to the proper place on the stack
1777        mov.l           LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
1778        mov.l           LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
1779        mov.l           LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
1780
1781        add.l           &LOCAL_SIZE-0x8,%sp
1782
1783        bra.l           _real_unfl
1784
1785# fmove in and out enter here.
1786fu_inex:
1787        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP to the stack
1788
1789        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1790        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1791        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1792
1793        mov.w           &0x30c4,EXC_VOFF(%a6)   # vector offset = 0xc4
1794        mov.w           &0xe001,2+FP_SRC(%a6)
1795
1796        frestore        FP_SRC(%a6)             # restore EXOP
1797
1798        unlk            %a6
1799
1800
1801        bra.l           _real_inex
1802
1803#########################################################################
1804#########################################################################
1805fu_in_pack:
1806
1807
1808# I'm not sure at this point what FPSR bits are valid for this instruction.
1809# so, since the emulation routines re-create them anyways, zero exception field
1810        andi.l          &0x0ff00ff,USER_FPSR(%a6) # zero exception field
1811
1812        fmov.l          &0x0,%fpcr              # zero current control regs
1813        fmov.l          &0x0,%fpsr
1814
1815        bsr.l           get_packed              # fetch packed src operand
1816
1817        lea             FP_SRC(%a6),%a0         # pass ptr to src
1818        bsr.l           set_tag_x               # set src optype tag
1819
1820        mov.b           %d0,STAG(%a6)           # save src optype tag
1821
1822        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1823
1824# bit five of the fp extension word separates the monadic and dyadic operations
1825# at this point
1826        btst            &0x5,1+EXC_CMDREG(%a6)  # is operation monadic or dyadic?
1827        beq.b           fu_extract_p            # monadic
1828        cmpi.b          1+EXC_CMDREG(%a6),&0x3a # is operation an ftst?
1829        beq.b           fu_extract_p            # yes, so it's monadic, too
1830
1831        bsr.l           load_fpn2               # load dst into FP_DST
1832
1833        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
1834        bsr.l           set_tag_x               # tag the operand type
1835        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
1836        bne.b           fu_op2_done_p           # no
1837        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
1838fu_op2_done_p:
1839        mov.b           %d0,DTAG(%a6)           # save dst optype tag
1840
1841fu_extract_p:
1842        clr.l           %d0
1843        mov.b           FPCR_MODE(%a6),%d0      # fetch rnd mode/prec
1844
1845        bfextu          1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension
1846
1847        lea             FP_SRC(%a6),%a0
1848        lea             FP_DST(%a6),%a1
1849
1850        mov.l           (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr
1851        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
1852
1853#
1854# Exceptions in order of precedence:
1855#       BSUN    : none
1856#       SNAN    : all dyadic ops
1857#       OPERR   : fsqrt(-NORM)
1858#       OVFL    : all except ftst,fcmp
1859#       UNFL    : all except ftst,fcmp
1860#       DZ      : fdiv
1861#       INEX2   : all except ftst,fcmp
1862#       INEX1   : all
1863#
1864
1865# we determine the highest priority exception(if any) set by the
1866# emulation routine that has also been enabled by the user.
1867        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions enabled
1868        bne.w           fu_in_ena_p             # some are enabled
1869
1870fu_in_cont_p:
1871# fcmp and ftst do not store any result.
1872        mov.b           1+EXC_CMDREG(%a6),%d0   # fetch extension
1873        andi.b          &0x38,%d0               # extract bits 3-5
1874        cmpi.b          %d0,&0x38               # is instr fcmp or ftst?
1875        beq.b           fu_in_exit_p            # yes
1876
1877        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1878        bsr.l           store_fpreg             # store the result
1879
1880fu_in_exit_p:
1881
1882        btst            &0x5,EXC_SR(%a6)        # user or supervisor?
1883        bne.w           fu_in_exit_s_p          # supervisor
1884
1885        mov.l           EXC_A7(%a6),%a0         # update user a7
1886        mov.l           %a0,%usp
1887
1888fu_in_exit_cont_p:
1889        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1890        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1891        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1892
1893        unlk            %a6                     # unravel stack frame
1894
1895        btst            &0x7,(%sp)              # is trace on?
1896        bne.w           fu_trace_p              # yes
1897
1898        bra.l           _fpsp_done              # exit to os
1899
1900# the exception occurred in supervisor mode. check to see if the
1901# addressing mode was (a7)+. if so, we'll need to shift the
1902# stack frame "up".
1903fu_in_exit_s_p:
1904        btst            &mia7_bit,SPCOND_FLG(%a6) # was ea mode (a7)+
1905        beq.b           fu_in_exit_cont_p       # no
1906
1907        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1908        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1909        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1910
1911        unlk            %a6                     # unravel stack frame
1912
1913# shift the stack frame "up". we don't really care about the <ea> field.
1914        mov.l           0x4(%sp),0x10(%sp)
1915        mov.l           0x0(%sp),0xc(%sp)
1916        add.l           &0xc,%sp
1917
1918        btst            &0x7,(%sp)              # is trace on?
1919        bne.w           fu_trace_p              # yes
1920
1921        bra.l           _fpsp_done              # exit to os
1922
1923fu_in_ena_p:
1924        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enabled & set
1925        bfffo           %d0{&24:&8},%d0         # find highest priority exception
1926        bne.b           fu_in_exc_p             # at least one was set
1927
1928#
1929# No exceptions occurred that were also enabled. Now:
1930#
1931#       if (OVFL && ovfl_disabled && inexact_enabled) {
1932#           branch to _real_inex() (even if the result was exact!);
1933#       } else {
1934#           save the result in the proper fp reg (unless the op is fcmp or ftst);
1935#           return;
1936#       }
1937#
1938        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
1939        beq.w           fu_in_cont_p            # no
1940
1941fu_in_ovflchk_p:
1942        btst            &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
1943        beq.w           fu_in_cont_p            # no
1944        bra.w           fu_in_exc_ovfl_p        # do _real_inex() now
1945
1946#
1947# An exception occurred and that exception was enabled:
1948#
1949#       shift enabled exception field into lo byte of d0;
1950#       if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) ||
1951#           ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) {
1952#               /*
1953#                * this is the case where we must call _real_inex() now or else
1954#                * there will be no other way to pass it the exceptional operand
1955#                */
1956#               call _real_inex();
1957#       } else {
1958#               restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU;
1959#       }
1960#
1961fu_in_exc_p:
1962        subi.l          &24,%d0                 # fix offset to be 0-8
1963        cmpi.b          %d0,&0x6                # is exception INEX? (6 or 7)
1964        blt.b           fu_in_exc_exit_p        # no
1965
1966# the enabled exception was inexact
1967        btst            &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur?
1968        bne.w           fu_in_exc_unfl_p        # yes
1969        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur?
1970        bne.w           fu_in_exc_ovfl_p        # yes
1971
1972# here, we insert the correct fsave status value into the fsave frame for the
1973# corresponding exception. the operand in the fsave frame should be the original
1974# src operand.
1975# as a reminder for future predicted pain and agony, we are passing in fsave the
1976# "non-skewed" operand for cases of sgl and dbl src INFs,NANs, and DENORMs.
1977# this is INCORRECT for enabled SNAN which would give to the user the skewed SNAN!!!
1978fu_in_exc_exit_p:
1979        btst            &0x5,EXC_SR(%a6)        # user or supervisor?
1980        bne.w           fu_in_exc_exit_s_p      # supervisor
1981
1982        mov.l           EXC_A7(%a6),%a0         # update user a7
1983        mov.l           %a0,%usp
1984
1985fu_in_exc_exit_cont_p:
1986        mov.w           (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6)
1987
1988        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1989        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1990        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1991
1992        frestore        FP_SRC(%a6)             # restore src op
1993
1994        unlk            %a6
1995
1996        btst            &0x7,(%sp)              # is trace enabled?
1997        bne.w           fu_trace_p              # yes
1998
1999        bra.l           _fpsp_done
2000
2001tbl_except_p:
2002        short           0xe000,0xe006,0xe004,0xe005
2003        short           0xe003,0xe002,0xe001,0xe001
2004
2005fu_in_exc_ovfl_p:
2006        mov.w           &0x3,%d0
2007        bra.w           fu_in_exc_exit_p
2008
2009fu_in_exc_unfl_p:
2010        mov.w           &0x4,%d0
2011        bra.w           fu_in_exc_exit_p
2012
2013fu_in_exc_exit_s_p:
2014        btst            &mia7_bit,SPCOND_FLG(%a6)
2015        beq.b           fu_in_exc_exit_cont_p
2016
2017        mov.w           (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6)
2018
2019        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2020        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2021        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2022
2023        frestore        FP_SRC(%a6)             # restore src op
2024
2025        unlk            %a6                     # unravel stack frame
2026
2027# shift stack frame "up". who cares about <ea> field.
2028        mov.l           0x4(%sp),0x10(%sp)
2029        mov.l           0x0(%sp),0xc(%sp)
2030        add.l           &0xc,%sp
2031
2032        btst            &0x7,(%sp)              # is trace on?
2033        bne.b           fu_trace_p              # yes
2034
2035        bra.l           _fpsp_done              # exit to os
2036
2037#
2038# The opclass two PACKED instruction that took an "Unimplemented Data Type"
2039# exception was being traced. Make the "current" PC the FPIAR and put it in the
2040# trace stack frame then jump to _real_trace().
2041#
2042#                 UNSUPP FRAME             TRACE FRAME
2043#               *****************       *****************
2044#               *      EA       *       *    Current    *
2045#               *               *       *      PC       *
2046#               *****************       *****************
2047#               * 0x2 * 0x0dc   *       * 0x2 *  0x024  *
2048#               *****************       *****************
2049#               *     Next      *       *     Next      *
2050#               *      PC       *       *      PC       *
2051#               *****************       *****************
2052#               *      SR       *       *      SR       *
2053#               *****************       *****************
2054fu_trace_p:
2055        mov.w           &0x2024,0x6(%sp)
2056        fmov.l          %fpiar,0x8(%sp)
2057
2058        bra.l           _real_trace
2059
2060#########################################################
2061#########################################################
2062fu_out_pack:
2063
2064
2065# I'm not sure at this point what FPSR bits are valid for this instruction.
2066# so, since the emulation routines re-create them anyways, zero exception field.
2067# fmove out doesn't affect ccodes.
2068        and.l           &0xffff00ff,USER_FPSR(%a6) # zero exception field
2069
2070        fmov.l          &0x0,%fpcr              # zero current control regs
2071        fmov.l          &0x0,%fpsr
2072
2073        bfextu          EXC_CMDREG(%a6){&6:&3},%d0
2074        bsr.l           load_fpn1
2075
2076# unlike other opclass 3, unimplemented data type exceptions, packed must be
2077# able to detect all operand types.
2078        lea             FP_SRC(%a6),%a0
2079        bsr.l           set_tag_x               # tag the operand type
2080        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
2081        bne.b           fu_op2_p                # no
2082        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
2083
2084fu_op2_p:
2085        mov.b           %d0,STAG(%a6)           # save src optype tag
2086
2087        clr.l           %d0
2088        mov.b           FPCR_MODE(%a6),%d0      # fetch rnd mode/prec
2089
2090        lea             FP_SRC(%a6),%a0         # pass ptr to src operand
2091
2092        mov.l           (%a6),EXC_A6(%a6)       # in case a6 changes
2093        bsr.l           fout                    # call fmove out routine
2094
2095# Exceptions in order of precedence:
2096#       BSUN    : no
2097#       SNAN    : yes
2098#       OPERR   : if ((k_factor > +17) || (dec. exp exceeds 3 digits))
2099#       OVFL    : no
2100#       UNFL    : no
2101#       DZ      : no
2102#       INEX2   : yes
2103#       INEX1   : no
2104
2105# determine the highest priority exception(if any) set by the
2106# emulation routine that has also been enabled by the user.
2107        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions enabled
2108        bne.w           fu_out_ena_p            # some are enabled
2109
2110fu_out_exit_p:
2111        mov.l           EXC_A6(%a6),(%a6)       # restore a6
2112
2113        btst            &0x5,EXC_SR(%a6)        # user or supervisor?
2114        bne.b           fu_out_exit_s_p         # supervisor
2115
2116        mov.l           EXC_A7(%a6),%a0         # update user a7
2117        mov.l           %a0,%usp
2118
2119fu_out_exit_cont_p:
2120        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2121        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2122        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2123
2124        unlk            %a6                     # unravel stack frame
2125
2126        btst            &0x7,(%sp)              # is trace on?
2127        bne.w           fu_trace_p              # yes
2128
2129        bra.l           _fpsp_done              # exit to os
2130
2131# the exception occurred in supervisor mode. check to see if the
2132# addressing mode was -(a7). if so, we'll need to shift the
2133# stack frame "down".
2134fu_out_exit_s_p:
2135        btst            &mda7_bit,SPCOND_FLG(%a6) # was ea mode -(a7)
2136        beq.b           fu_out_exit_cont_p      # no
2137
2138        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2139        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2140        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2141
2142        mov.l           (%a6),%a6               # restore frame pointer
2143
2144        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2145        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2146
2147# now, copy the result to the proper place on the stack
2148        mov.l           LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
2149        mov.l           LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
2150        mov.l           LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
2151
2152        add.l           &LOCAL_SIZE-0x8,%sp
2153
2154        btst            &0x7,(%sp)
2155        bne.w           fu_trace_p
2156
2157        bra.l           _fpsp_done
2158
2159fu_out_ena_p:
2160        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enabled
2161        bfffo           %d0{&24:&8},%d0         # find highest priority exception
2162        beq.w           fu_out_exit_p
2163
2164        mov.l           EXC_A6(%a6),(%a6)       # restore a6
2165
2166# an exception occurred and that exception was enabled.
2167# the only exception possible on packed move out are INEX, OPERR, and SNAN.
2168fu_out_exc_p:
2169        cmpi.b          %d0,&0x1a
2170        bgt.w           fu_inex_p2
2171        beq.w           fu_operr_p
2172
2173fu_snan_p:
2174        btst            &0x5,EXC_SR(%a6)
2175        bne.b           fu_snan_s_p
2176
2177        mov.l           EXC_A7(%a6),%a0
2178        mov.l           %a0,%usp
2179        bra.w           fu_snan
2180
2181fu_snan_s_p:
2182        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
2183        bne.w           fu_snan
2184
2185# the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
2186# the strategy is to move the exception frame "down" 12 bytes. then, we
2187# can store the default result where the exception frame was.
2188        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2189        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2190        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2191
2192        mov.w           &0x30d8,EXC_VOFF(%a6)   # vector offset = 0xd0
2193        mov.w           &0xe006,2+FP_SRC(%a6)   # set fsave status
2194
2195        frestore        FP_SRC(%a6)             # restore src operand
2196
2197        mov.l           (%a6),%a6               # restore frame pointer
2198
2199        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2200        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2201        mov.l           LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
2202
2203# now, we copy the default result to its proper location
2204        mov.l           LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
2205        mov.l           LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
2206        mov.l           LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
2207
2208        add.l           &LOCAL_SIZE-0x8,%sp
2209
2210
2211        bra.l           _real_snan
2212
2213fu_operr_p:
2214        btst            &0x5,EXC_SR(%a6)
2215        bne.w           fu_operr_p_s
2216
2217        mov.l           EXC_A7(%a6),%a0
2218        mov.l           %a0,%usp
2219        bra.w           fu_operr
2220
2221fu_operr_p_s:
2222        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
2223        bne.w           fu_operr
2224
2225# the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
2226# the strategy is to move the exception frame "down" 12 bytes. then, we
2227# can store the default result where the exception frame was.
2228        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2229        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2230        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2231
2232        mov.w           &0x30d0,EXC_VOFF(%a6)   # vector offset = 0xd0
2233        mov.w           &0xe004,2+FP_SRC(%a6)   # set fsave status
2234
2235        frestore        FP_SRC(%a6)             # restore src operand
2236
2237        mov.l           (%a6),%a6               # restore frame pointer
2238
2239        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2240        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2241        mov.l           LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
2242
2243# now, we copy the default result to its proper location
2244        mov.l           LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
2245        mov.l           LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
2246        mov.l           LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
2247
2248        add.l           &LOCAL_SIZE-0x8,%sp
2249
2250
2251        bra.l           _real_operr
2252
2253fu_inex_p2:
2254        btst            &0x5,EXC_SR(%a6)
2255        bne.w           fu_inex_s_p2
2256
2257        mov.l           EXC_A7(%a6),%a0
2258        mov.l           %a0,%usp
2259        bra.w           fu_inex
2260
2261fu_inex_s_p2:
2262        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
2263        bne.w           fu_inex
2264
2265# the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
2266# the strategy is to move the exception frame "down" 12 bytes. then, we
2267# can store the default result where the exception frame was.
2268        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2269        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2270        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2271
2272        mov.w           &0x30c4,EXC_VOFF(%a6)   # vector offset = 0xc4
2273        mov.w           &0xe001,2+FP_SRC(%a6)   # set fsave status
2274
2275        frestore        FP_SRC(%a6)             # restore src operand
2276
2277        mov.l           (%a6),%a6               # restore frame pointer
2278
2279        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2280        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2281        mov.l           LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
2282
2283# now, we copy the default result to its proper location
2284        mov.l           LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
2285        mov.l           LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
2286        mov.l           LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
2287
2288        add.l           &LOCAL_SIZE-0x8,%sp
2289
2290
2291        bra.l           _real_inex
2292
2293#########################################################################
2294
2295#
2296# if we're stuffing a source operand back into an fsave frame then we
2297# have to make sure that for single or double source operands that the
2298# format stuffed is as weird as the hardware usually makes it.
2299#
2300        global          funimp_skew
2301funimp_skew:
2302        bfextu          EXC_EXTWORD(%a6){&3:&3},%d0 # extract src specifier
2303        cmpi.b          %d0,&0x1                # was src sgl?
2304        beq.b           funimp_skew_sgl         # yes
2305        cmpi.b          %d0,&0x5                # was src dbl?
2306        beq.b           funimp_skew_dbl         # yes
2307        rts
2308
2309funimp_skew_sgl:
2310        mov.w           FP_SRC_EX(%a6),%d0      # fetch DENORM exponent
2311        andi.w          &0x7fff,%d0             # strip sign
2312        beq.b           funimp_skew_sgl_not
2313        cmpi.w          %d0,&0x3f80
2314        bgt.b           funimp_skew_sgl_not
2315        neg.w           %d0                     # make exponent negative
2316        addi.w          &0x3f81,%d0             # find amt to shift
2317        mov.l           FP_SRC_HI(%a6),%d1      # fetch DENORM hi(man)
2318        lsr.l           %d0,%d1                 # shift it
2319        bset            &31,%d1                 # set j-bit
2320        mov.l           %d1,FP_SRC_HI(%a6)      # insert new hi(man)
2321        andi.w          &0x8000,FP_SRC_EX(%a6)  # clear old exponent
2322        ori.w           &0x3f80,FP_SRC_EX(%a6)  # insert new "skewed" exponent
2323funimp_skew_sgl_not:
2324        rts
2325
2326funimp_skew_dbl:
2327        mov.w           FP_SRC_EX(%a6),%d0      # fetch DENORM exponent
2328        andi.w          &0x7fff,%d0             # strip sign
2329        beq.b           funimp_skew_dbl_not
2330        cmpi.w          %d0,&0x3c00
2331        bgt.b           funimp_skew_dbl_not
2332
2333        tst.b           FP_SRC_EX(%a6)          # make "internal format"
2334        smi.b           0x2+FP_SRC(%a6)
2335        mov.w           %d0,FP_SRC_EX(%a6)      # insert exponent with cleared sign
2336        clr.l           %d0                     # clear g,r,s
2337        lea             FP_SRC(%a6),%a0         # pass ptr to src op
2338        mov.w           &0x3c01,%d1             # pass denorm threshold
2339        bsr.l           dnrm_lp                 # denorm it
2340        mov.w           &0x3c00,%d0             # new exponent
2341        tst.b           0x2+FP_SRC(%a6)         # is sign set?
2342        beq.b           fss_dbl_denorm_done     # no
2343        bset            &15,%d0                 # set sign
2344fss_dbl_denorm_done:
2345        bset            &0x7,FP_SRC_HI(%a6)     # set j-bit
2346        mov.w           %d0,FP_SRC_EX(%a6)      # insert new exponent
2347funimp_skew_dbl_not:
2348        rts
2349
2350#########################################################################
2351        global          _mem_write2
2352_mem_write2:
2353        btst            &0x5,EXC_SR(%a6)
2354        beq.l           _dmem_write
2355        mov.l           0x0(%a0),FP_DST_EX(%a6)
2356        mov.l           0x4(%a0),FP_DST_HI(%a6)
2357        mov.l           0x8(%a0),FP_DST_LO(%a6)
2358        clr.l           %d1
2359        rts
2360
2361#########################################################################
2362# XDEF **************************************************************** #
2363#       _fpsp_effadd(): 060FPSP entry point for FP "Unimplemented       #
2364#                       effective address" exception.                   #
2365#                                                                       #
2366#       This handler should be the first code executed upon taking the  #
2367#       FP Unimplemented Effective Address exception in an operating    #
2368#       system.                                                         #
2369#                                                                       #
2370# XREF **************************************************************** #
2371#       _imem_read_long() - read instruction longword                   #
2372#       fix_skewed_ops() - adjust src operand in fsave frame            #
2373#       set_tag_x() - determine optype of src/dst operands              #
2374#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
2375#       unnorm_fix() - change UNNORM operands to NORM or ZERO           #
2376#       load_fpn2() - load dst operand from FP regfile                  #
2377#       tbl_unsupp - add of table of emulation routines for opclass 0,2 #
2378#       decbin() - convert packed data to FP binary data                #
2379#       _real_fpu_disabled() - "callout" for "FPU disabled" exception   #
2380#       _real_access() - "callout" for access error exception           #
2381#       _mem_read() - read extended immediate operand from memory       #
2382#       _fpsp_done() - "callout" for exit; work all done                #
2383#       _real_trace() - "callout" for Trace enabled exception           #
2384#       fmovm_dynamic() - emulate dynamic fmovm instruction             #
2385#       fmovm_ctrl() - emulate fmovm control instruction                #
2386#                                                                       #
2387# INPUT *************************************************************** #
2388#       - The system stack contains the "Unimplemented <ea>" stk frame  #
2389#                                                                       #
2390# OUTPUT ************************************************************** #
2391#       If access error:                                                #
2392#       - The system stack is changed to an access error stack frame    #
2393#       If FPU disabled:                                                #
2394#       - The system stack is changed to an FPU disabled stack frame    #
2395#       If Trace exception enabled:                                     #
2396#       - The system stack is changed to a Trace exception stack frame  #
2397#       Else: (normal case)                                             #
2398#       - None (correct result has been stored as appropriate)          #
2399#                                                                       #
2400# ALGORITHM *********************************************************** #
2401#       This exception handles 3 types of operations:                   #
2402# (1) FP Instructions using extended precision or packed immediate      #
2403#     addressing mode.                                                  #
2404# (2) The "fmovm.x" instruction w/ dynamic register specification.      #
2405# (3) The "fmovm.l" instruction w/ 2 or 3 control registers.            #
2406#                                                                       #
2407#       For immediate data operations, the data is read in w/ a         #
2408# _mem_read() "callout", converted to FP binary (if packed), and used   #
2409# as the source operand to the instruction specified by the instruction #
2410# word. If no FP exception should be reported ads a result of the       #
2411# emulation, then the result is stored to the destination register and  #
2412# the handler exits through _fpsp_done(). If an enabled exc has been    #
2413# signalled as a result of emulation, then an fsave state frame         #
2414# corresponding to the FP exception type must be entered into the 060   #
2415# FPU before exiting. In either the enabled or disabled cases, we       #
2416# must also check if a Trace exception is pending, in which case, we    #
2417# must create a Trace exception stack frame from the current exception  #
2418# stack frame. If no Trace is pending, we simply exit through           #
2419# _fpsp_done().                                                         #
2420#       For "fmovm.x", call the routine fmovm_dynamic() which will      #
2421# decode and emulate the instruction. No FP exceptions can be pending   #
2422# as a result of this operation emulation. A Trace exception can be     #
2423# pending, though, which means the current stack frame must be changed  #
2424# to a Trace stack frame and an exit made through _real_trace().        #
2425# For the case of "fmovm.x Dn,-(a7)", where the offending instruction   #
2426# was executed from supervisor mode, this handler must store the FP     #
2427# register file values to the system stack by itself since              #
2428# fmovm_dynamic() can't handle this. A normal exit is made through      #
2429# fpsp_done().                                                          #
2430#       For "fmovm.l", fmovm_ctrl() is used to emulate the instruction. #
2431# Again, a Trace exception may be pending and an exit made through      #
2432# _real_trace(). Else, a normal exit is made through _fpsp_done().      #
2433#                                                                       #
2434#       Before any of the above is attempted, it must be checked to     #
2435# see if the FPU is disabled. Since the "Unimp <ea>" exception is taken #
2436# before the "FPU disabled" exception, but the "FPU disabled" exception #
2437# has higher priority, we check the disabled bit in the PCR. If set,    #
2438# then we must create an 8 word "FPU disabled" exception stack frame    #
2439# from the current 4 word exception stack frame. This includes          #
2440# reproducing the effective address of the instruction to put on the    #
2441# new stack frame.                                                      #
2442#                                                                       #
2443#       In the process of all emulation work, if a _mem_read()          #
2444# "callout" returns a failing result indicating an access error, then   #
2445# we must create an access error stack frame from the current stack     #
2446# frame. This information includes a faulting address and a fault-      #
2447# status-longword. These are created within this handler.               #
2448#                                                                       #
2449#########################################################################
2450
2451        global          _fpsp_effadd
2452_fpsp_effadd:
2453
2454# This exception type takes priority over the "Line F Emulator"
2455# exception. Therefore, the FPU could be disabled when entering here.
2456# So, we must check to see if it's disabled and handle that case separately.
2457        mov.l           %d0,-(%sp)              # save d0
2458        movc            %pcr,%d0                # load proc cr
2459        btst            &0x1,%d0                # is FPU disabled?
2460        bne.w           iea_disabled            # yes
2461        mov.l           (%sp)+,%d0              # restore d0
2462
2463        link            %a6,&-LOCAL_SIZE        # init stack frame
2464
2465        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
2466        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
2467        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
2468
2469# PC of instruction that took the exception is the PC in the frame
2470        mov.l           EXC_PC(%a6),EXC_EXTWPTR(%a6)
2471
2472        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
2473        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
2474        bsr.l           _imem_read_long         # fetch the instruction words
2475        mov.l           %d0,EXC_OPWORD(%a6)     # store OPWORD and EXTWORD
2476
2477#########################################################################
2478
2479        tst.w           %d0                     # is operation fmovem?
2480        bmi.w           iea_fmovm               # yes
2481
2482#
2483# here, we will have:
2484#       fabs    fdabs   fsabs           facos           fmod
2485#       fadd    fdadd   fsadd           fasin           frem
2486#       fcmp                            fatan           fscale
2487#       fdiv    fddiv   fsdiv           fatanh          fsin
2488#       fint                            fcos            fsincos
2489#       fintrz                          fcosh           fsinh
2490#       fmove   fdmove  fsmove          fetox           ftan
2491#       fmul    fdmul   fsmul           fetoxm1         ftanh
2492#       fneg    fdneg   fsneg           fgetexp         ftentox
2493#       fsgldiv                         fgetman         ftwotox
2494#       fsglmul                         flog10
2495#       fsqrt                           flog2
2496#       fsub    fdsub   fssub           flogn
2497#       ftst                            flognp1
2498# which can all use f<op>.{x,p}
2499# so, now it's immediate data extended precision AND PACKED FORMAT!
2500#
2501iea_op:
2502        andi.l          &0x00ff00ff,USER_FPSR(%a6)
2503
2504        btst            &0xa,%d0                # is src fmt x or p?
2505        bne.b           iea_op_pack             # packed
2506
2507
2508        mov.l           EXC_EXTWPTR(%a6),%a0    # pass: ptr to #<data>
2509        lea             FP_SRC(%a6),%a1         # pass: ptr to super addr
2510        mov.l           &0xc,%d0                # pass: 12 bytes
2511        bsr.l           _imem_read              # read extended immediate
2512
2513        tst.l           %d1                     # did ifetch fail?
2514        bne.w           iea_iacc                # yes
2515
2516        bra.b           iea_op_setsrc
2517
2518iea_op_pack:
2519
2520        mov.l           EXC_EXTWPTR(%a6),%a0    # pass: ptr to #<data>
2521        lea             FP_SRC(%a6),%a1         # pass: ptr to super dst
2522        mov.l           &0xc,%d0                # pass: 12 bytes
2523        bsr.l           _imem_read              # read packed operand
2524
2525        tst.l           %d1                     # did ifetch fail?
2526        bne.w           iea_iacc                # yes
2527
2528# The packed operand is an INF or a NAN if the exponent field is all ones.
2529        bfextu          FP_SRC(%a6){&1:&15},%d0 # get exp
2530        cmpi.w          %d0,&0x7fff             # INF or NAN?
2531        beq.b           iea_op_setsrc           # operand is an INF or NAN
2532
2533# The packed operand is a zero if the mantissa is all zero, else it's
2534# a normal packed op.
2535        mov.b           3+FP_SRC(%a6),%d0       # get byte 4
2536        andi.b          &0x0f,%d0               # clear all but last nybble
2537        bne.b           iea_op_gp_not_spec      # not a zero
2538        tst.l           FP_SRC_HI(%a6)          # is lw 2 zero?
2539        bne.b           iea_op_gp_not_spec      # not a zero
2540        tst.l           FP_SRC_LO(%a6)          # is lw 3 zero?
2541        beq.b           iea_op_setsrc           # operand is a ZERO
2542iea_op_gp_not_spec:
2543        lea             FP_SRC(%a6),%a0         # pass: ptr to packed op
2544        bsr.l           decbin                  # convert to extended
2545        fmovm.x         &0x80,FP_SRC(%a6)       # make this the srcop
2546
2547iea_op_setsrc:
2548        addi.l          &0xc,EXC_EXTWPTR(%a6)   # update extension word pointer
2549
2550# FP_SRC now holds the src operand.
2551        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
2552        bsr.l           set_tag_x               # tag the operand type
2553        mov.b           %d0,STAG(%a6)           # could be ANYTHING!!!
2554        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
2555        bne.b           iea_op_getdst           # no
2556        bsr.l           unnorm_fix              # yes; convert to NORM/DENORM/ZERO
2557        mov.b           %d0,STAG(%a6)           # set new optype tag
2558iea_op_getdst:
2559        clr.b           STORE_FLG(%a6)          # clear "store result" boolean
2560
2561        btst            &0x5,1+EXC_CMDREG(%a6)  # is operation monadic or dyadic?
2562        beq.b           iea_op_extract          # monadic
2563        btst            &0x4,1+EXC_CMDREG(%a6)  # is operation fsincos,ftst,fcmp?
2564        bne.b           iea_op_spec             # yes
2565
2566iea_op_loaddst:
2567        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno
2568        bsr.l           load_fpn2               # load dst operand
2569
2570        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
2571        bsr.l           set_tag_x               # tag the operand type
2572        mov.b           %d0,DTAG(%a6)           # could be ANYTHING!!!
2573        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
2574        bne.b           iea_op_extract          # no
2575        bsr.l           unnorm_fix              # yes; convert to NORM/DENORM/ZERO
2576        mov.b           %d0,DTAG(%a6)           # set new optype tag
2577        bra.b           iea_op_extract
2578
2579# the operation is fsincos, ftst, or fcmp. only fcmp is dyadic
2580iea_op_spec:
2581        btst            &0x3,1+EXC_CMDREG(%a6)  # is operation fsincos?
2582        beq.b           iea_op_extract          # yes
2583# now, we're left with ftst and fcmp. so, first let's tag them so that they don't
2584# store a result. then, only fcmp will branch back and pick up a dst operand.
2585        st              STORE_FLG(%a6)          # don't store a final result
2586        btst            &0x1,1+EXC_CMDREG(%a6)  # is operation fcmp?
2587        beq.b           iea_op_loaddst          # yes
2588
2589iea_op_extract:
2590        clr.l           %d0
2591        mov.b           FPCR_MODE(%a6),%d0      # pass: rnd mode,prec
2592
2593        mov.b           1+EXC_CMDREG(%a6),%d1
2594        andi.w          &0x007f,%d1             # extract extension
2595
2596        fmov.l          &0x0,%fpcr
2597        fmov.l          &0x0,%fpsr
2598
2599        lea             FP_SRC(%a6),%a0
2600        lea             FP_DST(%a6),%a1
2601
2602        mov.l           (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
2603        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
2604
2605#
2606# Exceptions in order of precedence:
2607#       BSUN    : none
2608#       SNAN    : all operations
2609#       OPERR   : all reg-reg or mem-reg operations that can normally operr
2610#       OVFL    : same as OPERR
2611#       UNFL    : same as OPERR
2612#       DZ      : same as OPERR
2613#       INEX2   : same as OPERR
2614#       INEX1   : all packed immediate operations
2615#
2616
2617# we determine the highest priority exception(if any) set by the
2618# emulation routine that has also been enabled by the user.
2619        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions enabled
2620        bne.b           iea_op_ena              # some are enabled
2621
2622# now, we save the result, unless, of course, the operation was ftst or fcmp.
2623# these don't save results.
2624iea_op_save:
2625        tst.b           STORE_FLG(%a6)          # does this op store a result?
2626        bne.b           iea_op_exit1            # exit with no frestore
2627
2628iea_op_store:
2629        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno
2630        bsr.l           store_fpreg             # store the result
2631
2632iea_op_exit1:
2633        mov.l           EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC"
2634        mov.l           EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame
2635
2636        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
2637        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2638        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2639
2640        unlk            %a6                     # unravel the frame
2641
2642        btst            &0x7,(%sp)              # is trace on?
2643        bne.w           iea_op_trace            # yes
2644
2645        bra.l           _fpsp_done              # exit to os
2646
2647iea_op_ena:
2648        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enable and set
2649        bfffo           %d0{&24:&8},%d0         # find highest priority exception
2650        bne.b           iea_op_exc              # at least one was set
2651
2652# no exception occurred. now, did a disabled, exact overflow occur with inexact
2653# enabled? if so, then we have to stuff an overflow frame into the FPU.
2654        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur?
2655        beq.b           iea_op_save
2656
2657iea_op_ovfl:
2658        btst            &inex2_bit,FPCR_ENABLE(%a6) # is inexact enabled?
2659        beq.b           iea_op_store            # no
2660        bra.b           iea_op_exc_ovfl         # yes
2661
2662# an enabled exception occurred. we have to insert the exception type back into
2663# the machine.
2664iea_op_exc:
2665        subi.l          &24,%d0                 # fix offset to be 0-8
2666        cmpi.b          %d0,&0x6                # is exception INEX?
2667        bne.b           iea_op_exc_force        # no
2668
2669# the enabled exception was inexact. so, if it occurs with an overflow
2670# or underflow that was disabled, then we have to force an overflow or
2671# underflow frame.
2672        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur?
2673        bne.b           iea_op_exc_ovfl         # yes
2674        btst            &unfl_bit,FPSR_EXCEPT(%a6) # did underflow occur?
2675        bne.b           iea_op_exc_unfl         # yes
2676
2677iea_op_exc_force:
2678        mov.w           (tbl_iea_except.b,%pc,%d0.w*2),2+FP_SRC(%a6)
2679        bra.b           iea_op_exit2            # exit with frestore
2680
2681tbl_iea_except:
2682        short           0xe002, 0xe006, 0xe004, 0xe005
2683        short           0xe003, 0xe002, 0xe001, 0xe001
2684
2685iea_op_exc_ovfl:
2686        mov.w           &0xe005,2+FP_SRC(%a6)
2687        bra.b           iea_op_exit2
2688
2689iea_op_exc_unfl:
2690        mov.w           &0xe003,2+FP_SRC(%a6)
2691
2692iea_op_exit2:
2693        mov.l           EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC"
2694        mov.l           EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame
2695
2696        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
2697        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2698        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2699
2700        frestore        FP_SRC(%a6)             # restore exceptional state
2701
2702        unlk            %a6                     # unravel the frame
2703
2704        btst            &0x7,(%sp)              # is trace on?
2705        bne.b           iea_op_trace            # yes
2706
2707        bra.l           _fpsp_done              # exit to os
2708
2709#
2710# The opclass two instruction that took an "Unimplemented Effective Address"
2711# exception was being traced. Make the "current" PC the FPIAR and put it in
2712# the trace stack frame then jump to _real_trace().
2713#
2714#                UNIMP EA FRAME            TRACE FRAME
2715#               *****************       *****************
2716#               * 0x0 *  0x0f0  *       *    Current    *
2717#               *****************       *      PC       *
2718#               *    Current    *       *****************
2719#               *      PC       *       * 0x2 *  0x024  *
2720#               *****************       *****************
2721#               *      SR       *       *     Next      *
2722#               *****************       *      PC       *
2723#                                       *****************
2724#                                       *      SR       *
2725#                                       *****************
2726iea_op_trace:
2727        mov.l           (%sp),-(%sp)            # shift stack frame "down"
2728        mov.w           0x8(%sp),0x4(%sp)
2729        mov.w           &0x2024,0x6(%sp)        # stk fmt = 0x2; voff = 0x024
2730        fmov.l          %fpiar,0x8(%sp)         # "Current PC" is in FPIAR
2731
2732        bra.l           _real_trace
2733
2734#########################################################################
2735iea_fmovm:
2736        btst            &14,%d0                 # ctrl or data reg
2737        beq.w           iea_fmovm_ctrl
2738
2739iea_fmovm_data:
2740
2741        btst            &0x5,EXC_SR(%a6)        # user or supervisor mode
2742        bne.b           iea_fmovm_data_s
2743
2744iea_fmovm_data_u:
2745        mov.l           %usp,%a0
2746        mov.l           %a0,EXC_A7(%a6)         # store current a7
2747        bsr.l           fmovm_dynamic           # do dynamic fmovm
2748        mov.l           EXC_A7(%a6),%a0         # load possibly new a7
2749        mov.l           %a0,%usp                # update usp
2750        bra.w           iea_fmovm_exit
2751
2752iea_fmovm_data_s:
2753        clr.b           SPCOND_FLG(%a6)
2754        lea             0x2+EXC_VOFF(%a6),%a0
2755        mov.l           %a0,EXC_A7(%a6)
2756        bsr.l           fmovm_dynamic           # do dynamic fmovm
2757
2758        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
2759        beq.w           iea_fmovm_data_predec
2760        cmpi.b          SPCOND_FLG(%a6),&mia7_flg
2761        bne.w           iea_fmovm_exit
2762
2763# right now, d0 = the size.
2764# the data has been fetched from the supervisor stack, but we have not
2765# incremented the stack pointer by the appropriate number of bytes.
2766# do it here.
2767iea_fmovm_data_postinc:
2768        btst            &0x7,EXC_SR(%a6)
2769        bne.b           iea_fmovm_data_pi_trace
2770
2771        mov.w           EXC_SR(%a6),(EXC_SR,%a6,%d0)
2772        mov.l           EXC_EXTWPTR(%a6),(EXC_PC,%a6,%d0)
2773        mov.w           &0x00f0,(EXC_VOFF,%a6,%d0)
2774
2775        lea             (EXC_SR,%a6,%d0),%a0
2776        mov.l           %a0,EXC_SR(%a6)
2777
2778        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
2779        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2780        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2781
2782        unlk            %a6
2783        mov.l           (%sp)+,%sp
2784        bra.l           _fpsp_done
2785
2786iea_fmovm_data_pi_trace:
2787        mov.w           EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0)
2788        mov.l           EXC_EXTWPTR(%a6),(EXC_PC-0x4,%a6,%d0)
2789        mov.w           &0x2024,(EXC_VOFF-0x4,%a6,%d0)
2790        mov.l           EXC_PC(%a6),(EXC_VOFF+0x2-0x4,%a6,%d0)
2791
2792        lea             (EXC_SR-0x4,%a6,%d0),%a0
2793        mov.l           %a0,EXC_SR(%a6)
2794
2795        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
2796        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2797        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2798
2799        unlk            %a6
2800        mov.l           (%sp)+,%sp
2801        bra.l           _real_trace
2802
2803# right now, d1 = size and d0 = the strg.
2804iea_fmovm_data_predec:
2805        mov.b           %d1,EXC_VOFF(%a6)       # store strg
2806        mov.b           %d0,0x1+EXC_VOFF(%a6)   # store size
2807
2808        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
2809        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2810        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2811
2812        mov.l           (%a6),-(%sp)            # make a copy of a6
2813        mov.l           %d0,-(%sp)              # save d0
2814        mov.l           %d1,-(%sp)              # save d1
2815        mov.l           EXC_EXTWPTR(%a6),-(%sp) # make a copy of Next PC
2816
2817        clr.l           %d0
2818        mov.b           0x1+EXC_VOFF(%a6),%d0   # fetch size
2819        neg.l           %d0                     # get negative of size
2820
2821        btst            &0x7,EXC_SR(%a6)        # is trace enabled?
2822        beq.b           iea_fmovm_data_p2
2823
2824        mov.w           EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0)
2825        mov.l           EXC_PC(%a6),(EXC_VOFF-0x2,%a6,%d0)
2826        mov.l           (%sp)+,(EXC_PC-0x4,%a6,%d0)
2827        mov.w           &0x2024,(EXC_VOFF-0x4,%a6,%d0)
2828
2829        pea             (%a6,%d0)               # create final sp
2830        bra.b           iea_fmovm_data_p3
2831
2832iea_fmovm_data_p2:
2833        mov.w           EXC_SR(%a6),(EXC_SR,%a6,%d0)
2834        mov.l           (%sp)+,(EXC_PC,%a6,%d0)
2835        mov.w           &0x00f0,(EXC_VOFF,%a6,%d0)
2836
2837        pea             (0x4,%a6,%d0)           # create final sp
2838
2839iea_fmovm_data_p3:
2840        clr.l           %d1
2841        mov.b           EXC_VOFF(%a6),%d1       # fetch strg
2842
2843        tst.b           %d1
2844        bpl.b           fm_1
2845        fmovm.x         &0x80,(0x4+0x8,%a6,%d0)
2846        addi.l          &0xc,%d0
2847fm_1:
2848        lsl.b           &0x1,%d1
2849        bpl.b           fm_2
2850        fmovm.x         &0x40,(0x4+0x8,%a6,%d0)
2851        addi.l          &0xc,%d0
2852fm_2:
2853        lsl.b           &0x1,%d1
2854        bpl.b           fm_3
2855        fmovm.x         &0x20,(0x4+0x8,%a6,%d0)
2856        addi.l          &0xc,%d0
2857fm_3:
2858        lsl.b           &0x1,%d1
2859        bpl.b           fm_4
2860        fmovm.x         &0x10,(0x4+0x8,%a6,%d0)
2861        addi.l          &0xc,%d0
2862fm_4:
2863        lsl.b           &0x1,%d1
2864        bpl.b           fm_5
2865        fmovm.x         &0x08,(0x4+0x8,%a6,%d0)
2866        addi.l          &0xc,%d0
2867fm_5:
2868        lsl.b           &0x1,%d1
2869        bpl.b           fm_6
2870        fmovm.x         &0x04,(0x4+0x8,%a6,%d0)
2871        addi.l          &0xc,%d0
2872fm_6:
2873        lsl.b           &0x1,%d1
2874        bpl.b           fm_7
2875        fmovm.x         &0x02,(0x4+0x8,%a6,%d0)
2876        addi.l          &0xc,%d0
2877fm_7:
2878        lsl.b           &0x1,%d1
2879        bpl.b           fm_end
2880        fmovm.x         &0x01,(0x4+0x8,%a6,%d0)
2881fm_end:
2882        mov.l           0x4(%sp),%d1
2883        mov.l           0x8(%sp),%d0
2884        mov.l           0xc(%sp),%a6
2885        mov.l           (%sp)+,%sp
2886
2887        btst            &0x7,(%sp)              # is trace enabled?
2888        beq.l           _fpsp_done
2889        bra.l           _real_trace
2890
2891#########################################################################
2892iea_fmovm_ctrl:
2893
2894        bsr.l           fmovm_ctrl              # load ctrl regs
2895
2896iea_fmovm_exit:
2897        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
2898        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2899        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2900
2901        btst            &0x7,EXC_SR(%a6)        # is trace on?
2902        bne.b           iea_fmovm_trace         # yes
2903
2904        mov.l           EXC_EXTWPTR(%a6),EXC_PC(%a6) # set Next PC
2905
2906        unlk            %a6                     # unravel the frame
2907
2908        bra.l           _fpsp_done              # exit to os
2909
2910#
2911# The control reg instruction that took an "Unimplemented Effective Address"
2912# exception was being traced. The "Current PC" for the trace frame is the
2913# PC stacked for Unimp EA. The "Next PC" is in EXC_EXTWPTR.
2914# After fixing the stack frame, jump to _real_trace().
2915#
2916#                UNIMP EA FRAME            TRACE FRAME
2917#               *****************       *****************
2918#               * 0x0 *  0x0f0  *       *    Current    *
2919#               *****************       *      PC       *
2920#               *    Current    *       *****************
2921#               *      PC       *       * 0x2 *  0x024  *
2922#               *****************       *****************
2923#               *      SR       *       *     Next      *
2924#               *****************       *      PC       *
2925#                                       *****************
2926#                                       *      SR       *
2927#                                       *****************
2928# this ain't a pretty solution, but it works:
2929# -restore a6 (not with unlk)
2930# -shift stack frame down over where old a6 used to be
2931# -add LOCAL_SIZE to stack pointer
2932iea_fmovm_trace:
2933        mov.l           (%a6),%a6               # restore frame pointer
2934        mov.w           EXC_SR+LOCAL_SIZE(%sp),0x0+LOCAL_SIZE(%sp)
2935        mov.l           EXC_PC+LOCAL_SIZE(%sp),0x8+LOCAL_SIZE(%sp)
2936        mov.l           EXC_EXTWPTR+LOCAL_SIZE(%sp),0x2+LOCAL_SIZE(%sp)
2937        mov.w           &0x2024,0x6+LOCAL_SIZE(%sp) # stk fmt = 0x2; voff = 0x024
2938        add.l           &LOCAL_SIZE,%sp         # clear stack frame
2939
2940        bra.l           _real_trace
2941
2942#########################################################################
2943# The FPU is disabled and so we should really have taken the "Line
2944# F Emulator" exception. So, here we create an 8-word stack frame
2945# from our 4-word stack frame. This means we must calculate the length
2946# the faulting instruction to get the "next PC". This is trivial for
2947# immediate operands but requires some extra work for fmovm dynamic
2948# which can use most addressing modes.
2949iea_disabled:
2950        mov.l           (%sp)+,%d0              # restore d0
2951
2952        link            %a6,&-LOCAL_SIZE        # init stack frame
2953
2954        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
2955
2956# PC of instruction that took the exception is the PC in the frame
2957        mov.l           EXC_PC(%a6),EXC_EXTWPTR(%a6)
2958        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
2959        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
2960        bsr.l           _imem_read_long         # fetch the instruction words
2961        mov.l           %d0,EXC_OPWORD(%a6)     # store OPWORD and EXTWORD
2962
2963        tst.w           %d0                     # is instr fmovm?
2964        bmi.b           iea_dis_fmovm           # yes
2965# instruction is using an extended precision immediate operand. Therefore,
2966# the total instruction length is 16 bytes.
2967iea_dis_immed:
2968        mov.l           &0x10,%d0               # 16 bytes of instruction
2969        bra.b           iea_dis_cont
2970iea_dis_fmovm:
2971        btst            &0xe,%d0                # is instr fmovm ctrl
2972        bne.b           iea_dis_fmovm_data      # no
2973# the instruction is a fmovm.l with 2 or 3 registers.
2974        bfextu          %d0{&19:&3},%d1
2975        mov.l           &0xc,%d0
2976        cmpi.b          %d1,&0x7                # move all regs?
2977        bne.b           iea_dis_cont
2978        addq.l          &0x4,%d0
2979        bra.b           iea_dis_cont
2980# the instruction is an fmovm.x dynamic which can use many addressing
2981# modes and thus can have several different total instruction lengths.
2982# call fmovm_calc_ea which will go through the ea calc process and,
2983# as a by-product, will tell us how long the instruction is.
2984iea_dis_fmovm_data:
2985        clr.l           %d0
2986        bsr.l           fmovm_calc_ea
2987        mov.l           EXC_EXTWPTR(%a6),%d0
2988        sub.l           EXC_PC(%a6),%d0
2989iea_dis_cont:
2990        mov.w           %d0,EXC_VOFF(%a6)       # store stack shift value
2991
2992        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2993
2994        unlk            %a6
2995
2996# here, we actually create the 8-word frame from the 4-word frame,
2997# with the "next PC" as additional info.
2998# the <ea> field is let as undefined.
2999        subq.l          &0x8,%sp                # make room for new stack
3000        mov.l           %d0,-(%sp)              # save d0
3001        mov.w           0xc(%sp),0x4(%sp)       # move SR
3002        mov.l           0xe(%sp),0x6(%sp)       # move Current PC
3003        clr.l           %d0
3004        mov.w           0x12(%sp),%d0
3005        mov.l           0x6(%sp),0x10(%sp)      # move Current PC
3006        add.l           %d0,0x6(%sp)            # make Next PC
3007        mov.w           &0x402c,0xa(%sp)        # insert offset,frame format
3008        mov.l           (%sp)+,%d0              # restore d0
3009
3010        bra.l           _real_fpu_disabled
3011
3012##########
3013
3014iea_iacc:
3015        movc            %pcr,%d0
3016        btst            &0x1,%d0
3017        bne.b           iea_iacc_cont
3018        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3019        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1 on stack
3020iea_iacc_cont:
3021        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3022
3023        unlk            %a6
3024
3025        subq.w          &0x8,%sp                # make stack frame bigger
3026        mov.l           0x8(%sp),(%sp)          # store SR,hi(PC)
3027        mov.w           0xc(%sp),0x4(%sp)       # store lo(PC)
3028        mov.w           &0x4008,0x6(%sp)        # store voff
3029        mov.l           0x2(%sp),0x8(%sp)       # store ea
3030        mov.l           &0x09428001,0xc(%sp)    # store fslw
3031
3032iea_acc_done:
3033        btst            &0x5,(%sp)              # user or supervisor mode?
3034        beq.b           iea_acc_done2           # user
3035        bset            &0x2,0xd(%sp)           # set supervisor TM bit
3036
3037iea_acc_done2:
3038        bra.l           _real_access
3039
3040iea_dacc:
3041        lea             -LOCAL_SIZE(%a6),%sp
3042
3043        movc            %pcr,%d1
3044        btst            &0x1,%d1
3045        bne.b           iea_dacc_cont
3046        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1 on stack
3047        fmovm.l         LOCAL_SIZE+USER_FPCR(%sp),%fpcr,%fpsr,%fpiar # restore ctrl regs
3048iea_dacc_cont:
3049        mov.l           (%a6),%a6
3050
3051        mov.l           0x4+LOCAL_SIZE(%sp),-0x8+0x4+LOCAL_SIZE(%sp)
3052        mov.w           0x8+LOCAL_SIZE(%sp),-0x8+0x8+LOCAL_SIZE(%sp)
3053        mov.w           &0x4008,-0x8+0xa+LOCAL_SIZE(%sp)
3054        mov.l           %a0,-0x8+0xc+LOCAL_SIZE(%sp)
3055        mov.w           %d0,-0x8+0x10+LOCAL_SIZE(%sp)
3056        mov.w           &0x0001,-0x8+0x12+LOCAL_SIZE(%sp)
3057
3058        movm.l          LOCAL_SIZE+EXC_DREGS(%sp),&0x0303 # restore d0-d1/a0-a1
3059        add.w           &LOCAL_SIZE-0x4,%sp
3060
3061        bra.b           iea_acc_done
3062
3063#########################################################################
3064# XDEF **************************************************************** #
3065#       _fpsp_operr(): 060FPSP entry point for FP Operr exception.      #
3066#                                                                       #
3067#       This handler should be the first code executed upon taking the  #
3068#       FP Operand Error exception in an operating system.              #
3069#                                                                       #
3070# XREF **************************************************************** #
3071#       _imem_read_long() - read instruction longword                   #
3072#       fix_skewed_ops() - adjust src operand in fsave frame            #
3073#       _real_operr() - "callout" to operating system operr handler     #
3074#       _dmem_write_{byte,word,long}() - store data to mem (opclass 3)  #
3075#       store_dreg_{b,w,l}() - store data to data regfile (opclass 3)   #
3076#       facc_out_{b,w,l}() - store to memory took access error (opcl 3) #
3077#                                                                       #
3078# INPUT *************************************************************** #
3079#       - The system stack contains the FP Operr exception frame        #
3080#       - The fsave frame contains the source operand                   #
3081#                                                                       #
3082# OUTPUT ************************************************************** #
3083#       No access error:                                                #
3084#       - The system stack is unchanged                                 #
3085#       - The fsave frame contains the adjusted src op for opclass 0,2  #
3086#                                                                       #
3087# ALGORITHM *********************************************************** #
3088#       In a system where the FP Operr exception is enabled, the goal   #
3089# is to get to the handler specified at _real_operr(). But, on the 060, #
3090# for opclass zero and two instruction taking this exception, the       #
3091# input operand in the fsave frame may be incorrect for some cases      #
3092# and needs to be corrected. This handler calls fix_skewed_ops() to     #
3093# do just this and then exits through _real_operr().                    #
3094#       For opclass 3 instructions, the 060 doesn't store the default   #
3095# operr result out to memory or data register file as it should.        #
3096# This code must emulate the move out before finally exiting through    #
3097# _real_inex(). The move out, if to memory, is performed using          #
3098# _mem_write() "callout" routines that may return a failing result.     #
3099# In this special case, the handler must exit through facc_out()        #
3100# which creates an access error stack frame from the current operr      #
3101# stack frame.                                                          #
3102#                                                                       #
3103#########################################################################
3104
3105        global          _fpsp_operr
3106_fpsp_operr:
3107
3108        link.w          %a6,&-LOCAL_SIZE        # init stack frame
3109
3110        fsave           FP_SRC(%a6)             # grab the "busy" frame
3111
3112        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3113        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3114        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
3115
3116# the FPIAR holds the "current PC" of the faulting instruction
3117        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3118
3119        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3120        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3121        bsr.l           _imem_read_long         # fetch the instruction words
3122        mov.l           %d0,EXC_OPWORD(%a6)
3123
3124##############################################################################
3125
3126        btst            &13,%d0                 # is instr an fmove out?
3127        bne.b           foperr_out              # fmove out
3128
3129
3130# here, we simply see if the operand in the fsave frame needs to be "unskewed".
3131# this would be the case for opclass two operations with a source infinity or
3132# denorm operand in the sgl or dbl format. NANs also become skewed, but can't
3133# cause an operr so we don't need to check for them here.
3134        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3135        bsr.l           fix_skewed_ops          # fix src op
3136
3137foperr_exit:
3138        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3139        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3140        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3141
3142        frestore        FP_SRC(%a6)
3143
3144        unlk            %a6
3145        bra.l           _real_operr
3146
3147########################################################################
3148
3149#
3150# the hardware does not save the default result to memory on enabled
3151# operand error exceptions. we do this here before passing control to
3152# the user operand error handler.
3153#
3154# byte, word, and long destination format operations can pass
3155# through here. we simply need to test the sign of the src
3156# operand and save the appropriate minimum or maximum integer value
3157# to the effective address as pointed to by the stacked effective address.
3158#
3159# although packed opclass three operations can take operand error
3160# exceptions, they won't pass through here since they are caught
3161# first by the unsupported data format exception handler. that handler
3162# sends them directly to _real_operr() if necessary.
3163#
3164foperr_out:
3165
3166        mov.w           FP_SRC_EX(%a6),%d1      # fetch exponent
3167        andi.w          &0x7fff,%d1
3168        cmpi.w          %d1,&0x7fff
3169        bne.b           foperr_out_not_qnan
3170# the operand is either an infinity or a QNAN.
3171        tst.l           FP_SRC_LO(%a6)
3172        bne.b           foperr_out_qnan
3173        mov.l           FP_SRC_HI(%a6),%d1
3174        andi.l          &0x7fffffff,%d1
3175        beq.b           foperr_out_not_qnan
3176foperr_out_qnan:
3177        mov.l           FP_SRC_HI(%a6),L_SCR1(%a6)
3178        bra.b           foperr_out_jmp
3179
3180foperr_out_not_qnan:
3181        mov.l           &0x7fffffff,%d1
3182        tst.b           FP_SRC_EX(%a6)
3183        bpl.b           foperr_out_not_qnan2
3184        addq.l          &0x1,%d1
3185foperr_out_not_qnan2:
3186        mov.l           %d1,L_SCR1(%a6)
3187
3188foperr_out_jmp:
3189        bfextu          %d0{&19:&3},%d0         # extract dst format field
3190        mov.b           1+EXC_OPWORD(%a6),%d1   # extract <ea> mode,reg
3191        mov.w           (tbl_operr.b,%pc,%d0.w*2),%a0
3192        jmp             (tbl_operr.b,%pc,%a0)
3193
3194tbl_operr:
3195        short           foperr_out_l - tbl_operr # long word integer
3196        short           tbl_operr    - tbl_operr # sgl prec shouldn't happen
3197        short           tbl_operr    - tbl_operr # ext prec shouldn't happen
3198        short           foperr_exit  - tbl_operr # packed won't enter here
3199        short           foperr_out_w - tbl_operr # word integer
3200        short           tbl_operr    - tbl_operr # dbl prec shouldn't happen
3201        short           foperr_out_b - tbl_operr # byte integer
3202        short           tbl_operr    - tbl_operr # packed won't enter here
3203
3204foperr_out_b:
3205        mov.b           L_SCR1(%a6),%d0         # load positive default result
3206        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3207        ble.b           foperr_out_b_save_dn    # yes
3208        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3209        bsr.l           _dmem_write_byte        # write the default result
3210
3211        tst.l           %d1                     # did dstore fail?
3212        bne.l           facc_out_b              # yes
3213
3214        bra.w           foperr_exit
3215foperr_out_b_save_dn:
3216        andi.w          &0x0007,%d1
3217        bsr.l           store_dreg_b            # store result to regfile
3218        bra.w           foperr_exit
3219
3220foperr_out_w:
3221        mov.w           L_SCR1(%a6),%d0         # load positive default result
3222        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3223        ble.b           foperr_out_w_save_dn    # yes
3224        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3225        bsr.l           _dmem_write_word        # write the default result
3226
3227        tst.l           %d1                     # did dstore fail?
3228        bne.l           facc_out_w              # yes
3229
3230        bra.w           foperr_exit
3231foperr_out_w_save_dn:
3232        andi.w          &0x0007,%d1
3233        bsr.l           store_dreg_w            # store result to regfile
3234        bra.w           foperr_exit
3235
3236foperr_out_l:
3237        mov.l           L_SCR1(%a6),%d0         # load positive default result
3238        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3239        ble.b           foperr_out_l_save_dn    # yes
3240        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3241        bsr.l           _dmem_write_long        # write the default result
3242
3243        tst.l           %d1                     # did dstore fail?
3244        bne.l           facc_out_l              # yes
3245
3246        bra.w           foperr_exit
3247foperr_out_l_save_dn:
3248        andi.w          &0x0007,%d1
3249        bsr.l           store_dreg_l            # store result to regfile
3250        bra.w           foperr_exit
3251
3252#########################################################################
3253# XDEF **************************************************************** #
3254#       _fpsp_snan(): 060FPSP entry point for FP SNAN exception.        #
3255#                                                                       #
3256#       This handler should be the first code executed upon taking the  #
3257#       FP Signalling NAN exception in an operating system.             #
3258#                                                                       #
3259# XREF **************************************************************** #
3260#       _imem_read_long() - read instruction longword                   #
3261#       fix_skewed_ops() - adjust src operand in fsave frame            #
3262#       _real_snan() - "callout" to operating system SNAN handler       #
3263#       _dmem_write_{byte,word,long}() - store data to mem (opclass 3)  #
3264#       store_dreg_{b,w,l}() - store data to data regfile (opclass 3)   #
3265#       facc_out_{b,w,l,d,x}() - store to mem took acc error (opcl 3)   #
3266#       _calc_ea_fout() - fix An if <ea> is -() or ()+; also get <ea>   #
3267#                                                                       #
3268# INPUT *************************************************************** #
3269#       - The system stack contains the FP SNAN exception frame         #
3270#       - The fsave frame contains the source operand                   #
3271#                                                                       #
3272# OUTPUT ************************************************************** #
3273#       No access error:                                                #
3274#       - The system stack is unchanged                                 #
3275#       - The fsave frame contains the adjusted src op for opclass 0,2  #
3276#                                                                       #
3277# ALGORITHM *********************************************************** #
3278#       In a system where the FP SNAN exception is enabled, the goal    #
3279# is to get to the handler specified at _real_snan(). But, on the 060,  #
3280# for opclass zero and two instructions taking this exception, the      #
3281# input operand in the fsave frame may be incorrect for some cases      #
3282# and needs to be corrected. This handler calls fix_skewed_ops() to     #
3283# do just this and then exits through _real_snan().                     #
3284#       For opclass 3 instructions, the 060 doesn't store the default   #
3285# SNAN result out to memory or data register file as it should.         #
3286# This code must emulate the move out before finally exiting through    #
3287# _real_snan(). The move out, if to memory, is performed using          #
3288# _mem_write() "callout" routines that may return a failing result.     #
3289# In this special case, the handler must exit through facc_out()        #
3290# which creates an access error stack frame from the current SNAN       #
3291# stack frame.                                                          #
3292#       For the case of an extended precision opclass 3 instruction,    #
3293# if the effective addressing mode was -() or ()+, then the address     #
3294# register must get updated by calling _calc_ea_fout(). If the <ea>     #
3295# was -(a7) from supervisor mode, then the exception frame currently    #
3296# on the system stack must be carefully moved "down" to make room       #
3297# for the operand being moved.                                          #
3298#                                                                       #
3299#########################################################################
3300
3301        global          _fpsp_snan
3302_fpsp_snan:
3303
3304        link.w          %a6,&-LOCAL_SIZE        # init stack frame
3305
3306        fsave           FP_SRC(%a6)             # grab the "busy" frame
3307
3308        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3309        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3310        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
3311
3312# the FPIAR holds the "current PC" of the faulting instruction
3313        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3314
3315        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3316        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3317        bsr.l           _imem_read_long         # fetch the instruction words
3318        mov.l           %d0,EXC_OPWORD(%a6)
3319
3320##############################################################################
3321
3322        btst            &13,%d0                 # is instr an fmove out?
3323        bne.w           fsnan_out               # fmove out
3324
3325
3326# here, we simply see if the operand in the fsave frame needs to be "unskewed".
3327# this would be the case for opclass two operations with a source infinity or
3328# denorm operand in the sgl or dbl format. NANs also become skewed and must be
3329# fixed here.
3330        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3331        bsr.l           fix_skewed_ops          # fix src op
3332
3333fsnan_exit:
3334        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3335        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3336        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3337
3338        frestore        FP_SRC(%a6)
3339
3340        unlk            %a6
3341        bra.l           _real_snan
3342
3343########################################################################
3344
3345#
3346# the hardware does not save the default result to memory on enabled
3347# snan exceptions. we do this here before passing control to
3348# the user snan handler.
3349#
3350# byte, word, long, and packed destination format operations can pass
3351# through here. since packed format operations already were handled by
3352# fpsp_unsupp(), then we need to do nothing else for them here.
3353# for byte, word, and long, we simply need to test the sign of the src
3354# operand and save the appropriate minimum or maximum integer value
3355# to the effective address as pointed to by the stacked effective address.
3356#
3357fsnan_out:
3358
3359        bfextu          %d0{&19:&3},%d0         # extract dst format field
3360        mov.b           1+EXC_OPWORD(%a6),%d1   # extract <ea> mode,reg
3361        mov.w           (tbl_snan.b,%pc,%d0.w*2),%a0
3362        jmp             (tbl_snan.b,%pc,%a0)
3363
3364tbl_snan:
3365        short           fsnan_out_l - tbl_snan # long word integer
3366        short           fsnan_out_s - tbl_snan # sgl prec shouldn't happen
3367        short           fsnan_out_x - tbl_snan # ext prec shouldn't happen
3368        short           tbl_snan    - tbl_snan # packed needs no help
3369        short           fsnan_out_w - tbl_snan # word integer
3370        short           fsnan_out_d - tbl_snan # dbl prec shouldn't happen
3371        short           fsnan_out_b - tbl_snan # byte integer
3372        short           tbl_snan    - tbl_snan # packed needs no help
3373
3374fsnan_out_b:
3375        mov.b           FP_SRC_HI(%a6),%d0      # load upper byte of SNAN
3376        bset            &6,%d0                  # set SNAN bit
3377        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3378        ble.b           fsnan_out_b_dn          # yes
3379        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3380        bsr.l           _dmem_write_byte        # write the default result
3381
3382        tst.l           %d1                     # did dstore fail?
3383        bne.l           facc_out_b              # yes
3384
3385        bra.w           fsnan_exit
3386fsnan_out_b_dn:
3387        andi.w          &0x0007,%d1
3388        bsr.l           store_dreg_b            # store result to regfile
3389        bra.w           fsnan_exit
3390
3391fsnan_out_w:
3392        mov.w           FP_SRC_HI(%a6),%d0      # load upper word of SNAN
3393        bset            &14,%d0                 # set SNAN bit
3394        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3395        ble.b           fsnan_out_w_dn          # yes
3396        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3397        bsr.l           _dmem_write_word        # write the default result
3398
3399        tst.l           %d1                     # did dstore fail?
3400        bne.l           facc_out_w              # yes
3401
3402        bra.w           fsnan_exit
3403fsnan_out_w_dn:
3404        andi.w          &0x0007,%d1
3405        bsr.l           store_dreg_w            # store result to regfile
3406        bra.w           fsnan_exit
3407
3408fsnan_out_l:
3409        mov.l           FP_SRC_HI(%a6),%d0      # load upper longword of SNAN
3410        bset            &30,%d0                 # set SNAN bit
3411        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3412        ble.b           fsnan_out_l_dn          # yes
3413        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3414        bsr.l           _dmem_write_long        # write the default result
3415
3416        tst.l           %d1                     # did dstore fail?
3417        bne.l           facc_out_l              # yes
3418
3419        bra.w           fsnan_exit
3420fsnan_out_l_dn:
3421        andi.w          &0x0007,%d1
3422        bsr.l           store_dreg_l            # store result to regfile
3423        bra.w           fsnan_exit
3424
3425fsnan_out_s:
3426        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3427        ble.b           fsnan_out_d_dn          # yes
3428        mov.l           FP_SRC_EX(%a6),%d0      # fetch SNAN sign
3429        andi.l          &0x80000000,%d0         # keep sign
3430        ori.l           &0x7fc00000,%d0         # insert new exponent,SNAN bit
3431        mov.l           FP_SRC_HI(%a6),%d1      # load mantissa
3432        lsr.l           &0x8,%d1                # shift mantissa for sgl
3433        or.l            %d1,%d0                 # create sgl SNAN
3434        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3435        bsr.l           _dmem_write_long        # write the default result
3436
3437        tst.l           %d1                     # did dstore fail?
3438        bne.l           facc_out_l              # yes
3439
3440        bra.w           fsnan_exit
3441fsnan_out_d_dn:
3442        mov.l           FP_SRC_EX(%a6),%d0      # fetch SNAN sign
3443        andi.l          &0x80000000,%d0         # keep sign
3444        ori.l           &0x7fc00000,%d0         # insert new exponent,SNAN bit
3445        mov.l           %d1,-(%sp)
3446        mov.l           FP_SRC_HI(%a6),%d1      # load mantissa
3447        lsr.l           &0x8,%d1                # shift mantissa for sgl
3448        or.l            %d1,%d0                 # create sgl SNAN
3449        mov.l           (%sp)+,%d1
3450        andi.w          &0x0007,%d1
3451        bsr.l           store_dreg_l            # store result to regfile
3452        bra.w           fsnan_exit
3453
3454fsnan_out_d:
3455        mov.l           FP_SRC_EX(%a6),%d0      # fetch SNAN sign
3456        andi.l          &0x80000000,%d0         # keep sign
3457        ori.l           &0x7ff80000,%d0         # insert new exponent,SNAN bit
3458        mov.l           FP_SRC_HI(%a6),%d1      # load hi mantissa
3459        mov.l           %d0,FP_SCR0_EX(%a6)     # store to temp space
3460        mov.l           &11,%d0                 # load shift amt
3461        lsr.l           %d0,%d1
3462        or.l            %d1,FP_SCR0_EX(%a6)     # create dbl hi
3463        mov.l           FP_SRC_HI(%a6),%d1      # load hi mantissa
3464        andi.l          &0x000007ff,%d1
3465        ror.l           %d0,%d1
3466        mov.l           %d1,FP_SCR0_HI(%a6)     # store to temp space
3467        mov.l           FP_SRC_LO(%a6),%d1      # load lo mantissa
3468        lsr.l           %d0,%d1
3469        or.l            %d1,FP_SCR0_HI(%a6)     # create dbl lo
3470        lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
3471        mov.l           EXC_EA(%a6),%a1         # pass: dst addr
3472        movq.l          &0x8,%d0                # pass: size of 8 bytes
3473        bsr.l           _dmem_write             # write the default result
3474
3475        tst.l           %d1                     # did dstore fail?
3476        bne.l           facc_out_d              # yes
3477
3478        bra.w           fsnan_exit
3479
3480# for extended precision, if the addressing mode is pre-decrement or
3481# post-increment, then the address register did not get updated.
3482# in addition, for pre-decrement, the stacked <ea> is incorrect.
3483fsnan_out_x:
3484        clr.b           SPCOND_FLG(%a6)         # clear special case flag
3485
3486        mov.w           FP_SRC_EX(%a6),FP_SCR0_EX(%a6)
3487        clr.w           2+FP_SCR0(%a6)
3488        mov.l           FP_SRC_HI(%a6),%d0
3489        bset            &30,%d0
3490        mov.l           %d0,FP_SCR0_HI(%a6)
3491        mov.l           FP_SRC_LO(%a6),FP_SCR0_LO(%a6)
3492
3493        btst            &0x5,EXC_SR(%a6)        # supervisor mode exception?
3494        bne.b           fsnan_out_x_s           # yes
3495
3496        mov.l           %usp,%a0                # fetch user stack pointer
3497        mov.l           %a0,EXC_A7(%a6)         # save on stack for calc_ea()
3498        mov.l           (%a6),EXC_A6(%a6)
3499
3500        bsr.l           _calc_ea_fout           # find the correct ea,update An
3501        mov.l           %a0,%a1
3502        mov.l           %a0,EXC_EA(%a6)         # stack correct <ea>
3503
3504        mov.l           EXC_A7(%a6),%a0
3505        mov.l           %a0,%usp                # restore user stack pointer
3506        mov.l           EXC_A6(%a6),(%a6)
3507
3508fsnan_out_x_save:
3509        lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
3510        movq.l          &0xc,%d0                # pass: size of extended
3511        bsr.l           _dmem_write             # write the default result
3512
3513        tst.l           %d1                     # did dstore fail?
3514        bne.l           facc_out_x              # yes
3515
3516        bra.w           fsnan_exit
3517
3518fsnan_out_x_s:
3519        mov.l           (%a6),EXC_A6(%a6)
3520
3521        bsr.l           _calc_ea_fout           # find the correct ea,update An
3522        mov.l           %a0,%a1
3523        mov.l           %a0,EXC_EA(%a6)         # stack correct <ea>
3524
3525        mov.l           EXC_A6(%a6),(%a6)
3526
3527        cmpi.b          SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)?
3528        bne.b           fsnan_out_x_save        # no
3529
3530# the operation was "fmove.x SNAN,-(a7)" from supervisor mode.
3531        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3532        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3533        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3534
3535        frestore        FP_SRC(%a6)
3536
3537        mov.l           EXC_A6(%a6),%a6         # restore frame pointer
3538
3539        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
3540        mov.l           LOCAL_SIZE+EXC_PC+0x2(%sp),LOCAL_SIZE+EXC_PC+0x2-0xc(%sp)
3541        mov.l           LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
3542
3543        mov.l           LOCAL_SIZE+FP_SCR0_EX(%sp),LOCAL_SIZE+EXC_SR(%sp)
3544        mov.l           LOCAL_SIZE+FP_SCR0_HI(%sp),LOCAL_SIZE+EXC_PC+0x2(%sp)
3545        mov.l           LOCAL_SIZE+FP_SCR0_LO(%sp),LOCAL_SIZE+EXC_EA(%sp)
3546
3547        add.l           &LOCAL_SIZE-0x8,%sp
3548
3549        bra.l           _real_snan
3550
3551#########################################################################
3552# XDEF **************************************************************** #
3553#       _fpsp_inex(): 060FPSP entry point for FP Inexact exception.     #
3554#                                                                       #
3555#       This handler should be the first code executed upon taking the  #
3556#       FP Inexact exception in an operating system.                    #
3557#                                                                       #
3558# XREF **************************************************************** #
3559#       _imem_read_long() - read instruction longword                   #
3560#       fix_skewed_ops() - adjust src operand in fsave frame            #
3561#       set_tag_x() - determine optype of src/dst operands              #
3562#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
3563#       unnorm_fix() - change UNNORM operands to NORM or ZERO           #
3564#       load_fpn2() - load dst operand from FP regfile                  #
3565#       smovcr() - emulate an "fmovcr" instruction                      #
3566#       fout() - emulate an opclass 3 instruction                       #
3567#       tbl_unsupp - add of table of emulation routines for opclass 0,2 #
3568#       _real_inex() - "callout" to operating system inexact handler    #
3569#                                                                       #
3570# INPUT *************************************************************** #
3571#       - The system stack contains the FP Inexact exception frame      #
3572#       - The fsave frame contains the source operand                   #
3573#                                                                       #
3574# OUTPUT ************************************************************** #
3575#       - The system stack is unchanged                                 #
3576#       - The fsave frame contains the adjusted src op for opclass 0,2  #
3577#                                                                       #
3578# ALGORITHM *********************************************************** #
3579#       In a system where the FP Inexact exception is enabled, the goal #
3580# is to get to the handler specified at _real_inex(). But, on the 060,  #
3581# for opclass zero and two instruction taking this exception, the       #
3582# hardware doesn't store the correct result to the destination FP       #
3583# register as did the '040 and '881/2. This handler must emulate the    #
3584# instruction in order to get this value and then store it to the       #
3585# correct register before calling _real_inex().                         #
3586#       For opclass 3 instructions, the 060 doesn't store the default   #
3587# inexact result out to memory or data register file as it should.      #
3588# This code must emulate the move out by calling fout() before finally  #
3589# exiting through _real_inex().                                         #
3590#                                                                       #
3591#########################################################################
3592
3593        global          _fpsp_inex
3594_fpsp_inex:
3595
3596        link.w          %a6,&-LOCAL_SIZE        # init stack frame
3597
3598        fsave           FP_SRC(%a6)             # grab the "busy" frame
3599
3600        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3601        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3602        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
3603
3604# the FPIAR holds the "current PC" of the faulting instruction
3605        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3606
3607        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3608        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3609        bsr.l           _imem_read_long         # fetch the instruction words
3610        mov.l           %d0,EXC_OPWORD(%a6)
3611
3612##############################################################################
3613
3614        btst            &13,%d0                 # is instr an fmove out?
3615        bne.w           finex_out               # fmove out
3616
3617
3618# the hardware, for "fabs" and "fneg" w/ a long source format, puts the
3619# longword integer directly into the upper longword of the mantissa along
3620# w/ an exponent value of 0x401e. we convert this to extended precision here.
3621        bfextu          %d0{&19:&3},%d0         # fetch instr size
3622        bne.b           finex_cont              # instr size is not long
3623        cmpi.w          FP_SRC_EX(%a6),&0x401e  # is exponent 0x401e?
3624        bne.b           finex_cont              # no
3625        fmov.l          &0x0,%fpcr
3626        fmov.l          FP_SRC_HI(%a6),%fp0     # load integer src
3627        fmov.x          %fp0,FP_SRC(%a6)        # store integer as extended precision
3628        mov.w           &0xe001,0x2+FP_SRC(%a6)
3629
3630finex_cont:
3631        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3632        bsr.l           fix_skewed_ops          # fix src op
3633
3634# Here, we zero the ccode and exception byte field since we're going to
3635# emulate the whole instruction. Notice, though, that we don't kill the
3636# INEX1 bit. This is because a packed op has long since been converted
3637# to extended before arriving here. Therefore, we need to retain the
3638# INEX1 bit from when the operand was first converted.
3639        andi.l          &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field
3640
3641        fmov.l          &0x0,%fpcr              # zero current control regs
3642        fmov.l          &0x0,%fpsr
3643
3644        bfextu          EXC_EXTWORD(%a6){&0:&6},%d1 # extract upper 6 of cmdreg
3645        cmpi.b          %d1,&0x17               # is op an fmovecr?
3646        beq.w           finex_fmovcr            # yes
3647
3648        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3649        bsr.l           set_tag_x               # tag the operand type
3650        mov.b           %d0,STAG(%a6)           # maybe NORM,DENORM
3651
3652# bits four and five of the fp extension word separate the monadic and dyadic
3653# operations that can pass through fpsp_inex(). remember that fcmp and ftst
3654# will never take this exception, but fsincos will.
3655        btst            &0x5,1+EXC_CMDREG(%a6)  # is operation monadic or dyadic?
3656        beq.b           finex_extract           # monadic
3657
3658        btst            &0x4,1+EXC_CMDREG(%a6)  # is operation an fsincos?
3659        bne.b           finex_extract           # yes
3660
3661        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
3662        bsr.l           load_fpn2               # load dst into FP_DST
3663
3664        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
3665        bsr.l           set_tag_x               # tag the operand type
3666        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
3667        bne.b           finex_op2_done          # no
3668        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
3669finex_op2_done:
3670        mov.b           %d0,DTAG(%a6)           # save dst optype tag
3671
3672finex_extract:
3673        clr.l           %d0
3674        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec/mode
3675
3676        mov.b           1+EXC_CMDREG(%a6),%d1
3677        andi.w          &0x007f,%d1             # extract extension
3678
3679        lea             FP_SRC(%a6),%a0
3680        lea             FP_DST(%a6),%a1
3681
3682        mov.l           (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
3683        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
3684
3685# the operation has been emulated. the result is in fp0.
3686finex_save:
3687        bfextu          EXC_CMDREG(%a6){&6:&3},%d0
3688        bsr.l           store_fpreg
3689
3690finex_exit:
3691        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3692        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3693        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3694
3695        frestore        FP_SRC(%a6)
3696
3697        unlk            %a6
3698        bra.l           _real_inex
3699
3700finex_fmovcr:
3701        clr.l           %d0
3702        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec,mode
3703        mov.b           1+EXC_CMDREG(%a6),%d1
3704        andi.l          &0x0000007f,%d1         # pass rom offset
3705        bsr.l           smovcr
3706        bra.b           finex_save
3707
3708########################################################################
3709
3710#
3711# the hardware does not save the default result to memory on enabled
3712# inexact exceptions. we do this here before passing control to
3713# the user inexact handler.
3714#
3715# byte, word, and long destination format operations can pass
3716# through here. so can double and single precision.
3717# although packed opclass three operations can take inexact
3718# exceptions, they won't pass through here since they are caught
3719# first by the unsupported data format exception handler. that handler
3720# sends them directly to _real_inex() if necessary.
3721#
3722finex_out:
3723
3724        mov.b           &NORM,STAG(%a6)         # src is a NORM
3725
3726        clr.l           %d0
3727        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec,mode
3728
3729        andi.l          &0xffff00ff,USER_FPSR(%a6) # zero exception field
3730
3731        lea             FP_SRC(%a6),%a0         # pass ptr to src operand
3732
3733        bsr.l           fout                    # store the default result
3734
3735        bra.b           finex_exit
3736
3737#########################################################################
3738# XDEF **************************************************************** #
3739#       _fpsp_dz(): 060FPSP entry point for FP DZ exception.            #
3740#                                                                       #
3741#       This handler should be the first code executed upon taking      #
3742#       the FP DZ exception in an operating system.                     #
3743#                                                                       #
3744# XREF **************************************************************** #
3745#       _imem_read_long() - read instruction longword from memory       #
3746#       fix_skewed_ops() - adjust fsave operand                         #
3747#       _real_dz() - "callout" exit point from FP DZ handler            #
3748#                                                                       #
3749# INPUT *************************************************************** #
3750#       - The system stack contains the FP DZ exception stack.          #
3751#       - The fsave frame contains the source operand.                  #
3752#                                                                       #
3753# OUTPUT ************************************************************** #
3754#       - The system stack contains the FP DZ exception stack.          #
3755#       - The fsave frame contains the adjusted source operand.         #
3756#                                                                       #
3757# ALGORITHM *********************************************************** #
3758#       In a system where the DZ exception is enabled, the goal is to   #
3759# get to the handler specified at _real_dz(). But, on the 060, when the #
3760# exception is taken, the input operand in the fsave state frame may    #
3761# be incorrect for some cases and need to be adjusted. So, this package #
3762# adjusts the operand using fix_skewed_ops() and then branches to       #
3763# _real_dz().                                                           #
3764#                                                                       #
3765#########################################################################
3766
3767        global          _fpsp_dz
3768_fpsp_dz:
3769
3770        link.w          %a6,&-LOCAL_SIZE        # init stack frame
3771
3772        fsave           FP_SRC(%a6)             # grab the "busy" frame
3773
3774        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3775        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3776        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
3777
3778# the FPIAR holds the "current PC" of the faulting instruction
3779        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3780
3781        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3782        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3783        bsr.l           _imem_read_long         # fetch the instruction words
3784        mov.l           %d0,EXC_OPWORD(%a6)
3785
3786##############################################################################
3787
3788
3789# here, we simply see if the operand in the fsave frame needs to be "unskewed".
3790# this would be the case for opclass two operations with a source zero
3791# in the sgl or dbl format.
3792        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3793        bsr.l           fix_skewed_ops          # fix src op
3794
3795fdz_exit:
3796        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3797        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3798        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3799
3800        frestore        FP_SRC(%a6)
3801
3802        unlk            %a6
3803        bra.l           _real_dz
3804
3805#########################################################################
3806# XDEF **************************************************************** #
3807#       _fpsp_fline(): 060FPSP entry point for "Line F emulator"        #
3808#                      exception when the "reduced" version of the      #
3809#                      FPSP is implemented that does not emulate        #
3810#                      FP unimplemented instructions.                   #
3811#                                                                       #
3812#       This handler should be the first code executed upon taking a    #
3813#       "Line F Emulator" exception in an operating system integrating  #
3814#       the reduced version of 060FPSP.                                 #
3815#                                                                       #
3816# XREF **************************************************************** #
3817#       _real_fpu_disabled() - Handle "FPU disabled" exceptions         #
3818#       _real_fline() - Handle all other cases (treated equally)        #
3819#                                                                       #
3820# INPUT *************************************************************** #
3821#       - The system stack contains a "Line F Emulator" exception       #
3822#         stack frame.                                                  #
3823#                                                                       #
3824# OUTPUT ************************************************************** #
3825#       - The system stack is unchanged.                                #
3826#                                                                       #
3827# ALGORITHM *********************************************************** #
3828#       When a "Line F Emulator" exception occurs in a system where     #
3829# "FPU Unimplemented" instructions will not be emulated, the exception  #
3830# can occur because then FPU is disabled or the instruction is to be    #
3831# classifed as "Line F". This module determines which case exists and   #
3832# calls the appropriate "callout".                                      #
3833#                                                                       #
3834#########################################################################
3835
3836        global          _fpsp_fline
3837_fpsp_fline:
3838
3839# check to see if the FPU is disabled. if so, jump to the OS entry
3840# point for that condition.
3841        cmpi.w          0x6(%sp),&0x402c
3842        beq.l           _real_fpu_disabled
3843
3844        bra.l           _real_fline
3845
3846#########################################################################
3847# XDEF **************************************************************** #
3848#       _dcalc_ea(): calc correct <ea> from <ea> stacked on exception   #
3849#                                                                       #
3850# XREF **************************************************************** #
3851#       inc_areg() - increment an address register                      #
3852#       dec_areg() - decrement an address register                      #
3853#                                                                       #
3854# INPUT *************************************************************** #
3855#       d0 = number of bytes to adjust <ea> by                          #
3856#                                                                       #
3857# OUTPUT ************************************************************** #
3858#       None                                                            #
3859#                                                                       #
3860# ALGORITHM *********************************************************** #
3861# "Dummy" CALCulate Effective Address:                                  #
3862#       The stacked <ea> for FP unimplemented instructions and opclass  #
3863#       two packed instructions is correct with the exception of...     #
3864#                                                                       #
3865#       1) -(An)   : The register is not updated regardless of size.    #
3866#                    Also, for extended precision and packed, the       #
3867#                    stacked <ea> value is 8 bytes too big              #
3868#       2) (An)+   : The register is not updated.                       #
3869#       3) #<data> : The upper longword of the immediate operand is     #
3870#                    stacked b,w,l and s sizes are completely stacked.  #
3871#                    d,x, and p are not.                                #
3872#                                                                       #
3873#########################################################################
3874
3875        global          _dcalc_ea
3876_dcalc_ea:
3877        mov.l           %d0, %a0                # move # bytes to %a0
3878
3879        mov.b           1+EXC_OPWORD(%a6), %d0  # fetch opcode word
3880        mov.l           %d0, %d1                # make a copy
3881
3882        andi.w          &0x38, %d0              # extract mode field
3883        andi.l          &0x7, %d1               # extract reg  field
3884
3885        cmpi.b          %d0,&0x18               # is mode (An)+ ?
3886        beq.b           dcea_pi                 # yes
3887
3888        cmpi.b          %d0,&0x20               # is mode -(An) ?
3889        beq.b           dcea_pd                 # yes
3890
3891        or.w            %d1,%d0                 # concat mode,reg
3892        cmpi.b          %d0,&0x3c               # is mode #<data>?
3893
3894        beq.b           dcea_imm                # yes
3895
3896        mov.l           EXC_EA(%a6),%a0         # return <ea>
3897        rts
3898
3899# need to set immediate data flag here since we'll need to do
3900# an imem_read to fetch this later.
3901dcea_imm:
3902        mov.b           &immed_flg,SPCOND_FLG(%a6)
3903        lea             ([USER_FPIAR,%a6],0x4),%a0 # no; return <ea>
3904        rts
3905
3906# here, the <ea> is stacked correctly. however, we must update the
3907# address register...
3908dcea_pi:
3909        mov.l           %a0,%d0                 # pass amt to inc by
3910        bsr.l           inc_areg                # inc addr register
3911
3912        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
3913        rts
3914
3915# the <ea> is stacked correctly for all but extended and packed which
3916# the <ea>s are 8 bytes too large.
3917# it would make no sense to have a pre-decrement to a7 in supervisor
3918# mode so we don't even worry about this tricky case here : )
3919dcea_pd:
3920        mov.l           %a0,%d0                 # pass amt to dec by
3921        bsr.l           dec_areg                # dec addr register
3922
3923        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
3924
3925        cmpi.b          %d0,&0xc                # is opsize ext or packed?
3926        beq.b           dcea_pd2                # yes
3927        rts
3928dcea_pd2:
3929        sub.l           &0x8,%a0                # correct <ea>
3930        mov.l           %a0,EXC_EA(%a6)         # put correct <ea> on stack
3931        rts
3932
3933#########################################################################
3934# XDEF **************************************************************** #
3935#       _calc_ea_fout(): calculate correct stacked <ea> for extended    #
3936#                        and packed data opclass 3 operations.          #
3937#                                                                       #
3938# XREF **************************************************************** #
3939#       None                                                            #
3940#                                                                       #
3941# INPUT *************************************************************** #
3942#       None                                                            #
3943#                                                                       #
3944# OUTPUT ************************************************************** #
3945#       a0 = return correct effective address                           #
3946#                                                                       #
3947# ALGORITHM *********************************************************** #
3948#       For opclass 3 extended and packed data operations, the <ea>     #
3949# stacked for the exception is incorrect for -(an) and (an)+ addressing #
3950# modes. Also, while we're at it, the index register itself must get    #
3951# updated.                                                              #
3952#       So, for -(an), we must subtract 8 off of the stacked <ea> value #
3953# and return that value as the correct <ea> and store that value in An. #
3954# For (an)+, the stacked <ea> is correct but we must adjust An by +12.  #
3955#                                                                       #
3956#########################################################################
3957
3958# This calc_ea is currently used to retrieve the correct <ea>
3959# for fmove outs of type extended and packed.
3960        global          _calc_ea_fout
3961_calc_ea_fout:
3962        mov.b           1+EXC_OPWORD(%a6),%d0   # fetch opcode word
3963        mov.l           %d0,%d1                 # make a copy
3964
3965        andi.w          &0x38,%d0               # extract mode field
3966        andi.l          &0x7,%d1                # extract reg  field
3967
3968        cmpi.b          %d0,&0x18               # is mode (An)+ ?
3969        beq.b           ceaf_pi                 # yes
3970
3971        cmpi.b          %d0,&0x20               # is mode -(An) ?
3972        beq.w           ceaf_pd                 # yes
3973
3974        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
3975        rts
3976
3977# (An)+ : extended and packed fmove out
3978#       : stacked <ea> is correct
3979#       : "An" not updated
3980ceaf_pi:
3981        mov.w           (tbl_ceaf_pi.b,%pc,%d1.w*2),%d1
3982        mov.l           EXC_EA(%a6),%a0
3983        jmp             (tbl_ceaf_pi.b,%pc,%d1.w*1)
3984
3985        swbeg           &0x8
3986tbl_ceaf_pi:
3987        short           ceaf_pi0 - tbl_ceaf_pi
3988        short           ceaf_pi1 - tbl_ceaf_pi
3989        short           ceaf_pi2 - tbl_ceaf_pi
3990        short           ceaf_pi3 - tbl_ceaf_pi
3991        short           ceaf_pi4 - tbl_ceaf_pi
3992        short           ceaf_pi5 - tbl_ceaf_pi
3993        short           ceaf_pi6 - tbl_ceaf_pi
3994        short           ceaf_pi7 - tbl_ceaf_pi
3995
3996ceaf_pi0:
3997        addi.l          &0xc,EXC_DREGS+0x8(%a6)
3998        rts
3999ceaf_pi1:
4000        addi.l          &0xc,EXC_DREGS+0xc(%a6)
4001        rts
4002ceaf_pi2:
4003        add.l           &0xc,%a2
4004        rts
4005ceaf_pi3:
4006        add.l           &0xc,%a3
4007        rts
4008ceaf_pi4:
4009        add.l           &0xc,%a4
4010        rts
4011ceaf_pi5:
4012        add.l           &0xc,%a5
4013        rts
4014ceaf_pi6:
4015        addi.l          &0xc,EXC_A6(%a6)
4016        rts
4017ceaf_pi7:
4018        mov.b           &mia7_flg,SPCOND_FLG(%a6)
4019        addi.l          &0xc,EXC_A7(%a6)
4020        rts
4021
4022# -(An) : extended and packed fmove out
4023#       : stacked <ea> = actual <ea> + 8
4024#       : "An" not updated
4025ceaf_pd:
4026        mov.w           (tbl_ceaf_pd.b,%pc,%d1.w*2),%d1
4027        mov.l           EXC_EA(%a6),%a0
4028        sub.l           &0x8,%a0
4029        sub.l           &0x8,EXC_EA(%a6)
4030        jmp             (tbl_ceaf_pd.b,%pc,%d1.w*1)
4031
4032        swbeg           &0x8
4033tbl_ceaf_pd:
4034        short           ceaf_pd0 - tbl_ceaf_pd
4035        short           ceaf_pd1 - tbl_ceaf_pd
4036        short           ceaf_pd2 - tbl_ceaf_pd
4037        short           ceaf_pd3 - tbl_ceaf_pd
4038        short           ceaf_pd4 - tbl_ceaf_pd
4039        short           ceaf_pd5 - tbl_ceaf_pd
4040        short           ceaf_pd6 - tbl_ceaf_pd
4041        short           ceaf_pd7 - tbl_ceaf_pd
4042
4043ceaf_pd0:
4044        mov.l           %a0,EXC_DREGS+0x8(%a6)
4045        rts
4046ceaf_pd1:
4047        mov.l           %a0,EXC_DREGS+0xc(%a6)
4048        rts
4049ceaf_pd2:
4050        mov.l           %a0,%a2
4051        rts
4052ceaf_pd3:
4053        mov.l           %a0,%a3
4054        rts
4055ceaf_pd4:
4056        mov.l           %a0,%a4
4057        rts
4058ceaf_pd5:
4059        mov.l           %a0,%a5
4060        rts
4061ceaf_pd6:
4062        mov.l           %a0,EXC_A6(%a6)
4063        rts
4064ceaf_pd7:
4065        mov.l           %a0,EXC_A7(%a6)
4066        mov.b           &mda7_flg,SPCOND_FLG(%a6)
4067        rts
4068
4069#
4070# This table holds the offsets of the emulation routines for each individual
4071# math operation relative to the address of this table. Included are
4072# routines like fadd/fmul/fabs. The transcendentals ARE NOT. This is because
4073# this table is for the version if the 060FPSP without transcendentals.
4074# The location within the table is determined by the extension bits of the
4075# operation longword.
4076#
4077
4078        swbeg           &109
4079tbl_unsupp:
4080        long            fin             - tbl_unsupp    # 00: fmove
4081        long            fint            - tbl_unsupp    # 01: fint
4082        long            tbl_unsupp      - tbl_unsupp    # 02: fsinh
4083        long            fintrz          - tbl_unsupp    # 03: fintrz
4084        long            fsqrt           - tbl_unsupp    # 04: fsqrt
4085        long            tbl_unsupp      - tbl_unsupp
4086        long            tbl_unsupp      - tbl_unsupp    # 06: flognp1
4087        long            tbl_unsupp      - tbl_unsupp
4088        long            tbl_unsupp      - tbl_unsupp    # 08: fetoxm1
4089        long            tbl_unsupp      - tbl_unsupp    # 09: ftanh
4090        long            tbl_unsupp      - tbl_unsupp    # 0a: fatan
4091        long            tbl_unsupp      - tbl_unsupp
4092        long            tbl_unsupp      - tbl_unsupp    # 0c: fasin
4093        long            tbl_unsupp      - tbl_unsupp    # 0d: fatanh
4094        long            tbl_unsupp      - tbl_unsupp    # 0e: fsin
4095        long            tbl_unsupp      - tbl_unsupp    # 0f: ftan
4096        long            tbl_unsupp      - tbl_unsupp    # 10: fetox
4097        long            tbl_unsupp      - tbl_unsupp    # 11: ftwotox
4098        long            tbl_unsupp      - tbl_unsupp    # 12: ftentox
4099        long            tbl_unsupp      - tbl_unsupp
4100        long            tbl_unsupp      - tbl_unsupp    # 14: flogn
4101        long            tbl_unsupp      - tbl_unsupp    # 15: flog10
4102        long            tbl_unsupp      - tbl_unsupp    # 16: flog2
4103        long            tbl_unsupp      - tbl_unsupp
4104        long            fabs            - tbl_unsupp    # 18: fabs
4105        long            tbl_unsupp      - tbl_unsupp    # 19: fcosh
4106        long            fneg            - tbl_unsupp    # 1a: fneg
4107        long            tbl_unsupp      - tbl_unsupp
4108        long            tbl_unsupp      - tbl_unsupp    # 1c: facos
4109        long            tbl_unsupp      - tbl_unsupp    # 1d: fcos
4110        long            tbl_unsupp      - tbl_unsupp    # 1e: fgetexp
4111        long            tbl_unsupp      - tbl_unsupp    # 1f: fgetman
4112        long            fdiv            - tbl_unsupp    # 20: fdiv
4113        long            tbl_unsupp      - tbl_unsupp    # 21: fmod
4114        long            fadd            - tbl_unsupp    # 22: fadd
4115        long            fmul            - tbl_unsupp    # 23: fmul
4116        long            fsgldiv         - tbl_unsupp    # 24: fsgldiv
4117        long            tbl_unsupp      - tbl_unsupp    # 25: frem
4118        long            tbl_unsupp      - tbl_unsupp    # 26: fscale
4119        long            fsglmul         - tbl_unsupp    # 27: fsglmul
4120        long            fsub            - tbl_unsupp    # 28: fsub
4121        long            tbl_unsupp      - tbl_unsupp
4122        long            tbl_unsupp      - tbl_unsupp
4123        long            tbl_unsupp      - tbl_unsupp
4124        long            tbl_unsupp      - tbl_unsupp
4125        long            tbl_unsupp      - tbl_unsupp
4126        long            tbl_unsupp      - tbl_unsupp
4127        long            tbl_unsupp      - tbl_unsupp
4128        long            tbl_unsupp      - tbl_unsupp    # 30: fsincos
4129        long            tbl_unsupp      - tbl_unsupp    # 31: fsincos
4130        long            tbl_unsupp      - tbl_unsupp    # 32: fsincos
4131        long            tbl_unsupp      - tbl_unsupp    # 33: fsincos
4132        long            tbl_unsupp      - tbl_unsupp    # 34: fsincos
4133        long            tbl_unsupp      - tbl_unsupp    # 35: fsincos
4134        long            tbl_unsupp      - tbl_unsupp    # 36: fsincos
4135        long            tbl_unsupp      - tbl_unsupp    # 37: fsincos
4136        long            fcmp            - tbl_unsupp    # 38: fcmp
4137        long            tbl_unsupp      - tbl_unsupp
4138        long            ftst            - tbl_unsupp    # 3a: ftst
4139        long            tbl_unsupp      - tbl_unsupp
4140        long            tbl_unsupp      - tbl_unsupp
4141        long            tbl_unsupp      - tbl_unsupp
4142        long            tbl_unsupp      - tbl_unsupp
4143        long            tbl_unsupp      - tbl_unsupp
4144        long            fsin            - tbl_unsupp    # 40: fsmove
4145        long            fssqrt          - tbl_unsupp    # 41: fssqrt
4146        long            tbl_unsupp      - tbl_unsupp
4147        long            tbl_unsupp      - tbl_unsupp
4148        long            fdin            - tbl_unsupp    # 44: fdmove
4149        long            fdsqrt          - tbl_unsupp    # 45: fdsqrt
4150        long            tbl_unsupp      - tbl_unsupp
4151        long            tbl_unsupp      - tbl_unsupp
4152        long            tbl_unsupp      - tbl_unsupp
4153        long            tbl_unsupp      - tbl_unsupp
4154        long            tbl_unsupp      - tbl_unsupp
4155        long            tbl_unsupp      - tbl_unsupp
4156        long            tbl_unsupp      - tbl_unsupp
4157        long            tbl_unsupp      - tbl_unsupp
4158        long            tbl_unsupp      - tbl_unsupp
4159        long            tbl_unsupp      - tbl_unsupp
4160        long            tbl_unsupp      - tbl_unsupp
4161        long            tbl_unsupp      - tbl_unsupp
4162        long            tbl_unsupp      - tbl_unsupp
4163        long            tbl_unsupp      - tbl_unsupp
4164        long            tbl_unsupp      - tbl_unsupp
4165        long            tbl_unsupp      - tbl_unsupp
4166        long            tbl_unsupp      - tbl_unsupp
4167        long            tbl_unsupp      - tbl_unsupp
4168        long            fsabs           - tbl_unsupp    # 58: fsabs
4169        long            tbl_unsupp      - tbl_unsupp
4170        long            fsneg           - tbl_unsupp    # 5a: fsneg
4171        long            tbl_unsupp      - tbl_unsupp
4172        long            fdabs           - tbl_unsupp    # 5c: fdabs
4173        long            tbl_unsupp      - tbl_unsupp
4174        long            fdneg           - tbl_unsupp    # 5e: fdneg
4175        long            tbl_unsupp      - tbl_unsupp
4176        long            fsdiv           - tbl_unsupp    # 60: fsdiv
4177        long            tbl_unsupp      - tbl_unsupp
4178        long            fsadd           - tbl_unsupp    # 62: fsadd
4179        long            fsmul           - tbl_unsupp    # 63: fsmul
4180        long            fddiv           - tbl_unsupp    # 64: fddiv
4181        long            tbl_unsupp      - tbl_unsupp
4182        long            fdadd           - tbl_unsupp    # 66: fdadd
4183        long            fdmul           - tbl_unsupp    # 67: fdmul
4184        long            fssub           - tbl_unsupp    # 68: fssub
4185        long            tbl_unsupp      - tbl_unsupp
4186        long            tbl_unsupp      - tbl_unsupp
4187        long            tbl_unsupp      - tbl_unsupp
4188        long            fdsub           - tbl_unsupp    # 6c: fdsub
4189
4190#################################################
4191# Add this here so non-fp modules can compile.
4192# (smovcr is called from fpsp_inex.)
4193        global          smovcr
4194smovcr:
4195        bra.b           smovcr
4196
4197#########################################################################
4198# XDEF **************************************************************** #
4199#       fmovm_dynamic(): emulate "fmovm" dynamic instruction            #
4200#                                                                       #
4201# XREF **************************************************************** #
4202#       fetch_dreg() - fetch data register                              #
4203#       {i,d,}mem_read() - fetch data from memory                       #
4204#       _mem_write() - write data to memory                             #
4205#       iea_iacc() - instruction memory access error occurred           #
4206#       iea_dacc() - data memory access error occurred                  #
4207#       restore() - restore An index regs if access error occurred      #
4208#                                                                       #
4209# INPUT *************************************************************** #
4210#       None                                                            #
4211#                                                                       #
4212# OUTPUT ************************************************************** #
4213#       If instr is "fmovm Dn,-(A7)" from supervisor mode,              #
4214#               d0 = size of dump                                       #
4215#               d1 = Dn                                                 #
4216#       Else if instruction access error,                               #
4217#               d0 = FSLW                                               #
4218#       Else if data access error,                                      #
4219#               d0 = FSLW                                               #
4220#               a0 = address of fault                                   #
4221#       Else                                                            #
4222#               none.                                                   #
4223#                                                                       #
4224# ALGORITHM *********************************************************** #
4225#       The effective address must be calculated since this is entered  #
4226# from an "Unimplemented Effective Address" exception handler. So, we   #
4227# have our own fcalc_ea() routine here. If an access error is flagged   #
4228# by a _{i,d,}mem_read() call, we must exit through the special         #
4229# handler.                                                              #
4230#       The data register is determined and its value loaded to get the #
4231# string of FP registers affected. This value is used as an index into  #
4232# a lookup table such that we can determine the number of bytes         #
4233# involved.                                                             #
4234#       If the instruction is "fmovm.x <ea>,Dn", a _mem_read() is used  #
4235# to read in all FP values. Again, _mem_read() may fail and require a   #
4236# special exit.                                                         #
4237#       If the instruction is "fmovm.x DN,<ea>", a _mem_write() is used #
4238# to write all FP values. _mem_write() may also fail.                   #
4239#       If the instruction is "fmovm.x DN,-(a7)" from supervisor mode,  #
4240# then we return the size of the dump and the string to the caller      #
4241# so that the move can occur outside of this routine. This special      #
4242# case is required so that moves to the system stack are handled        #
4243# correctly.                                                            #
4244#                                                                       #
4245# DYNAMIC:                                                              #
4246#       fmovm.x dn, <ea>                                                #
4247#       fmovm.x <ea>, dn                                                #
4248#                                                                       #
4249#             <WORD 1>                <WORD2>                           #
4250#       1111 0010 00 |<ea>|     11@& 1000 0$$$ 0000                     #
4251#                                                                       #
4252#       & = (0): predecrement addressing mode                           #
4253#           (1): postincrement or control addressing mode               #
4254#       @ = (0): move listed regs from memory to the FPU                #
4255#           (1): move listed regs from the FPU to memory                #
4256#       $$$    : index of data register holding reg select mask         #
4257#                                                                       #
4258# NOTES:                                                                #
4259#       If the data register holds a zero, then the                     #
4260#       instruction is a nop.                                           #
4261#                                                                       #
4262#########################################################################
4263
4264        global          fmovm_dynamic
4265fmovm_dynamic:
4266
4267# extract the data register in which the bit string resides...
4268        mov.b           1+EXC_EXTWORD(%a6),%d1  # fetch extword
4269        andi.w          &0x70,%d1               # extract reg bits
4270        lsr.b           &0x4,%d1                # shift into lo bits
4271
4272# fetch the bit string into d0...
4273        bsr.l           fetch_dreg              # fetch reg string
4274
4275        andi.l          &0x000000ff,%d0         # keep only lo byte
4276
4277        mov.l           %d0,-(%sp)              # save strg
4278        mov.b           (tbl_fmovm_size.w,%pc,%d0),%d0
4279        mov.l           %d0,-(%sp)              # save size
4280        bsr.l           fmovm_calc_ea           # calculate <ea>
4281        mov.l           (%sp)+,%d0              # restore size
4282        mov.l           (%sp)+,%d1              # restore strg
4283
4284# if the bit string is a zero, then the operation is a no-op
4285# but, make sure that we've calculated ea and advanced the opword pointer
4286        beq.w           fmovm_data_done
4287
4288# separate move ins from move outs...
4289        btst            &0x5,EXC_EXTWORD(%a6)   # is it a move in or out?
4290        beq.w           fmovm_data_in           # it's a move out
4291
4292#############
4293# MOVE OUT: #
4294#############
4295fmovm_data_out:
4296        btst            &0x4,EXC_EXTWORD(%a6)   # control or predecrement?
4297        bne.w           fmovm_out_ctrl          # control
4298
4299############################
4300fmovm_out_predec:
4301# for predecrement mode, the bit string is the opposite of both control
4302# operations and postincrement mode. (bit7 = FP7 ... bit0 = FP0)
4303# here, we convert it to be just like the others...
4304        mov.b           (tbl_fmovm_convert.w,%pc,%d1.w*1),%d1
4305
4306        btst            &0x5,EXC_SR(%a6)        # user or supervisor mode?
4307        beq.b           fmovm_out_ctrl          # user
4308
4309fmovm_out_predec_s:
4310        cmpi.b          SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)?
4311        bne.b           fmovm_out_ctrl
4312
4313# the operation was unfortunately an: fmovm.x dn,-(sp)
4314# called from supervisor mode.
4315# we're also passing "size" and "strg" back to the calling routine
4316        rts
4317
4318############################
4319fmovm_out_ctrl:
4320        mov.l           %a0,%a1                 # move <ea> to a1
4321
4322        sub.l           %d0,%sp                 # subtract size of dump
4323        lea             (%sp),%a0
4324
4325        tst.b           %d1                     # should FP0 be moved?
4326        bpl.b           fmovm_out_ctrl_fp1      # no
4327
4328        mov.l           0x0+EXC_FP0(%a6),(%a0)+ # yes
4329        mov.l           0x4+EXC_FP0(%a6),(%a0)+
4330        mov.l           0x8+EXC_FP0(%a6),(%a0)+
4331
4332fmovm_out_ctrl_fp1:
4333        lsl.b           &0x1,%d1                # should FP1 be moved?
4334        bpl.b           fmovm_out_ctrl_fp2      # no
4335
4336        mov.l           0x0+EXC_FP1(%a6),(%a0)+ # yes
4337        mov.l           0x4+EXC_FP1(%a6),(%a0)+
4338        mov.l           0x8+EXC_FP1(%a6),(%a0)+
4339
4340fmovm_out_ctrl_fp2:
4341        lsl.b           &0x1,%d1                # should FP2 be moved?
4342        bpl.b           fmovm_out_ctrl_fp3      # no
4343
4344        fmovm.x         &0x20,(%a0)             # yes
4345        add.l           &0xc,%a0
4346
4347fmovm_out_ctrl_fp3:
4348        lsl.b           &0x1,%d1                # should FP3 be moved?
4349        bpl.b           fmovm_out_ctrl_fp4      # no
4350
4351        fmovm.x         &0x10,(%a0)             # yes
4352        add.l           &0xc,%a0
4353
4354fmovm_out_ctrl_fp4:
4355        lsl.b           &0x1,%d1                # should FP4 be moved?
4356        bpl.b           fmovm_out_ctrl_fp5      # no
4357
4358        fmovm.x         &0x08,(%a0)             # yes
4359        add.l           &0xc,%a0
4360
4361fmovm_out_ctrl_fp5:
4362        lsl.b           &0x1,%d1                # should FP5 be moved?
4363        bpl.b           fmovm_out_ctrl_fp6      # no
4364
4365        fmovm.x         &0x04,(%a0)             # yes
4366        add.l           &0xc,%a0
4367
4368fmovm_out_ctrl_fp6:
4369        lsl.b           &0x1,%d1                # should FP6 be moved?
4370        bpl.b           fmovm_out_ctrl_fp7      # no
4371
4372        fmovm.x         &0x02,(%a0)             # yes
4373        add.l           &0xc,%a0
4374
4375fmovm_out_ctrl_fp7:
4376        lsl.b           &0x1,%d1                # should FP7 be moved?
4377        bpl.b           fmovm_out_ctrl_done     # no
4378
4379        fmovm.x         &0x01,(%a0)             # yes
4380        add.l           &0xc,%a0
4381
4382fmovm_out_ctrl_done:
4383        mov.l           %a1,L_SCR1(%a6)
4384
4385        lea             (%sp),%a0               # pass: supervisor src
4386        mov.l           %d0,-(%sp)              # save size
4387        bsr.l           _dmem_write             # copy data to user mem
4388
4389        mov.l           (%sp)+,%d0
4390        add.l           %d0,%sp                 # clear fpreg data from stack
4391
4392        tst.l           %d1                     # did dstore err?
4393        bne.w           fmovm_out_err           # yes
4394
4395        rts
4396
4397############
4398# MOVE IN: #
4399############
4400fmovm_data_in:
4401        mov.l           %a0,L_SCR1(%a6)
4402
4403        sub.l           %d0,%sp                 # make room for fpregs
4404        lea             (%sp),%a1
4405
4406        mov.l           %d1,-(%sp)              # save bit string for later
4407        mov.l           %d0,-(%sp)              # save # of bytes
4408
4409        bsr.l           _dmem_read              # copy data from user mem
4410
4411        mov.l           (%sp)+,%d0              # retrieve # of bytes
4412
4413        tst.l           %d1                     # did dfetch fail?
4414        bne.w           fmovm_in_err            # yes
4415
4416        mov.l           (%sp)+,%d1              # load bit string
4417
4418        lea             (%sp),%a0               # addr of stack
4419
4420        tst.b           %d1                     # should FP0 be moved?
4421        bpl.b           fmovm_data_in_fp1       # no
4422
4423        mov.l           (%a0)+,0x0+EXC_FP0(%a6) # yes
4424        mov.l           (%a0)+,0x4+EXC_FP0(%a6)
4425        mov.l           (%a0)+,0x8+EXC_FP0(%a6)
4426
4427fmovm_data_in_fp1:
4428        lsl.b           &0x1,%d1                # should FP1 be moved?
4429        bpl.b           fmovm_data_in_fp2       # no
4430
4431        mov.l           (%a0)+,0x0+EXC_FP1(%a6) # yes
4432        mov.l           (%a0)+,0x4+EXC_FP1(%a6)
4433        mov.l           (%a0)+,0x8+EXC_FP1(%a6)
4434
4435fmovm_data_in_fp2:
4436        lsl.b           &0x1,%d1                # should FP2 be moved?
4437        bpl.b           fmovm_data_in_fp3       # no
4438
4439        fmovm.x         (%a0)+,&0x20            # yes
4440
4441fmovm_data_in_fp3:
4442        lsl.b           &0x1,%d1                # should FP3 be moved?
4443        bpl.b           fmovm_data_in_fp4       # no
4444
4445        fmovm.x         (%a0)+,&0x10            # yes
4446
4447fmovm_data_in_fp4:
4448        lsl.b           &0x1,%d1                # should FP4 be moved?
4449        bpl.b           fmovm_data_in_fp5       # no
4450
4451        fmovm.x         (%a0)+,&0x08            # yes
4452
4453fmovm_data_in_fp5:
4454        lsl.b           &0x1,%d1                # should FP5 be moved?
4455        bpl.b           fmovm_data_in_fp6       # no
4456
4457        fmovm.x         (%a0)+,&0x04            # yes
4458
4459fmovm_data_in_fp6:
4460        lsl.b           &0x1,%d1                # should FP6 be moved?
4461        bpl.b           fmovm_data_in_fp7       # no
4462
4463        fmovm.x         (%a0)+,&0x02            # yes
4464
4465fmovm_data_in_fp7:
4466        lsl.b           &0x1,%d1                # should FP7 be moved?
4467        bpl.b           fmovm_data_in_done      # no
4468
4469        fmovm.x         (%a0)+,&0x01            # yes
4470
4471fmovm_data_in_done:
4472        add.l           %d0,%sp                 # remove fpregs from stack
4473        rts
4474
4475#####################################
4476
4477fmovm_data_done:
4478        rts
4479
4480##############################################################################
4481
4482#
4483# table indexed by the operation's bit string that gives the number
4484# of bytes that will be moved.
4485#
4486# number of bytes = (# of 1's in bit string) * 12(bytes/fpreg)
4487#
4488tbl_fmovm_size:
4489        byte    0x00,0x0c,0x0c,0x18,0x0c,0x18,0x18,0x24
4490        byte    0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4491        byte    0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4492        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4493        byte    0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4494        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4495        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4496        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4497        byte    0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4498        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4499        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4500        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4501        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4502        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4503        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4504        byte    0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4505        byte    0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4506        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4507        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4508        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4509        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4510        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4511        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4512        byte    0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4513        byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4514        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4515        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4516        byte    0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4517        byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4518        byte    0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4519        byte    0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4520        byte    0x3c,0x48,0x48,0x54,0x48,0x54,0x54,0x60
4521
4522#
4523# table to convert a pre-decrement bit string into a post-increment
4524# or control bit string.
4525# ex:   0x00    ==>     0x00
4526#       0x01    ==>     0x80
4527#       0x02    ==>     0x40
4528#               .
4529#               .
4530#       0xfd    ==>     0xbf
4531#       0xfe    ==>     0x7f
4532#       0xff    ==>     0xff
4533#
4534tbl_fmovm_convert:
4535        byte    0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0
4536        byte    0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0
4537        byte    0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8
4538        byte    0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8
4539        byte    0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4
4540        byte    0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4
4541        byte    0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec
4542        byte    0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc
4543        byte    0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2
4544        byte    0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2
4545        byte    0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea
4546        byte    0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa
4547        byte    0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6
4548        byte    0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6
4549        byte    0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee
4550        byte    0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe
4551        byte    0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1
4552        byte    0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1
4553        byte    0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9
4554        byte    0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9
4555        byte    0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5
4556        byte    0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5
4557        byte    0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed
4558        byte    0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd
4559        byte    0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3
4560        byte    0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3
4561        byte    0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb
4562        byte    0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb
4563        byte    0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7
4564        byte    0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7
4565        byte    0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef
4566        byte    0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
4567
4568        global          fmovm_calc_ea
4569###############################################
4570# _fmovm_calc_ea: calculate effective address #
4571###############################################
4572fmovm_calc_ea:
4573        mov.l           %d0,%a0                 # move # bytes to a0
4574
4575# currently, MODE and REG are taken from the EXC_OPWORD. this could be
4576# easily changed if they were inputs passed in registers.
4577        mov.w           EXC_OPWORD(%a6),%d0     # fetch opcode word
4578        mov.w           %d0,%d1                 # make a copy
4579
4580        andi.w          &0x3f,%d0               # extract mode field
4581        andi.l          &0x7,%d1                # extract reg  field
4582
4583# jump to the corresponding function for each {MODE,REG} pair.
4584        mov.w           (tbl_fea_mode.b,%pc,%d0.w*2),%d0 # fetch jmp distance
4585        jmp             (tbl_fea_mode.b,%pc,%d0.w*1) # jmp to correct ea mode
4586
4587        swbeg           &64
4588tbl_fea_mode:
4589        short           tbl_fea_mode    -       tbl_fea_mode
4590        short           tbl_fea_mode    -       tbl_fea_mode
4591        short           tbl_fea_mode    -       tbl_fea_mode
4592        short           tbl_fea_mode    -       tbl_fea_mode
4593        short           tbl_fea_mode    -       tbl_fea_mode
4594        short           tbl_fea_mode    -       tbl_fea_mode
4595        short           tbl_fea_mode    -       tbl_fea_mode
4596        short           tbl_fea_mode    -       tbl_fea_mode
4597
4598        short           tbl_fea_mode    -       tbl_fea_mode
4599        short           tbl_fea_mode    -       tbl_fea_mode
4600        short           tbl_fea_mode    -       tbl_fea_mode
4601        short           tbl_fea_mode    -       tbl_fea_mode
4602        short           tbl_fea_mode    -       tbl_fea_mode
4603        short           tbl_fea_mode    -       tbl_fea_mode
4604        short           tbl_fea_mode    -       tbl_fea_mode
4605        short           tbl_fea_mode    -       tbl_fea_mode
4606
4607        short           faddr_ind_a0    -       tbl_fea_mode
4608        short           faddr_ind_a1    -       tbl_fea_mode
4609        short           faddr_ind_a2    -       tbl_fea_mode
4610        short           faddr_ind_a3    -       tbl_fea_mode
4611        short           faddr_ind_a4    -       tbl_fea_mode
4612        short           faddr_ind_a5    -       tbl_fea_mode
4613        short           faddr_ind_a6    -       tbl_fea_mode
4614        short           faddr_ind_a7    -       tbl_fea_mode
4615
4616        short           faddr_ind_p_a0  -       tbl_fea_mode
4617        short           faddr_ind_p_a1  -       tbl_fea_mode
4618        short           faddr_ind_p_a2  -       tbl_fea_mode
4619        short           faddr_ind_p_a3  -       tbl_fea_mode
4620        short           faddr_ind_p_a4  -       tbl_fea_mode
4621        short           faddr_ind_p_a5  -       tbl_fea_mode
4622        short           faddr_ind_p_a6  -       tbl_fea_mode
4623        short           faddr_ind_p_a7  -       tbl_fea_mode
4624
4625        short           faddr_ind_m_a0  -       tbl_fea_mode
4626        short           faddr_ind_m_a1  -       tbl_fea_mode
4627        short           faddr_ind_m_a2  -       tbl_fea_mode
4628        short           faddr_ind_m_a3  -       tbl_fea_mode
4629        short           faddr_ind_m_a4  -       tbl_fea_mode
4630        short           faddr_ind_m_a5  -       tbl_fea_mode
4631        short           faddr_ind_m_a6  -       tbl_fea_mode
4632        short           faddr_ind_m_a7  -       tbl_fea_mode
4633
4634        short           faddr_ind_disp_a0       -       tbl_fea_mode
4635        short           faddr_ind_disp_a1       -       tbl_fea_mode
4636        short           faddr_ind_disp_a2       -       tbl_fea_mode
4637        short           faddr_ind_disp_a3       -       tbl_fea_mode
4638        short           faddr_ind_disp_a4       -       tbl_fea_mode
4639        short           faddr_ind_disp_a5       -       tbl_fea_mode
4640        short           faddr_ind_disp_a6       -       tbl_fea_mode
4641        short           faddr_ind_disp_a7       -       tbl_fea_mode
4642
4643        short           faddr_ind_ext   -       tbl_fea_mode
4644        short           faddr_ind_ext   -       tbl_fea_mode
4645        short           faddr_ind_ext   -       tbl_fea_mode
4646        short           faddr_ind_ext   -       tbl_fea_mode
4647        short           faddr_ind_ext   -       tbl_fea_mode
4648        short           faddr_ind_ext   -       tbl_fea_mode
4649        short           faddr_ind_ext   -       tbl_fea_mode
4650        short           faddr_ind_ext   -       tbl_fea_mode
4651
4652        short           fabs_short      -       tbl_fea_mode
4653        short           fabs_long       -       tbl_fea_mode
4654        short           fpc_ind         -       tbl_fea_mode
4655        short           fpc_ind_ext     -       tbl_fea_mode
4656        short           tbl_fea_mode    -       tbl_fea_mode
4657        short           tbl_fea_mode    -       tbl_fea_mode
4658        short           tbl_fea_mode    -       tbl_fea_mode
4659        short           tbl_fea_mode    -       tbl_fea_mode
4660
4661###################################
4662# Address register indirect: (An) #
4663###################################
4664faddr_ind_a0:
4665        mov.l           EXC_DREGS+0x8(%a6),%a0  # Get current a0
4666        rts
4667
4668faddr_ind_a1:
4669        mov.l           EXC_DREGS+0xc(%a6),%a0  # Get current a1
4670        rts
4671
4672faddr_ind_a2:
4673        mov.l           %a2,%a0                 # Get current a2
4674        rts
4675
4676faddr_ind_a3:
4677        mov.l           %a3,%a0                 # Get current a3
4678        rts
4679
4680faddr_ind_a4:
4681        mov.l           %a4,%a0                 # Get current a4
4682        rts
4683
4684faddr_ind_a5:
4685        mov.l           %a5,%a0                 # Get current a5
4686        rts
4687
4688faddr_ind_a6:
4689        mov.l           (%a6),%a0               # Get current a6
4690        rts
4691
4692faddr_ind_a7:
4693        mov.l           EXC_A7(%a6),%a0         # Get current a7
4694        rts
4695
4696#####################################################
4697# Address register indirect w/ postincrement: (An)+ #
4698#####################################################
4699faddr_ind_p_a0:
4700        mov.l           EXC_DREGS+0x8(%a6),%d0  # Get current a0
4701        mov.l           %d0,%d1
4702        add.l           %a0,%d1                 # Increment
4703        mov.l           %d1,EXC_DREGS+0x8(%a6)  # Save incr value
4704        mov.l           %d0,%a0
4705        rts
4706
4707faddr_ind_p_a1:
4708        mov.l           EXC_DREGS+0xc(%a6),%d0  # Get current a1
4709        mov.l           %d0,%d1
4710        add.l           %a0,%d1                 # Increment
4711        mov.l           %d1,EXC_DREGS+0xc(%a6)  # Save incr value
4712        mov.l           %d0,%a0
4713        rts
4714
4715faddr_ind_p_a2:
4716        mov.l           %a2,%d0                 # Get current a2
4717        mov.l           %d0,%d1
4718        add.l           %a0,%d1                 # Increment
4719        mov.l           %d1,%a2                 # Save incr value
4720        mov.l           %d0,%a0
4721        rts
4722
4723faddr_ind_p_a3:
4724        mov.l           %a3,%d0                 # Get current a3
4725        mov.l           %d0,%d1
4726        add.l           %a0,%d1                 # Increment
4727        mov.l           %d1,%a3                 # Save incr value
4728        mov.l           %d0,%a0
4729        rts
4730
4731faddr_ind_p_a4:
4732        mov.l           %a4,%d0                 # Get current a4
4733        mov.l           %d0,%d1
4734        add.l           %a0,%d1                 # Increment
4735        mov.l           %d1,%a4                 # Save incr value
4736        mov.l           %d0,%a0
4737        rts
4738
4739faddr_ind_p_a5:
4740        mov.l           %a5,%d0                 # Get current a5
4741        mov.l           %d0,%d1
4742        add.l           %a0,%d1                 # Increment
4743        mov.l           %d1,%a5                 # Save incr value
4744        mov.l           %d0,%a0
4745        rts
4746
4747faddr_ind_p_a6:
4748        mov.l           (%a6),%d0               # Get current a6
4749        mov.l           %d0,%d1
4750        add.l           %a0,%d1                 # Increment
4751        mov.l           %d1,(%a6)               # Save incr value
4752        mov.l           %d0,%a0
4753        rts
4754
4755faddr_ind_p_a7:
4756        mov.b           &mia7_flg,SPCOND_FLG(%a6) # set "special case" flag
4757
4758        mov.l           EXC_A7(%a6),%d0         # Get current a7
4759        mov.l           %d0,%d1
4760        add.l           %a0,%d1                 # Increment
4761        mov.l           %d1,EXC_A7(%a6)         # Save incr value
4762        mov.l           %d0,%a0
4763        rts
4764
4765####################################################
4766# Address register indirect w/ predecrement: -(An) #
4767####################################################
4768faddr_ind_m_a0:
4769        mov.l           EXC_DREGS+0x8(%a6),%d0  # Get current a0
4770        sub.l           %a0,%d0                 # Decrement
4771        mov.l           %d0,EXC_DREGS+0x8(%a6)  # Save decr value
4772        mov.l           %d0,%a0
4773        rts
4774
4775faddr_ind_m_a1:
4776        mov.l           EXC_DREGS+0xc(%a6),%d0  # Get current a1
4777        sub.l           %a0,%d0                 # Decrement
4778        mov.l           %d0,EXC_DREGS+0xc(%a6)  # Save decr value
4779        mov.l           %d0,%a0
4780        rts
4781
4782faddr_ind_m_a2:
4783        mov.l           %a2,%d0                 # Get current a2
4784        sub.l           %a0,%d0                 # Decrement
4785        mov.l           %d0,%a2                 # Save decr value
4786        mov.l           %d0,%a0
4787        rts
4788
4789faddr_ind_m_a3:
4790        mov.l           %a3,%d0                 # Get current a3
4791        sub.l           %a0,%d0                 # Decrement
4792        mov.l           %d0,%a3                 # Save decr value
4793        mov.l           %d0,%a0
4794        rts
4795
4796faddr_ind_m_a4:
4797        mov.l           %a4,%d0                 # Get current a4
4798        sub.l           %a0,%d0                 # Decrement
4799        mov.l           %d0,%a4                 # Save decr value
4800        mov.l           %d0,%a0
4801        rts
4802
4803faddr_ind_m_a5:
4804        mov.l           %a5,%d0                 # Get current a5
4805        sub.l           %a0,%d0                 # Decrement
4806        mov.l           %d0,%a5                 # Save decr value
4807        mov.l           %d0,%a0
4808        rts
4809
4810faddr_ind_m_a6:
4811        mov.l           (%a6),%d0               # Get current a6
4812        sub.l           %a0,%d0                 # Decrement
4813        mov.l           %d0,(%a6)               # Save decr value
4814        mov.l           %d0,%a0
4815        rts
4816
4817faddr_ind_m_a7:
4818        mov.b           &mda7_flg,SPCOND_FLG(%a6) # set "special case" flag
4819
4820        mov.l           EXC_A7(%a6),%d0         # Get current a7
4821        sub.l           %a0,%d0                 # Decrement
4822        mov.l           %d0,EXC_A7(%a6)         # Save decr value
4823        mov.l           %d0,%a0
4824        rts
4825
4826########################################################
4827# Address register indirect w/ displacement: (d16, An) #
4828########################################################
4829faddr_ind_disp_a0:
4830        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4831        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4832        bsr.l           _imem_read_word
4833
4834        tst.l           %d1                     # did ifetch fail?
4835        bne.l           iea_iacc                # yes
4836
4837        mov.w           %d0,%a0                 # sign extend displacement
4838
4839        add.l           EXC_DREGS+0x8(%a6),%a0  # a0 + d16
4840        rts
4841
4842faddr_ind_disp_a1:
4843        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4844        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4845        bsr.l           _imem_read_word
4846
4847        tst.l           %d1                     # did ifetch fail?
4848        bne.l           iea_iacc                # yes
4849
4850        mov.w           %d0,%a0                 # sign extend displacement
4851
4852        add.l           EXC_DREGS+0xc(%a6),%a0  # a1 + d16
4853        rts
4854
4855faddr_ind_disp_a2:
4856        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4857        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4858        bsr.l           _imem_read_word
4859
4860        tst.l           %d1                     # did ifetch fail?
4861        bne.l           iea_iacc                # yes
4862
4863        mov.w           %d0,%a0                 # sign extend displacement
4864
4865        add.l           %a2,%a0                 # a2 + d16
4866        rts
4867
4868faddr_ind_disp_a3:
4869        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4870        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4871        bsr.l           _imem_read_word
4872
4873        tst.l           %d1                     # did ifetch fail?
4874        bne.l           iea_iacc                # yes
4875
4876        mov.w           %d0,%a0                 # sign extend displacement
4877
4878        add.l           %a3,%a0                 # a3 + d16
4879        rts
4880
4881faddr_ind_disp_a4:
4882        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4883        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4884        bsr.l           _imem_read_word
4885
4886        tst.l           %d1                     # did ifetch fail?
4887        bne.l           iea_iacc                # yes
4888
4889        mov.w           %d0,%a0                 # sign extend displacement
4890
4891        add.l           %a4,%a0                 # a4 + d16
4892        rts
4893
4894faddr_ind_disp_a5:
4895        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4896        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4897        bsr.l           _imem_read_word
4898
4899        tst.l           %d1                     # did ifetch fail?
4900        bne.l           iea_iacc                # yes
4901
4902        mov.w           %d0,%a0                 # sign extend displacement
4903
4904        add.l           %a5,%a0                 # a5 + d16
4905        rts
4906
4907faddr_ind_disp_a6:
4908        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4909        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4910        bsr.l           _imem_read_word
4911
4912        tst.l           %d1                     # did ifetch fail?
4913        bne.l           iea_iacc                # yes
4914
4915        mov.w           %d0,%a0                 # sign extend displacement
4916
4917        add.l           (%a6),%a0               # a6 + d16
4918        rts
4919
4920faddr_ind_disp_a7:
4921        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4922        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4923        bsr.l           _imem_read_word
4924
4925        tst.l           %d1                     # did ifetch fail?
4926        bne.l           iea_iacc                # yes
4927
4928        mov.w           %d0,%a0                 # sign extend displacement
4929
4930        add.l           EXC_A7(%a6),%a0         # a7 + d16
4931        rts
4932
4933########################################################################
4934# Address register indirect w/ index(8-bit displacement): (d8, An, Xn) #
4935#    "       "         "    w/   "  (base displacement): (bd, An, Xn)  #
4936# Memory indirect postindexed: ([bd, An], Xn, od)                      #
4937# Memory indirect preindexed: ([bd, An, Xn], od)                       #
4938########################################################################
4939faddr_ind_ext:
4940        addq.l          &0x8,%d1
4941        bsr.l           fetch_dreg              # fetch base areg
4942        mov.l           %d0,-(%sp)
4943
4944        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4945        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4946        bsr.l           _imem_read_word         # fetch extword in d0
4947
4948        tst.l           %d1                     # did ifetch fail?
4949        bne.l           iea_iacc                # yes
4950
4951        mov.l           (%sp)+,%a0
4952
4953        btst            &0x8,%d0
4954        bne.w           fcalc_mem_ind
4955
4956        mov.l           %d0,L_SCR1(%a6)         # hold opword
4957
4958        mov.l           %d0,%d1
4959        rol.w           &0x4,%d1
4960        andi.w          &0xf,%d1                # extract index regno
4961
4962# count on fetch_dreg() not to alter a0...
4963        bsr.l           fetch_dreg              # fetch index
4964
4965        mov.l           %d2,-(%sp)              # save d2
4966        mov.l           L_SCR1(%a6),%d2         # fetch opword
4967
4968        btst            &0xb,%d2                # is it word or long?
4969        bne.b           faii8_long
4970        ext.l           %d0                     # sign extend word index
4971faii8_long:
4972        mov.l           %d2,%d1
4973        rol.w           &0x7,%d1
4974        andi.l          &0x3,%d1                # extract scale value
4975
4976        lsl.l           %d1,%d0                 # shift index by scale
4977
4978        extb.l          %d2                     # sign extend displacement
4979        add.l           %d2,%d0                 # index + disp
4980        add.l           %d0,%a0                 # An + (index + disp)
4981
4982        mov.l           (%sp)+,%d2              # restore old d2
4983        rts
4984
4985###########################
4986# Absolute short: (XXX).W #
4987###########################
4988fabs_short:
4989        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4990        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4991        bsr.l           _imem_read_word         # fetch short address
4992
4993        tst.l           %d1                     # did ifetch fail?
4994        bne.l           iea_iacc                # yes
4995
4996        mov.w           %d0,%a0                 # return <ea> in a0
4997        rts
4998
4999##########################
5000# Absolute long: (XXX).L #
5001##########################
5002fabs_long:
5003        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
5004        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
5005        bsr.l           _imem_read_long         # fetch long address
5006
5007        tst.l           %d1                     # did ifetch fail?
5008        bne.l           iea_iacc                # yes
5009
5010        mov.l           %d0,%a0                 # return <ea> in a0
5011        rts
5012
5013#######################################################
5014# Program counter indirect w/ displacement: (d16, PC) #
5015#######################################################
5016fpc_ind:
5017        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
5018        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
5019        bsr.l           _imem_read_word         # fetch word displacement
5020
5021        tst.l           %d1                     # did ifetch fail?
5022        bne.l           iea_iacc                # yes
5023
5024        mov.w           %d0,%a0                 # sign extend displacement
5025
5026        add.l           EXC_EXTWPTR(%a6),%a0    # pc + d16
5027
5028# _imem_read_word() increased the extwptr by 2. need to adjust here.
5029        subq.l          &0x2,%a0                # adjust <ea>
5030        rts
5031
5032##########################################################
5033# PC indirect w/ index(8-bit displacement): (d8, PC, An) #
5034# "     "     w/   "  (base displacement): (bd, PC, An)  #
5035# PC memory indirect postindexed: ([bd, PC], Xn, od)     #
5036# PC memory indirect preindexed: ([bd, PC, Xn], od)      #
5037##########################################################
5038fpc_ind_ext:
5039        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
5040        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
5041        bsr.l           _imem_read_word         # fetch ext word
5042
5043        tst.l           %d1                     # did ifetch fail?
5044        bne.l           iea_iacc                # yes
5045
5046        mov.l           EXC_EXTWPTR(%a6),%a0    # put base in a0
5047        subq.l          &0x2,%a0                # adjust base
5048
5049        btst            &0x8,%d0                # is disp only 8 bits?
5050        bne.w           fcalc_mem_ind           # calc memory indirect
5051
5052        mov.l           %d0,L_SCR1(%a6)         # store opword
5053
5054        mov.l           %d0,%d1                 # make extword copy
5055        rol.w           &0x4,%d1                # rotate reg num into place
5056        andi.w          &0xf,%d1                # extract register number
5057
5058# count on fetch_dreg() not to alter a0...
5059        bsr.l           fetch_dreg              # fetch index
5060
5061        mov.l           %d2,-(%sp)              # save d2
5062        mov.l           L_SCR1(%a6),%d2         # fetch opword
5063
5064        btst            &0xb,%d2                # is index word or long?
5065        bne.b           fpii8_long              # long
5066        ext.l           %d0                     # sign extend word index
5067fpii8_long:
5068        mov.l           %d2,%d1
5069        rol.w           &0x7,%d1                # rotate scale value into place
5070        andi.l          &0x3,%d1                # extract scale value
5071
5072        lsl.l           %d1,%d0                 # shift index by scale
5073
5074        extb.l          %d2                     # sign extend displacement
5075        add.l           %d2,%d0                 # disp + index
5076        add.l           %d0,%a0                 # An + (index + disp)
5077
5078        mov.l           (%sp)+,%d2              # restore temp register
5079        rts
5080
5081# d2 = index
5082# d3 = base
5083# d4 = od
5084# d5 = extword
5085fcalc_mem_ind:
5086        btst            &0x6,%d0                # is the index suppressed?
5087        beq.b           fcalc_index
5088
5089        movm.l          &0x3c00,-(%sp)          # save d2-d5
5090
5091        mov.l           %d0,%d5                 # put extword in d5
5092        mov.l           %a0,%d3                 # put base in d3
5093
5094        clr.l           %d2                     # yes, so index = 0
5095        bra.b           fbase_supp_ck
5096
5097# index:
5098fcalc_index:
5099        mov.l           %d0,L_SCR1(%a6)         # save d0 (opword)
5100        bfextu          %d0{&16:&4},%d1         # fetch dreg index
5101        bsr.l           fetch_dreg
5102
5103        movm.l          &0x3c00,-(%sp)          # save d2-d5
5104        mov.l           %d0,%d2                 # put index in d2
5105        mov.l           L_SCR1(%a6),%d5
5106        mov.l           %a0,%d3
5107
5108        btst            &0xb,%d5                # is index word or long?
5109        bne.b           fno_ext
5110        ext.l           %d2
5111
5112fno_ext:
5113        bfextu          %d5{&21:&2},%d0
5114        lsl.l           %d0,%d2
5115
5116# base address (passed as parameter in d3):
5117# we clear the value here if it should actually be suppressed.
5118fbase_supp_ck:
5119        btst            &0x7,%d5                # is the bd suppressed?
5120        beq.b           fno_base_sup
5121        clr.l           %d3
5122
5123# base displacement:
5124fno_base_sup:
5125        bfextu          %d5{&26:&2},%d0         # get bd size
5126#       beq.l           fmovm_error             # if (size == 0) it's reserved
5127
5128        cmpi.b          %d0,&0x2
5129        blt.b           fno_bd
5130        beq.b           fget_word_bd
5131
5132        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
5133        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
5134        bsr.l           _imem_read_long
5135
5136        tst.l           %d1                     # did ifetch fail?
5137        bne.l           fcea_iacc               # yes
5138
5139        bra.b           fchk_ind
5140
5141fget_word_bd:
5142        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
5143        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
5144        bsr.l           _imem_read_word
5145
5146        tst.l           %d1                     # did ifetch fail?
5147        bne.l           fcea_iacc               # yes
5148
5149        ext.l           %d0                     # sign extend bd
5150
5151fchk_ind:
5152        add.l           %d0,%d3                 # base += bd
5153
5154# outer displacement:
5155fno_bd:
5156        bfextu          %d5{&30:&2},%d0         # is od suppressed?
5157        beq.w           faii_bd
5158
5159        cmpi.b          %d0,&0x2
5160        blt.b           fnull_od
5161        beq.b           fword_od
5162
5163        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
5164        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
5165        bsr.l           _imem_read_long
5166
5167        tst.l           %d1                     # did ifetch fail?
5168        bne.l           fcea_iacc               # yes
5169
5170        bra.b           fadd_them
5171
5172fword_od:
5173        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
5174        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
5175        bsr.l           _imem_read_word
5176
5177        tst.l           %d1                     # did ifetch fail?
5178        bne.l           fcea_iacc               # yes
5179
5180        ext.l           %d0                     # sign extend od
5181        bra.b           fadd_them
5182
5183fnull_od:
5184        clr.l           %d0
5185
5186fadd_them:
5187        mov.l           %d0,%d4
5188
5189        btst            &0x2,%d5                # pre or post indexing?
5190        beq.b           fpre_indexed
5191
5192        mov.l           %d3,%a0
5193        bsr.l           _dmem_read_long
5194
5195        tst.l           %d1                     # did dfetch fail?
5196        bne.w           fcea_err                # yes
5197
5198        add.l           %d2,%d0                 # <ea> += index
5199        add.l           %d4,%d0                 # <ea> += od
5200        bra.b           fdone_ea
5201
5202fpre_indexed:
5203        add.l           %d2,%d3                 # preindexing
5204        mov.l           %d3,%a0
5205        bsr.l           _dmem_read_long
5206
5207        tst.l           %d1                     # did dfetch fail?
5208        bne.w           fcea_err                # yes
5209
5210        add.l           %d4,%d0                 # ea += od
5211        bra.b           fdone_ea
5212
5213faii_bd:
5214        add.l           %d2,%d3                 # ea = (base + bd) + index
5215        mov.l           %d3,%d0
5216fdone_ea:
5217        mov.l           %d0,%a0
5218
5219        movm.l          (%sp)+,&0x003c          # restore d2-d5
5220        rts
5221
5222#########################################################
5223fcea_err:
5224        mov.l           %d3,%a0
5225
5226        movm.l          (%sp)+,&0x003c          # restore d2-d5
5227        mov.w           &0x0101,%d0
5228        bra.l           iea_dacc
5229
5230fcea_iacc:
5231        movm.l          (%sp)+,&0x003c          # restore d2-d5
5232        bra.l           iea_iacc
5233
5234fmovm_out_err:
5235        bsr.l           restore
5236        mov.w           &0x00e1,%d0
5237        bra.b           fmovm_err
5238
5239fmovm_in_err:
5240        bsr.l           restore
5241        mov.w           &0x0161,%d0
5242
5243fmovm_err:
5244        mov.l           L_SCR1(%a6),%a0
5245        bra.l           iea_dacc
5246
5247#########################################################################
5248# XDEF **************************************************************** #
5249#       fmovm_ctrl(): emulate fmovm.l of control registers instr        #
5250#                                                                       #
5251# XREF **************************************************************** #
5252#       _imem_read_long() - read longword from memory                   #
5253#       iea_iacc() - _imem_read_long() failed; error recovery           #
5254#                                                                       #
5255# INPUT *************************************************************** #
5256#       None                                                            #
5257#                                                                       #
5258# OUTPUT ************************************************************** #
5259#       If _imem_read_long() doesn't fail:                              #
5260#               USER_FPCR(a6)  = new FPCR value                         #
5261#               USER_FPSR(a6)  = new FPSR value                         #
5262#               USER_FPIAR(a6) = new FPIAR value                        #
5263#                                                                       #
5264# ALGORITHM *********************************************************** #
5265#       Decode the instruction type by looking at the extension word    #
5266# in order to see how many control registers to fetch from memory.      #
5267# Fetch them using _imem_read_long(). If this fetch fails, exit through #
5268# the special access error exit handler iea_iacc().                     #
5269#                                                                       #
5270# Instruction word decoding:                                            #
5271#                                                                       #
5272#       fmovem.l #<data>, {FPIAR&|FPCR&|FPSR}                           #
5273#                                                                       #
5274#               WORD1                   WORD2                           #
5275#       1111 0010 00 111100     100$ $$00 0000 0000                     #
5276#                                                                       #
5277#       $$$ (100): FPCR                                                 #
5278#           (010): FPSR                                                 #
5279#           (001): FPIAR                                                #
5280#           (000): FPIAR                                                #
5281#                                                                       #
5282#########################################################################
5283
5284        global          fmovm_ctrl
5285fmovm_ctrl:
5286        mov.b           EXC_EXTWORD(%a6),%d0    # fetch reg select bits
5287        cmpi.b          %d0,&0x9c               # fpcr & fpsr & fpiar ?
5288        beq.w           fctrl_in_7              # yes
5289        cmpi.b          %d0,&0x98               # fpcr & fpsr ?
5290        beq.w           fctrl_in_6              # yes
5291        cmpi.b          %d0,&0x94               # fpcr & fpiar ?
5292        beq.b           fctrl_in_5              # yes
5293
5294# fmovem.l #<data>, fpsr/fpiar
5295fctrl_in_3:
5296        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
5297        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
5298        bsr.l           _imem_read_long         # fetch FPSR from mem
5299
5300        tst.l           %d1                     # did ifetch fail?
5301        bne.l           iea_iacc                # yes
5302
5303        mov.l           %d0,USER_FPSR(%a6)      # store new FPSR to stack
5304        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
5305        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
5306        bsr.l           _imem_read_long         # fetch FPIAR from mem
5307
5308        tst.l           %d1                     # did ifetch fail?
5309        bne.l           iea_iacc                # yes
5310
5311        mov.l           %d0,USER_FPIAR(%a6)     # store new FPIAR to stack
5312        rts
5313
5314# fmovem.l #<data>, fpcr/fpiar
5315fctrl_in_5:
5316        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
5317        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
5318        bsr.l           _imem_read_long         # fetch FPCR from mem
5319
5320        tst.l           %d1                     # did ifetch fail?
5321        bne.l           iea_iacc                # yes
5322
5323        mov.l           %d0,USER_FPCR(%a6)      # store new FPCR to stack
5324        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
5325        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
5326        bsr.l           _imem_read_long         # fetch FPIAR from mem
5327
5328        tst.l           %d1                     # did ifetch fail?
5329        bne.l           iea_iacc                # yes
5330
5331        mov.l           %d0,USER_FPIAR(%a6)     # store new FPIAR to stack
5332        rts
5333
5334# fmovem.l #<data>, fpcr/fpsr
5335fctrl_in_6:
5336        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
5337        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
5338        bsr.l           _imem_read_long         # fetch FPCR from mem
5339
5340        tst.l           %d1                     # did ifetch fail?
5341        bne.l           iea_iacc                # yes
5342
5343        mov.l           %d0,USER_FPCR(%a6)      # store new FPCR to mem
5344        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
5345        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
5346        bsr.l           _imem_read_long         # fetch FPSR from mem
5347
5348        tst.l           %d1                     # did ifetch fail?
5349        bne.l           iea_iacc                # yes
5350
5351        mov.l           %d0,USER_FPSR(%a6)      # store new FPSR to mem
5352        rts
5353
5354# fmovem.l #<data>, fpcr/fpsr/fpiar
5355fctrl_in_7:
5356        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
5357        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
5358        bsr.l           _imem_read_long         # fetch FPCR from mem
5359
5360        tst.l           %d1                     # did ifetch fail?
5361        bne.l           iea_iacc                # yes
5362
5363        mov.l           %d0,USER_FPCR(%a6)      # store new FPCR to mem
5364        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
5365        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
5366        bsr.l           _imem_read_long         # fetch FPSR from mem
5367
5368        tst.l           %d1                     # did ifetch fail?
5369        bne.l           iea_iacc                # yes
5370
5371        mov.l           %d0,USER_FPSR(%a6)      # store new FPSR to mem
5372        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
5373        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
5374        bsr.l           _imem_read_long         # fetch FPIAR from mem
5375
5376        tst.l           %d1                     # did ifetch fail?
5377        bne.l           iea_iacc                # yes
5378
5379        mov.l           %d0,USER_FPIAR(%a6)     # store new FPIAR to mem
5380        rts
5381
5382##########################################################################
5383
5384#########################################################################
5385# XDEF **************************************************************** #
5386#       addsub_scaler2(): scale inputs to fadd/fsub such that no        #
5387#                         OVFL/UNFL exceptions will result              #
5388#                                                                       #
5389# XREF **************************************************************** #
5390#       norm() - normalize mantissa after adjusting exponent            #
5391#                                                                       #
5392# INPUT *************************************************************** #
5393#       FP_SRC(a6) = fp op1(src)                                        #
5394#       FP_DST(a6) = fp op2(dst)                                        #
5395#                                                                       #
5396# OUTPUT ************************************************************** #
5397#       FP_SRC(a6) = fp op1 scaled(src)                                 #
5398#       FP_DST(a6) = fp op2 scaled(dst)                                 #
5399#       d0         = scale amount                                       #
5400#                                                                       #
5401# ALGORITHM *********************************************************** #
5402#       If the DST exponent is > the SRC exponent, set the DST exponent #
5403# equal to 0x3fff and scale the SRC exponent by the value that the      #
5404# DST exponent was scaled by. If the SRC exponent is greater or equal,  #
5405# do the opposite. Return this scale factor in d0.                      #
5406#       If the two exponents differ by > the number of mantissa bits    #
5407# plus two, then set the smallest exponent to a very small value as a   #
5408# quick shortcut.                                                       #
5409#                                                                       #
5410#########################################################################
5411
5412        global          addsub_scaler2
5413addsub_scaler2:
5414        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
5415        mov.l           DST_HI(%a1),FP_SCR1_HI(%a6)
5416        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
5417        mov.l           DST_LO(%a1),FP_SCR1_LO(%a6)
5418        mov.w           SRC_EX(%a0),%d0
5419        mov.w           DST_EX(%a1),%d1
5420        mov.w           %d0,FP_SCR0_EX(%a6)
5421        mov.w           %d1,FP_SCR1_EX(%a6)
5422
5423        andi.w          &0x7fff,%d0
5424        andi.w          &0x7fff,%d1
5425        mov.w           %d0,L_SCR1(%a6)         # store src exponent
5426        mov.w           %d1,2+L_SCR1(%a6)       # store dst exponent
5427
5428        cmp.w           %d0, %d1                # is src exp >= dst exp?
5429        bge.l           src_exp_ge2
5430
5431# dst exp is >  src exp; scale dst to exp = 0x3fff
5432dst_exp_gt2:
5433        bsr.l           scale_to_zero_dst
5434        mov.l           %d0,-(%sp)              # save scale factor
5435
5436        cmpi.b          STAG(%a6),&DENORM       # is dst denormalized?
5437        bne.b           cmpexp12
5438
5439        lea             FP_SCR0(%a6),%a0
5440        bsr.l           norm                    # normalize the denorm; result is new exp
5441        neg.w           %d0                     # new exp = -(shft val)
5442        mov.w           %d0,L_SCR1(%a6)         # inset new exp
5443
5444cmpexp12:
5445        mov.w           2+L_SCR1(%a6),%d0
5446        subi.w          &mantissalen+2,%d0      # subtract mantissalen+2 from larger exp
5447
5448        cmp.w           %d0,L_SCR1(%a6)         # is difference >= len(mantissa)+2?
5449        bge.b           quick_scale12
5450
5451        mov.w           L_SCR1(%a6),%d0
5452        add.w           0x2(%sp),%d0            # scale src exponent by scale factor
5453        mov.w           FP_SCR0_EX(%a6),%d1
5454        and.w           &0x8000,%d1
5455        or.w            %d1,%d0                 # concat {sgn,new exp}
5456        mov.w           %d0,FP_SCR0_EX(%a6)     # insert new dst exponent
5457
5458        mov.l           (%sp)+,%d0              # return SCALE factor
5459        rts
5460
5461quick_scale12:
5462        andi.w          &0x8000,FP_SCR0_EX(%a6) # zero src exponent
5463        bset            &0x0,1+FP_SCR0_EX(%a6)  # set exp = 1
5464
5465        mov.l           (%sp)+,%d0              # return SCALE factor
5466        rts
5467
5468# src exp is >= dst exp; scale src to exp = 0x3fff
5469src_exp_ge2:
5470        bsr.l           scale_to_zero_src
5471        mov.l           %d0,-(%sp)              # save scale factor
5472
5473        cmpi.b          DTAG(%a6),&DENORM       # is dst denormalized?
5474        bne.b           cmpexp22
5475        lea             FP_SCR1(%a6),%a0
5476        bsr.l           norm                    # normalize the denorm; result is new exp
5477        neg.w           %d0                     # new exp = -(shft val)
5478        mov.w           %d0,2+L_SCR1(%a6)       # inset new exp
5479
5480cmpexp22:
5481        mov.w           L_SCR1(%a6),%d0
5482        subi.w          &mantissalen+2,%d0      # subtract mantissalen+2 from larger exp
5483
5484        cmp.w           %d0,2+L_SCR1(%a6)       # is difference >= len(mantissa)+2?
5485        bge.b           quick_scale22
5486
5487        mov.w           2+L_SCR1(%a6),%d0
5488        add.w           0x2(%sp),%d0            # scale dst exponent by scale factor
5489        mov.w           FP_SCR1_EX(%a6),%d1
5490        andi.w          &0x8000,%d1
5491        or.w            %d1,%d0                 # concat {sgn,new exp}
5492        mov.w           %d0,FP_SCR1_EX(%a6)     # insert new dst exponent
5493
5494        mov.l           (%sp)+,%d0              # return SCALE factor
5495        rts
5496
5497quick_scale22:
5498        andi.w          &0x8000,FP_SCR1_EX(%a6) # zero dst exponent
5499        bset            &0x0,1+FP_SCR1_EX(%a6)  # set exp = 1
5500
5501        mov.l           (%sp)+,%d0              # return SCALE factor
5502        rts
5503
5504##########################################################################
5505
5506#########################################################################
5507# XDEF **************************************************************** #
5508#       scale_to_zero_src(): scale the exponent of extended precision   #
5509#                            value at FP_SCR0(a6).                      #
5510#                                                                       #
5511# XREF **************************************************************** #
5512#       norm() - normalize the mantissa if the operand was a DENORM     #
5513#                                                                       #
5514# INPUT *************************************************************** #
5515#       FP_SCR0(a6) = extended precision operand to be scaled           #
5516#                                                                       #
5517# OUTPUT ************************************************************** #
5518#       FP_SCR0(a6) = scaled extended precision operand                 #
5519#       d0          = scale value                                       #
5520#                                                                       #
5521# ALGORITHM *********************************************************** #
5522#       Set the exponent of the input operand to 0x3fff. Save the value #
5523# of the difference between the original and new exponent. Then,        #
5524# normalize the operand if it was a DENORM. Add this normalization      #
5525# value to the previous value. Return the result.                       #
5526#                                                                       #
5527#########################################################################
5528
5529        global          scale_to_zero_src
5530scale_to_zero_src:
5531        mov.w           FP_SCR0_EX(%a6),%d1     # extract operand's {sgn,exp}
5532        mov.w           %d1,%d0                 # make a copy
5533
5534        andi.l          &0x7fff,%d1             # extract operand's exponent
5535
5536        andi.w          &0x8000,%d0             # extract operand's sgn
5537        or.w            &0x3fff,%d0             # insert new operand's exponent(=0)
5538
5539        mov.w           %d0,FP_SCR0_EX(%a6)     # insert biased exponent
5540
5541        cmpi.b          STAG(%a6),&DENORM       # is operand normalized?
5542        beq.b           stzs_denorm             # normalize the DENORM
5543
5544stzs_norm:
5545        mov.l           &0x3fff,%d0
5546        sub.l           %d1,%d0                 # scale = BIAS + (-exp)
5547
5548        rts
5549
5550stzs_denorm:
5551        lea             FP_SCR0(%a6),%a0        # pass ptr to src op
5552        bsr.l           norm                    # normalize denorm
5553        neg.l           %d0                     # new exponent = -(shft val)
5554        mov.l           %d0,%d1                 # prepare for op_norm call
5555        bra.b           stzs_norm               # finish scaling
5556
5557###
5558
5559#########################################################################
5560# XDEF **************************************************************** #
5561#       scale_sqrt(): scale the input operand exponent so a subsequent  #
5562#                     fsqrt operation won't take an exception.          #
5563#                                                                       #
5564# XREF **************************************************************** #
5565#       norm() - normalize the mantissa if the operand was a DENORM     #
5566#                                                                       #
5567# INPUT *************************************************************** #
5568#       FP_SCR0(a6) = extended precision operand to be scaled           #
5569#                                                                       #
5570# OUTPUT ************************************************************** #
5571#       FP_SCR0(a6) = scaled extended precision operand                 #
5572#       d0          = scale value                                       #
5573#                                                                       #
5574# ALGORITHM *********************************************************** #
5575#       If the input operand is a DENORM, normalize it.                 #
5576#       If the exponent of the input operand is even, set the exponent  #
5577# to 0x3ffe and return a scale factor of "(exp-0x3ffe)/2". If the       #
5578# exponent of the input operand is off, set the exponent to ox3fff and  #
5579# return a scale factor of "(exp-0x3fff)/2".                            #
5580#                                                                       #
5581#########################################################################
5582
5583        global          scale_sqrt
5584scale_sqrt:
5585        cmpi.b          STAG(%a6),&DENORM       # is operand normalized?
5586        beq.b           ss_denorm               # normalize the DENORM
5587
5588        mov.w           FP_SCR0_EX(%a6),%d1     # extract operand's {sgn,exp}
5589        andi.l          &0x7fff,%d1             # extract operand's exponent
5590
5591        andi.w          &0x8000,FP_SCR0_EX(%a6) # extract operand's sgn
5592
5593        btst            &0x0,%d1                # is exp even or odd?
5594        beq.b           ss_norm_even
5595
5596        ori.w           &0x3fff,FP_SCR0_EX(%a6) # insert new operand's exponent(=0)
5597
5598        mov.l           &0x3fff,%d0
5599        sub.l           %d1,%d0                 # scale = BIAS + (-exp)
5600        asr.l           &0x1,%d0                # divide scale factor by 2
5601        rts
5602
5603ss_norm_even:
5604        ori.w           &0x3ffe,FP_SCR0_EX(%a6) # insert new operand's exponent(=0)
5605
5606        mov.l           &0x3ffe,%d0
5607        sub.l           %d1,%d0                 # scale = BIAS + (-exp)
5608        asr.l           &0x1,%d0                # divide scale factor by 2
5609        rts
5610
5611ss_denorm:
5612        lea             FP_SCR0(%a6),%a0        # pass ptr to src op
5613        bsr.l           norm                    # normalize denorm
5614
5615        btst            &0x0,%d0                # is exp even or odd?
5616        beq.b           ss_denorm_even
5617
5618        ori.w           &0x3fff,FP_SCR0_EX(%a6) # insert new operand's exponent(=0)
5619
5620        add.l           &0x3fff,%d0
5621        asr.l           &0x1,%d0                # divide scale factor by 2
5622        rts
5623
5624ss_denorm_even:
5625        ori.w           &0x3ffe,FP_SCR0_EX(%a6) # insert new operand's exponent(=0)
5626
5627        add.l           &0x3ffe,%d0
5628        asr.l           &0x1,%d0                # divide scale factor by 2
5629        rts
5630
5631###
5632
5633#########################################################################
5634# XDEF **************************************************************** #
5635#       scale_to_zero_dst(): scale the exponent of extended precision   #
5636#                            value at FP_SCR1(a6).                      #
5637#                                                                       #
5638# XREF **************************************************************** #
5639#       norm() - normalize the mantissa if the operand was a DENORM     #
5640#                                                                       #
5641# INPUT *************************************************************** #
5642#       FP_SCR1(a6) = extended precision operand to be scaled           #
5643#                                                                       #
5644# OUTPUT ************************************************************** #
5645#       FP_SCR1(a6) = scaled extended precision operand                 #
5646#       d0          = scale value                                       #
5647#                                                                       #
5648# ALGORITHM *********************************************************** #
5649#       Set the exponent of the input operand to 0x3fff. Save the value #
5650# of the difference between the original and new exponent. Then,        #
5651# normalize the operand if it was a DENORM. Add this normalization      #
5652# value to the previous value. Return the result.                       #
5653#                                                                       #
5654#########################################################################
5655
5656        global          scale_to_zero_dst
5657scale_to_zero_dst:
5658        mov.w           FP_SCR1_EX(%a6),%d1     # extract operand's {sgn,exp}
5659        mov.w           %d1,%d0                 # make a copy
5660
5661        andi.l          &0x7fff,%d1             # extract operand's exponent
5662
5663        andi.w          &0x8000,%d0             # extract operand's sgn
5664        or.w            &0x3fff,%d0             # insert new operand's exponent(=0)
5665
5666        mov.w           %d0,FP_SCR1_EX(%a6)     # insert biased exponent
5667
5668        cmpi.b          DTAG(%a6),&DENORM       # is operand normalized?
5669        beq.b           stzd_denorm             # normalize the DENORM
5670
5671stzd_norm:
5672        mov.l           &0x3fff,%d0
5673        sub.l           %d1,%d0                 # scale = BIAS + (-exp)
5674        rts
5675
5676stzd_denorm:
5677        lea             FP_SCR1(%a6),%a0        # pass ptr to dst op
5678        bsr.l           norm                    # normalize denorm
5679        neg.l           %d0                     # new exponent = -(shft val)
5680        mov.l           %d0,%d1                 # prepare for op_norm call
5681        bra.b           stzd_norm               # finish scaling
5682
5683##########################################################################
5684
5685#########################################################################
5686# XDEF **************************************************************** #
5687#       res_qnan(): return default result w/ QNAN operand for dyadic    #
5688#       res_snan(): return default result w/ SNAN operand for dyadic    #
5689#       res_qnan_1op(): return dflt result w/ QNAN operand for monadic  #
5690#       res_snan_1op(): return dflt result w/ SNAN operand for monadic  #
5691#                                                                       #
5692# XREF **************************************************************** #
5693#       None                                                            #
5694#                                                                       #
5695# INPUT *************************************************************** #
5696#       FP_SRC(a6) = pointer to extended precision src operand          #
5697#       FP_DST(a6) = pointer to extended precision dst operand          #
5698#                                                                       #
5699# OUTPUT ************************************************************** #
5700#       fp0 = default result                                            #
5701#                                                                       #
5702# ALGORITHM *********************************************************** #
5703#       If either operand (but not both operands) of an operation is a  #
5704# nonsignalling NAN, then that NAN is returned as the result. If both   #
5705# operands are nonsignalling NANs, then the destination operand         #
5706# nonsignalling NAN is returned as the result.                          #
5707#       If either operand to an operation is a signalling NAN (SNAN),   #
5708# then, the SNAN bit is set in the FPSR EXC byte. If the SNAN trap      #
5709# enable bit is set in the FPCR, then the trap is taken and the         #
5710# destination is not modified. If the SNAN trap enable bit is not set,  #
5711# then the SNAN is converted to a nonsignalling NAN (by setting the     #
5712# SNAN bit in the operand to one), and the operation continues as       #
5713# described in the preceding paragraph, for nonsignalling NANs.         #
5714#       Make sure the appropriate FPSR bits are set before exiting.     #
5715#                                                                       #
5716#########################################################################
5717
5718        global          res_qnan
5719        global          res_snan
5720res_qnan:
5721res_snan:
5722        cmp.b           DTAG(%a6), &SNAN        # is the dst an SNAN?
5723        beq.b           dst_snan2
5724        cmp.b           DTAG(%a6), &QNAN        # is the dst a  QNAN?
5725        beq.b           dst_qnan2
5726src_nan:
5727        cmp.b           STAG(%a6), &QNAN
5728        beq.b           src_qnan2
5729        global          res_snan_1op
5730res_snan_1op:
5731src_snan2:
5732        bset            &0x6, FP_SRC_HI(%a6)    # set SNAN bit
5733        or.l            &nan_mask+aiop_mask+snan_mask, USER_FPSR(%a6)
5734        lea             FP_SRC(%a6), %a0
5735        bra.b           nan_comp
5736        global          res_qnan_1op
5737res_qnan_1op:
5738src_qnan2:
5739        or.l            &nan_mask, USER_FPSR(%a6)
5740        lea             FP_SRC(%a6), %a0
5741        bra.b           nan_comp
5742dst_snan2:
5743        or.l            &nan_mask+aiop_mask+snan_mask, USER_FPSR(%a6)
5744        bset            &0x6, FP_DST_HI(%a6)    # set SNAN bit
5745        lea             FP_DST(%a6), %a0
5746        bra.b           nan_comp
5747dst_qnan2:
5748        lea             FP_DST(%a6), %a0
5749        cmp.b           STAG(%a6), &SNAN
5750        bne             nan_done
5751        or.l            &aiop_mask+snan_mask, USER_FPSR(%a6)
5752nan_done:
5753        or.l            &nan_mask, USER_FPSR(%a6)
5754nan_comp:
5755        btst            &0x7, FTEMP_EX(%a0)     # is NAN neg?
5756        beq.b           nan_not_neg
5757        or.l            &neg_mask, USER_FPSR(%a6)
5758nan_not_neg:
5759        fmovm.x         (%a0), &0x80
5760        rts
5761
5762#########################################################################
5763# XDEF **************************************************************** #
5764#       res_operr(): return default result during operand error         #
5765#                                                                       #
5766# XREF **************************************************************** #
5767#       None                                                            #
5768#                                                                       #
5769# INPUT *************************************************************** #
5770#       None                                                            #
5771#                                                                       #
5772# OUTPUT ************************************************************** #
5773#       fp0 = default operand error result                              #
5774#                                                                       #
5775# ALGORITHM *********************************************************** #
5776#       An nonsignalling NAN is returned as the default result when     #
5777# an operand error occurs for the following cases:                      #
5778#                                                                       #
5779#       Multiply: (Infinity x Zero)                                     #
5780#       Divide  : (Zero / Zero) || (Infinity / Infinity)                #
5781#                                                                       #
5782#########################################################################
5783
5784        global          res_operr
5785res_operr:
5786        or.l            &nan_mask+operr_mask+aiop_mask, USER_FPSR(%a6)
5787        fmovm.x         nan_return(%pc), &0x80
5788        rts
5789
5790nan_return:
5791        long            0x7fff0000, 0xffffffff, 0xffffffff
5792
5793#########################################################################
5794# XDEF **************************************************************** #
5795#       _denorm(): denormalize an intermediate result                   #
5796#                                                                       #
5797# XREF **************************************************************** #
5798#       None                                                            #
5799#                                                                       #
5800# INPUT *************************************************************** #
5801#       a0 = points to the operand to be denormalized                   #
5802#               (in the internal extended format)                       #
5803#                                                                       #
5804#       d0 = rounding precision                                         #
5805#                                                                       #
5806# OUTPUT ************************************************************** #
5807#       a0 = pointer to the denormalized result                         #
5808#               (in the internal extended format)                       #
5809#                                                                       #
5810#       d0 = guard,round,sticky                                         #
5811#                                                                       #
5812# ALGORITHM *********************************************************** #
5813#       According to the exponent underflow threshold for the given     #
5814# precision, shift the mantissa bits to the right in order raise the    #
5815# exponent of the operand to the threshold value. While shifting the    #
5816# mantissa bits right, maintain the value of the guard, round, and      #
5817# sticky bits.                                                          #
5818# other notes:                                                          #
5819#       (1) _denorm() is called by the underflow routines               #
5820#       (2) _denorm() does NOT affect the status register               #
5821#                                                                       #
5822#########################################################################
5823
5824#
5825# table of exponent threshold values for each precision
5826#
5827tbl_thresh:
5828        short           0x0
5829        short           sgl_thresh
5830        short           dbl_thresh
5831
5832        global          _denorm
5833_denorm:
5834#
5835# Load the exponent threshold for the precision selected and check
5836# to see if (threshold - exponent) is > 65 in which case we can
5837# simply calculate the sticky bit and zero the mantissa. otherwise
5838# we have to call the denormalization routine.
5839#
5840        lsr.b           &0x2, %d0               # shift prec to lo bits
5841        mov.w           (tbl_thresh.b,%pc,%d0.w*2), %d1 # load prec threshold
5842        mov.w           %d1, %d0                # copy d1 into d0
5843        sub.w           FTEMP_EX(%a0), %d0      # diff = threshold - exp
5844        cmpi.w          %d0, &66                # is diff > 65? (mant + g,r bits)
5845        bpl.b           denorm_set_stky         # yes; just calc sticky
5846
5847        clr.l           %d0                     # clear g,r,s
5848        btst            &inex2_bit, FPSR_EXCEPT(%a6) # yes; was INEX2 set?
5849        beq.b           denorm_call             # no; don't change anything
5850        bset            &29, %d0                # yes; set sticky bit
5851
5852denorm_call:
5853        bsr.l           dnrm_lp                 # denormalize the number
5854        rts
5855
5856#
5857# all bit would have been shifted off during the denorm so simply
5858# calculate if the sticky should be set and clear the entire mantissa.
5859#
5860denorm_set_stky:
5861        mov.l           &0x20000000, %d0        # set sticky bit in return value
5862        mov.w           %d1, FTEMP_EX(%a0)      # load exp with threshold
5863        clr.l           FTEMP_HI(%a0)           # set d1 = 0 (ms mantissa)
5864        clr.l           FTEMP_LO(%a0)           # set d2 = 0 (ms mantissa)
5865        rts
5866
5867#                                                                       #
5868# dnrm_lp(): normalize exponent/mantissa to specified threshold         #
5869#                                                                       #
5870# INPUT:                                                                #
5871#       %a0        : points to the operand to be denormalized           #
5872#       %d0{31:29} : initial guard,round,sticky                         #
5873#       %d1{15:0}  : denormalization threshold                          #
5874# OUTPUT:                                                               #
5875#       %a0        : points to the denormalized operand                 #
5876#       %d0{31:29} : final guard,round,sticky                           #
5877#                                                                       #
5878
5879# *** Local Equates *** #
5880set     GRS,            L_SCR2                  # g,r,s temp storage
5881set     FTEMP_LO2,      L_SCR1                  # FTEMP_LO copy
5882
5883        global          dnrm_lp
5884dnrm_lp:
5885
5886#
5887# make a copy of FTEMP_LO and place the g,r,s bits directly after it
5888# in memory so as to make the bitfield extraction for denormalization easier.
5889#
5890        mov.l           FTEMP_LO(%a0), FTEMP_LO2(%a6) # make FTEMP_LO copy
5891        mov.l           %d0, GRS(%a6)           # place g,r,s after it
5892
5893#
5894# check to see how much less than the underflow threshold the operand
5895# exponent is.
5896#
5897        mov.l           %d1, %d0                # copy the denorm threshold
5898        sub.w           FTEMP_EX(%a0), %d1      # d1 = threshold - uns exponent
5899        ble.b           dnrm_no_lp              # d1 <= 0
5900        cmpi.w          %d1, &0x20              # is ( 0 <= d1 < 32) ?
5901        blt.b           case_1                  # yes
5902        cmpi.w          %d1, &0x40              # is (32 <= d1 < 64) ?
5903        blt.b           case_2                  # yes
5904        bra.w           case_3                  # (d1 >= 64)
5905
5906#
5907# No normalization necessary
5908#
5909dnrm_no_lp:
5910        mov.l           GRS(%a6), %d0           # restore original g,r,s
5911        rts
5912
5913#
5914# case (0<d1<32)
5915#
5916# %d0 = denorm threshold
5917# %d1 = "n" = amt to shift
5918#
5919#       ---------------------------------------------------------
5920#       |     FTEMP_HI    |     FTEMP_LO     |grs000.........000|
5921#       ---------------------------------------------------------
5922#       <-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)->
5923#       \          \                  \                  \
5924#        \          \                  \                  \
5925#         \          \                  \                  \
5926#          \          \                  \                  \
5927#           \          \                  \                  \
5928#            \          \                  \                  \
5929#             \          \                  \                  \
5930#              \          \                  \                  \
5931#       <-(n)-><-(32 - n)-><------(32)-------><------(32)------->
5932#       ---------------------------------------------------------
5933#       |0.....0| NEW_HI  |  NEW_FTEMP_LO     |grs              |
5934#       ---------------------------------------------------------
5935#
5936case_1:
5937        mov.l           %d2, -(%sp)             # create temp storage
5938
5939        mov.w           %d0, FTEMP_EX(%a0)      # exponent = denorm threshold
5940        mov.l           &32, %d0
5941        sub.w           %d1, %d0                # %d0 = 32 - %d1
5942
5943        cmpi.w          %d1, &29                # is shft amt >= 29
5944        blt.b           case1_extract           # no; no fix needed
5945        mov.b           GRS(%a6), %d2
5946        or.b            %d2, 3+FTEMP_LO2(%a6)
5947
5948case1_extract:
5949        bfextu          FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_HI
5950        bfextu          FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new FTEMP_LO
5951        bfextu          FTEMP_LO2(%a6){%d0:&32}, %d0 # %d0 = new G,R,S
5952
5953        mov.l           %d2, FTEMP_HI(%a0)      # store new FTEMP_HI
5954        mov.l           %d1, FTEMP_LO(%a0)      # store new FTEMP_LO
5955
5956        bftst           %d0{&2:&30}             # were bits shifted off?
5957        beq.b           case1_sticky_clear      # no; go finish
5958        bset            &rnd_stky_bit, %d0      # yes; set sticky bit
5959
5960case1_sticky_clear:
5961        and.l           &0xe0000000, %d0        # clear all but G,R,S
5962        mov.l           (%sp)+, %d2             # restore temp register
5963        rts
5964
5965#
5966# case (32<=d1<64)
5967#
5968# %d0 = denorm threshold
5969# %d1 = "n" = amt to shift
5970#
5971#       ---------------------------------------------------------
5972#       |     FTEMP_HI    |     FTEMP_LO     |grs000.........000|
5973#       ---------------------------------------------------------
5974#       <-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)->
5975#       \          \                  \
5976#        \          \                  \
5977#         \          \                  -------------------
5978#          \          --------------------                 \
5979#           -------------------           \                 \
5980#                              \           \                 \
5981#                               \           \                 \
5982#                                \           \                 \
5983#       <-------(32)------><-(n)-><-(32 - n)-><------(32)------->
5984#       ---------------------------------------------------------
5985#       |0...............0|0....0| NEW_LO     |grs              |
5986#       ---------------------------------------------------------
5987#
5988case_2:
5989        mov.l           %d2, -(%sp)             # create temp storage
5990
5991        mov.w           %d0, FTEMP_EX(%a0)      # exponent = denorm threshold
5992        subi.w          &0x20, %d1              # %d1 now between 0 and 32
5993        mov.l           &0x20, %d0
5994        sub.w           %d1, %d0                # %d0 = 32 - %d1
5995
5996# subtle step here; or in the g,r,s at the bottom of FTEMP_LO to minimize
5997# the number of bits to check for the sticky detect.
5998# it only plays a role in shift amounts of 61-63.
5999        mov.b           GRS(%a6), %d2
6000        or.b            %d2, 3+FTEMP_LO2(%a6)
6001
6002        bfextu          FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_LO
6003        bfextu          FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new G,R,S
6004
6005        bftst           %d1{&2:&30}             # were any bits shifted off?
6006        bne.b           case2_set_sticky        # yes; set sticky bit
6007        bftst           FTEMP_LO2(%a6){%d0:&31} # were any bits shifted off?
6008        bne.b           case2_set_sticky        # yes; set sticky bit
6009
6010        mov.l           %d1, %d0                # move new G,R,S to %d0
6011        bra.b           case2_end
6012
6013case2_set_sticky:
6014        mov.l           %d1, %d0                # move new G,R,S to %d0
6015        bset            &rnd_stky_bit, %d0      # set sticky bit
6016
6017case2_end:
6018        clr.l           FTEMP_HI(%a0)           # store FTEMP_HI = 0
6019        mov.l           %d2, FTEMP_LO(%a0)      # store FTEMP_LO
6020        and.l           &0xe0000000, %d0        # clear all but G,R,S
6021
6022        mov.l           (%sp)+,%d2              # restore temp register
6023        rts
6024
6025#
6026# case (d1>=64)
6027#
6028# %d0 = denorm threshold
6029# %d1 = amt to shift
6030#
6031case_3:
6032        mov.w           %d0, FTEMP_EX(%a0)      # insert denorm threshold
6033
6034        cmpi.w          %d1, &65                # is shift amt > 65?
6035        blt.b           case3_64                # no; it's == 64
6036        beq.b           case3_65                # no; it's == 65
6037
6038#
6039# case (d1>65)
6040#
6041# Shift value is > 65 and out of range. All bits are shifted off.
6042# Return a zero mantissa with the sticky bit set
6043#
6044        clr.l           FTEMP_HI(%a0)           # clear hi(mantissa)
6045        clr.l           FTEMP_LO(%a0)           # clear lo(mantissa)
6046        mov.l           &0x20000000, %d0        # set sticky bit
6047        rts
6048
6049#
6050# case (d1 == 64)
6051#
6052#       ---------------------------------------------------------
6053#       |     FTEMP_HI    |     FTEMP_LO     |grs000.........000|
6054#       ---------------------------------------------------------
6055#       <-------(32)------>
6056#       \                  \
6057#        \                  \
6058#         \                  \
6059#          \                  ------------------------------
6060#           -------------------------------                 \
6061#                                          \                 \
6062#                                           \                 \
6063#                                            \                 \
6064#                                             <-------(32)------>
6065#       ---------------------------------------------------------
6066#       |0...............0|0................0|grs               |
6067#       ---------------------------------------------------------
6068#
6069case3_64:
6070        mov.l           FTEMP_HI(%a0), %d0      # fetch hi(mantissa)
6071        mov.l           %d0, %d1                # make a copy
6072        and.l           &0xc0000000, %d0        # extract G,R
6073        and.l           &0x3fffffff, %d1        # extract other bits
6074
6075        bra.b           case3_complete
6076
6077#
6078# case (d1 == 65)
6079#
6080#       ---------------------------------------------------------
6081#       |     FTEMP_HI    |     FTEMP_LO     |grs000.........000|
6082#       ---------------------------------------------------------
6083#       <-------(32)------>
6084#       \                  \
6085#        \                  \
6086#         \                  \
6087#          \                  ------------------------------
6088#           --------------------------------                \
6089#                                           \                \
6090#                                            \                \
6091#                                             \                \
6092#                                              <-------(31)----->
6093#       ---------------------------------------------------------
6094#       |0...............0|0................0|0rs               |
6095#       ---------------------------------------------------------
6096#
6097case3_65:
6098        mov.l           FTEMP_HI(%a0), %d0      # fetch hi(mantissa)
6099        and.l           &0x80000000, %d0        # extract R bit
6100        lsr.l           &0x1, %d0               # shift high bit into R bit
6101        and.l           &0x7fffffff, %d1        # extract other bits
6102
6103case3_complete:
6104# last operation done was an "and" of the bits shifted off so the condition
6105# codes are already set so branch accordingly.
6106        bne.b           case3_set_sticky        # yes; go set new sticky
6107        tst.l           FTEMP_LO(%a0)           # were any bits shifted off?
6108        bne.b           case3_set_sticky        # yes; go set new sticky
6109        tst.b           GRS(%a6)                # were any bits shifted off?
6110        bne.b           case3_set_sticky        # yes; go set new sticky
6111
6112#
6113# no bits were shifted off so don't set the sticky bit.
6114# the guard and
6115# the entire mantissa is zero.
6116#
6117        clr.l           FTEMP_HI(%a0)           # clear hi(mantissa)
6118        clr.l           FTEMP_LO(%a0)           # clear lo(mantissa)
6119        rts
6120
6121#
6122# some bits were shifted off so set the sticky bit.
6123# the entire mantissa is zero.
6124#
6125case3_set_sticky:
6126        bset            &rnd_stky_bit,%d0       # set new sticky bit
6127        clr.l           FTEMP_HI(%a0)           # clear hi(mantissa)
6128        clr.l           FTEMP_LO(%a0)           # clear lo(mantissa)
6129        rts
6130
6131#########################################################################
6132# XDEF **************************************************************** #
6133#       _round(): round result according to precision/mode              #
6134#                                                                       #
6135# XREF **************************************************************** #
6136#       None                                                            #
6137#                                                                       #
6138# INPUT *************************************************************** #
6139#       a0        = ptr to input operand in internal extended format    #
6140#       d1(hi)    = contains rounding precision:                        #
6141#                       ext = $0000xxxx                                 #
6142#                       sgl = $0004xxxx                                 #
6143#                       dbl = $0008xxxx                                 #
6144#       d1(lo)    = contains rounding mode:                             #
6145#                       RN  = $xxxx0000                                 #
6146#                       RZ  = $xxxx0001                                 #
6147#                       RM  = $xxxx0002                                 #
6148#                       RP  = $xxxx0003                                 #
6149#       d0{31:29} = contains the g,r,s bits (extended)                  #
6150#                                                                       #
6151# OUTPUT ************************************************************** #
6152#       a0 = pointer to rounded result                                  #
6153#                                                                       #
6154# ALGORITHM *********************************************************** #
6155#       On return the value pointed to by a0 is correctly rounded,      #
6156#       a0 is preserved and the g-r-s bits in d0 are cleared.           #
6157#       The result is not typed - the tag field is invalid.  The        #
6158#       result is still in the internal extended format.                #
6159#                                                                       #
6160#       The INEX bit of USER_FPSR will be set if the rounded result was #
6161#       inexact (i.e. if any of the g-r-s bits were set).               #
6162#                                                                       #
6163#########################################################################
6164
6165        global          _round
6166_round:
6167#
6168# ext_grs() looks at the rounding precision and sets the appropriate
6169# G,R,S bits.
6170# If (G,R,S == 0) then result is exact and round is done, else set
6171# the inex flag in status reg and continue.
6172#
6173        bsr.l           ext_grs                 # extract G,R,S
6174
6175        tst.l           %d0                     # are G,R,S zero?
6176        beq.w           truncate                # yes; round is complete
6177
6178        or.w            &inx2a_mask, 2+USER_FPSR(%a6) # set inex2/ainex
6179
6180#
6181# Use rounding mode as an index into a jump table for these modes.
6182# All of the following assumes grs != 0.
6183#
6184        mov.w           (tbl_mode.b,%pc,%d1.w*2), %a1 # load jump offset
6185        jmp             (tbl_mode.b,%pc,%a1)    # jmp to rnd mode handler
6186
6187tbl_mode:
6188        short           rnd_near - tbl_mode
6189        short           truncate - tbl_mode     # RZ always truncates
6190        short           rnd_mnus - tbl_mode
6191        short           rnd_plus - tbl_mode
6192
6193#################################################################
6194#       ROUND PLUS INFINITY                                     #
6195#                                                               #
6196#       If sign of fp number = 0 (positive), then add 1 to l.   #
6197#################################################################
6198rnd_plus:
6199        tst.b           FTEMP_SGN(%a0)          # check for sign
6200        bmi.w           truncate                # if positive then truncate
6201
6202        mov.l           &0xffffffff, %d0        # force g,r,s to be all f's
6203        swap            %d1                     # set up d1 for round prec.
6204
6205        cmpi.b          %d1, &s_mode            # is prec = sgl?
6206        beq.w           add_sgl                 # yes
6207        bgt.w           add_dbl                 # no; it's dbl
6208        bra.w           add_ext                 # no; it's ext
6209
6210#################################################################
6211#       ROUND MINUS INFINITY                                    #
6212#                                                               #
6213#       If sign of fp number = 1 (negative), then add 1 to l.   #
6214#################################################################
6215rnd_mnus:
6216        tst.b           FTEMP_SGN(%a0)          # check for sign
6217        bpl.w           truncate                # if negative then truncate
6218
6219        mov.l           &0xffffffff, %d0        # force g,r,s to be all f's
6220        swap            %d1                     # set up d1 for round prec.
6221
6222        cmpi.b          %d1, &s_mode            # is prec = sgl?
6223        beq.w           add_sgl                 # yes
6224        bgt.w           add_dbl                 # no; it's dbl
6225        bra.w           add_ext                 # no; it's ext
6226
6227#################################################################
6228#       ROUND NEAREST                                           #
6229#                                                               #
6230#       If (g=1), then add 1 to l and if (r=s=0), then clear l  #
6231#       Note that this will round to even in case of a tie.     #
6232#################################################################
6233rnd_near:
6234        asl.l           &0x1, %d0               # shift g-bit to c-bit
6235        bcc.w           truncate                # if (g=1) then
6236
6237        swap            %d1                     # set up d1 for round prec.
6238
6239        cmpi.b          %d1, &s_mode            # is prec = sgl?
6240        beq.w           add_sgl                 # yes
6241        bgt.w           add_dbl                 # no; it's dbl
6242        bra.w           add_ext                 # no; it's ext
6243
6244# *** LOCAL EQUATES ***
6245set     ad_1_sgl,       0x00000100      # constant to add 1 to l-bit in sgl prec
6246set     ad_1_dbl,       0x00000800      # constant to add 1 to l-bit in dbl prec
6247
6248#########################
6249#       ADD SINGLE      #
6250#########################
6251add_sgl:
6252        add.l           &ad_1_sgl, FTEMP_HI(%a0)
6253        bcc.b           scc_clr                 # no mantissa overflow
6254        roxr.w          FTEMP_HI(%a0)           # shift v-bit back in
6255        roxr.w          FTEMP_HI+2(%a0)         # shift v-bit back in
6256        add.w           &0x1, FTEMP_EX(%a0)     # and incr exponent
6257scc_clr:
6258        tst.l           %d0                     # test for rs = 0
6259        bne.b           sgl_done
6260        and.w           &0xfe00, FTEMP_HI+2(%a0) # clear the l-bit
6261sgl_done:
6262        and.l           &0xffffff00, FTEMP_HI(%a0) # truncate bits beyond sgl limit
6263        clr.l           FTEMP_LO(%a0)           # clear d2
6264        rts
6265
6266#########################
6267#       ADD EXTENDED    #
6268#########################
6269add_ext:
6270        addq.l          &1,FTEMP_LO(%a0)        # add 1 to l-bit
6271        bcc.b           xcc_clr                 # test for carry out
6272        addq.l          &1,FTEMP_HI(%a0)        # propagate carry
6273        bcc.b           xcc_clr
6274        roxr.w          FTEMP_HI(%a0)           # mant is 0 so restore v-bit
6275        roxr.w          FTEMP_HI+2(%a0)         # mant is 0 so restore v-bit
6276        roxr.w          FTEMP_LO(%a0)
6277        roxr.w          FTEMP_LO+2(%a0)
6278        add.w           &0x1,FTEMP_EX(%a0)      # and inc exp
6279xcc_clr:
6280        tst.l           %d0                     # test rs = 0
6281        bne.b           add_ext_done
6282        and.b           &0xfe,FTEMP_LO+3(%a0)   # clear the l bit
6283add_ext_done:
6284        rts
6285
6286#########################
6287#       ADD DOUBLE      #
6288#########################
6289add_dbl:
6290        add.l           &ad_1_dbl, FTEMP_LO(%a0) # add 1 to lsb
6291        bcc.b           dcc_clr                 # no carry
6292        addq.l          &0x1, FTEMP_HI(%a0)     # propagate carry
6293        bcc.b           dcc_clr                 # no carry
6294
6295        roxr.w          FTEMP_HI(%a0)           # mant is 0 so restore v-bit
6296        roxr.w          FTEMP_HI+2(%a0)         # mant is 0 so restore v-bit
6297        roxr.w          FTEMP_LO(%a0)
6298        roxr.w          FTEMP_LO+2(%a0)
6299        addq.w          &0x1, FTEMP_EX(%a0)     # incr exponent
6300dcc_clr:
6301        tst.l           %d0                     # test for rs = 0
6302        bne.b           dbl_done
6303        and.w           &0xf000, FTEMP_LO+2(%a0) # clear the l-bit
6304
6305dbl_done:
6306        and.l           &0xfffff800,FTEMP_LO(%a0) # truncate bits beyond dbl limit
6307        rts
6308
6309###########################
6310# Truncate all other bits #
6311###########################
6312truncate:
6313        swap            %d1                     # select rnd prec
6314
6315        cmpi.b          %d1, &s_mode            # is prec sgl?
6316        beq.w           sgl_done                # yes
6317        bgt.b           dbl_done                # no; it's dbl
6318        rts                                     # no; it's ext
6319
6320
6321#
6322# ext_grs(): extract guard, round and sticky bits according to
6323#            rounding precision.
6324#
6325# INPUT
6326#       d0         = extended precision g,r,s (in d0{31:29})
6327#       d1         = {PREC,ROUND}
6328# OUTPUT
6329#       d0{31:29}  = guard, round, sticky
6330#
6331# The ext_grs extract the guard/round/sticky bits according to the
6332# selected rounding precision. It is called by the round subroutine
6333# only.  All registers except d0 are kept intact. d0 becomes an
6334# updated guard,round,sticky in d0{31:29}
6335#
6336# Notes: the ext_grs uses the round PREC, and therefore has to swap d1
6337#        prior to usage, and needs to restore d1 to original. this
6338#        routine is tightly tied to the round routine and not meant to
6339#        uphold standard subroutine calling practices.
6340#
6341
6342ext_grs:
6343        swap            %d1                     # have d1.w point to round precision
6344        tst.b           %d1                     # is rnd prec = extended?
6345        bne.b           ext_grs_not_ext         # no; go handle sgl or dbl
6346
6347#
6348# %d0 actually already hold g,r,s since _round() had it before calling
6349# this function. so, as long as we don't disturb it, we are "returning" it.
6350#
6351ext_grs_ext:
6352        swap            %d1                     # yes; return to correct positions
6353        rts
6354
6355ext_grs_not_ext:
6356        movm.l          &0x3000, -(%sp)         # make some temp registers {d2/d3}
6357
6358        cmpi.b          %d1, &s_mode            # is rnd prec = sgl?
6359        bne.b           ext_grs_dbl             # no; go handle dbl
6360
6361#
6362# sgl:
6363#       96              64        40    32              0
6364#       -----------------------------------------------------
6365#       | EXP   |XXXXXXX|         |xx   |               |grs|
6366#       -----------------------------------------------------
6367#                       <--(24)--->nn\                     /
6368#                                  ee ---------------------
6369#                                  ww           |
6370#                                               v
6371#                                  gr      new sticky
6372#
6373ext_grs_sgl:
6374        bfextu          FTEMP_HI(%a0){&24:&2}, %d3 # sgl prec. g-r are 2 bits right
6375        mov.l           &30, %d2                # of the sgl prec. limits
6376        lsl.l           %d2, %d3                # shift g-r bits to MSB of d3
6377        mov.l           FTEMP_HI(%a0), %d2      # get word 2 for s-bit test
6378        and.l           &0x0000003f, %d2        # s bit is the or of all other
6379        bne.b           ext_grs_st_stky         # bits to the right of g-r
6380        tst.l           FTEMP_LO(%a0)           # test lower mantissa
6381        bne.b           ext_grs_st_stky         # if any are set, set sticky
6382        tst.l           %d0                     # test original g,r,s
6383        bne.b           ext_grs_st_stky         # if any are set, set sticky
6384        bra.b           ext_grs_end_sd          # if words 3 and 4 are clr, exit
6385
6386#
6387# dbl:
6388#       96              64              32       11     0
6389#       -----------------------------------------------------
6390#       | EXP   |XXXXXXX|               |        |xx    |grs|
6391#       -----------------------------------------------------
6392#                                                 nn\       /
6393#                                                 ee -------
6394#                                                 ww    |
6395#                                                       v
6396#                                                 gr    new sticky
6397#
6398ext_grs_dbl:
6399        bfextu          FTEMP_LO(%a0){&21:&2}, %d3 # dbl-prec. g-r are 2 bits right
6400        mov.l           &30, %d2                # of the dbl prec. limits
6401        lsl.l           %d2, %d3                # shift g-r bits to the MSB of d3
6402        mov.l           FTEMP_LO(%a0), %d2      # get lower mantissa  for s-bit test
6403        and.l           &0x000001ff, %d2        # s bit is the or-ing of all
6404        bne.b           ext_grs_st_stky         # other bits to the right of g-r
6405        tst.l           %d0                     # test word original g,r,s
6406        bne.b           ext_grs_st_stky         # if any are set, set sticky
6407        bra.b           ext_grs_end_sd          # if clear, exit
6408
6409ext_grs_st_stky:
6410        bset            &rnd_stky_bit, %d3      # set sticky bit
6411ext_grs_end_sd:
6412        mov.l           %d3, %d0                # return grs to d0
6413
6414        movm.l          (%sp)+, &0xc            # restore scratch registers {d2/d3}
6415
6416        swap            %d1                     # restore d1 to original
6417        rts
6418
6419#########################################################################
6420# norm(): normalize the mantissa of an extended precision input. the    #
6421#         input operand should not be normalized already.               #
6422#                                                                       #
6423# XDEF **************************************************************** #
6424#       norm()                                                          #
6425#                                                                       #
6426# XREF **************************************************************** #
6427#       none                                                            #
6428#                                                                       #
6429# INPUT *************************************************************** #
6430#       a0 = pointer fp extended precision operand to normalize         #
6431#                                                                       #
6432# OUTPUT ************************************************************** #
6433#       d0 = number of bit positions the mantissa was shifted           #
6434#       a0 = the input operand's mantissa is normalized; the exponent   #
6435#            is unchanged.                                              #
6436#                                                                       #
6437#########################################################################
6438        global          norm
6439norm:
6440        mov.l           %d2, -(%sp)             # create some temp regs
6441        mov.l           %d3, -(%sp)
6442
6443        mov.l           FTEMP_HI(%a0), %d0      # load hi(mantissa)
6444        mov.l           FTEMP_LO(%a0), %d1      # load lo(mantissa)
6445
6446        bfffo           %d0{&0:&32}, %d2        # how many places to shift?
6447        beq.b           norm_lo                 # hi(man) is all zeroes!
6448
6449norm_hi:
6450        lsl.l           %d2, %d0                # left shift hi(man)
6451        bfextu          %d1{&0:%d2}, %d3        # extract lo bits
6452
6453        or.l            %d3, %d0                # create hi(man)
6454        lsl.l           %d2, %d1                # create lo(man)
6455
6456        mov.l           %d0, FTEMP_HI(%a0)      # store new hi(man)
6457        mov.l           %d1, FTEMP_LO(%a0)      # store new lo(man)
6458
6459        mov.l           %d2, %d0                # return shift amount
6460
6461        mov.l           (%sp)+, %d3             # restore temp regs
6462        mov.l           (%sp)+, %d2
6463
6464        rts
6465
6466norm_lo:
6467        bfffo           %d1{&0:&32}, %d2        # how many places to shift?
6468        lsl.l           %d2, %d1                # shift lo(man)
6469        add.l           &32, %d2                # add 32 to shft amount
6470
6471        mov.l           %d1, FTEMP_HI(%a0)      # store hi(man)
6472        clr.l           FTEMP_LO(%a0)           # lo(man) is now zero
6473
6474        mov.l           %d2, %d0                # return shift amount
6475
6476        mov.l           (%sp)+, %d3             # restore temp regs
6477        mov.l           (%sp)+, %d2
6478
6479        rts
6480
6481#########################################################################
6482# unnorm_fix(): - changes an UNNORM to one of NORM, DENORM, or ZERO     #
6483#               - returns corresponding optype tag                      #
6484#                                                                       #
6485# XDEF **************************************************************** #
6486#       unnorm_fix()                                                    #
6487#                                                                       #
6488# XREF **************************************************************** #
6489#       norm() - normalize the mantissa                                 #
6490#                                                                       #
6491# INPUT *************************************************************** #
6492#       a0 = pointer to unnormalized extended precision number          #
6493#                                                                       #
6494# OUTPUT ************************************************************** #
6495#       d0 = optype tag - is corrected to one of NORM, DENORM, or ZERO  #
6496#       a0 = input operand has been converted to a norm, denorm, or     #
6497#            zero; both the exponent and mantissa are changed.          #
6498#                                                                       #
6499#########################################################################
6500
6501        global          unnorm_fix
6502unnorm_fix:
6503        bfffo           FTEMP_HI(%a0){&0:&32}, %d0 # how many shifts are needed?
6504        bne.b           unnorm_shift            # hi(man) is not all zeroes
6505
6506#
6507# hi(man) is all zeroes so see if any bits in lo(man) are set
6508#
6509unnorm_chk_lo:
6510        bfffo           FTEMP_LO(%a0){&0:&32}, %d0 # is operand really a zero?
6511        beq.w           unnorm_zero             # yes
6512
6513        add.w           &32, %d0                # no; fix shift distance
6514
6515#
6516# d0 = # shifts needed for complete normalization
6517#
6518unnorm_shift:
6519        clr.l           %d1                     # clear top word
6520        mov.w           FTEMP_EX(%a0), %d1      # extract exponent
6521        and.w           &0x7fff, %d1            # strip off sgn
6522
6523        cmp.w           %d0, %d1                # will denorm push exp < 0?
6524        bgt.b           unnorm_nrm_zero         # yes; denorm only until exp = 0
6525
6526#
6527# exponent would not go < 0. Therefore, number stays normalized
6528#
6529        sub.w           %d0, %d1                # shift exponent value
6530        mov.w           FTEMP_EX(%a0), %d0      # load old exponent
6531        and.w           &0x8000, %d0            # save old sign
6532        or.w            %d0, %d1                # {sgn,new exp}
6533        mov.w           %d1, FTEMP_EX(%a0)      # insert new exponent
6534
6535        bsr.l           norm                    # normalize UNNORM
6536
6537        mov.b           &NORM, %d0              # return new optype tag
6538        rts
6539
6540#
6541# exponent would go < 0, so only denormalize until exp = 0
6542#
6543unnorm_nrm_zero:
6544        cmp.b           %d1, &32                # is exp <= 32?
6545        bgt.b           unnorm_nrm_zero_lrg     # no; go handle large exponent
6546
6547        bfextu          FTEMP_HI(%a0){%d1:&32}, %d0 # extract new hi(man)
6548        mov.l           %d0, FTEMP_HI(%a0)      # save new hi(man)
6549
6550        mov.l           FTEMP_LO(%a0), %d0      # fetch old lo(man)
6551        lsl.l           %d1, %d0                # extract new lo(man)
6552        mov.l           %d0, FTEMP_LO(%a0)      # save new lo(man)
6553
6554        and.w           &0x8000, FTEMP_EX(%a0)  # set exp = 0
6555
6556        mov.b           &DENORM, %d0            # return new optype tag
6557        rts
6558
6559#
6560# only mantissa bits set are in lo(man)
6561#
6562unnorm_nrm_zero_lrg:
6563        sub.w           &32, %d1                # adjust shft amt by 32
6564
6565        mov.l           FTEMP_LO(%a0), %d0      # fetch old lo(man)
6566        lsl.l           %d1, %d0                # left shift lo(man)
6567
6568        mov.l           %d0, FTEMP_HI(%a0)      # store new hi(man)
6569        clr.l           FTEMP_LO(%a0)           # lo(man) = 0
6570
6571        and.w           &0x8000, FTEMP_EX(%a0)  # set exp = 0
6572
6573        mov.b           &DENORM, %d0            # return new optype tag
6574        rts
6575
6576#
6577# whole mantissa is zero so this UNNORM is actually a zero
6578#
6579unnorm_zero:
6580        and.w           &0x8000, FTEMP_EX(%a0)  # force exponent to zero
6581
6582        mov.b           &ZERO, %d0              # fix optype tag
6583        rts
6584
6585#########################################################################
6586# XDEF **************************************************************** #
6587#       set_tag_x(): return the optype of the input ext fp number       #
6588#                                                                       #
6589# XREF **************************************************************** #
6590#       None                                                            #
6591#                                                                       #
6592# INPUT *************************************************************** #
6593#       a0 = pointer to extended precision operand                      #
6594#                                                                       #
6595# OUTPUT ************************************************************** #
6596#       d0 = value of type tag                                          #
6597#               one of: NORM, INF, QNAN, SNAN, DENORM, UNNORM, ZERO     #
6598#                                                                       #
6599# ALGORITHM *********************************************************** #
6600#       Simply test the exponent, j-bit, and mantissa values to         #
6601# determine the type of operand.                                        #
6602#       If it's an unnormalized zero, alter the operand and force it    #
6603# to be a normal zero.                                                  #
6604#                                                                       #
6605#########################################################################
6606
6607        global          set_tag_x
6608set_tag_x:
6609        mov.w           FTEMP_EX(%a0), %d0      # extract exponent
6610        andi.w          &0x7fff, %d0            # strip off sign
6611        cmpi.w          %d0, &0x7fff            # is (EXP == MAX)?
6612        beq.b           inf_or_nan_x
6613not_inf_or_nan_x:
6614        btst            &0x7,FTEMP_HI(%a0)
6615        beq.b           not_norm_x
6616is_norm_x:
6617        mov.b           &NORM, %d0
6618        rts
6619not_norm_x:
6620        tst.w           %d0                     # is exponent = 0?
6621        bne.b           is_unnorm_x
6622not_unnorm_x:
6623        tst.l           FTEMP_HI(%a0)
6624        bne.b           is_denorm_x
6625        tst.l           FTEMP_LO(%a0)
6626        bne.b           is_denorm_x
6627is_zero_x:
6628        mov.b           &ZERO, %d0
6629        rts
6630is_denorm_x:
6631        mov.b           &DENORM, %d0
6632        rts
6633# must distinguish now "Unnormalized zeroes" which we
6634# must convert to zero.
6635is_unnorm_x:
6636        tst.l           FTEMP_HI(%a0)
6637        bne.b           is_unnorm_reg_x
6638        tst.l           FTEMP_LO(%a0)
6639        bne.b           is_unnorm_reg_x
6640# it's an "unnormalized zero". let's convert it to an actual zero...
6641        andi.w          &0x8000,FTEMP_EX(%a0)   # clear exponent
6642        mov.b           &ZERO, %d0
6643        rts
6644is_unnorm_reg_x:
6645        mov.b           &UNNORM, %d0
6646        rts
6647inf_or_nan_x:
6648        tst.l           FTEMP_LO(%a0)
6649        bne.b           is_nan_x
6650        mov.l           FTEMP_HI(%a0), %d0
6651        and.l           &0x7fffffff, %d0        # msb is a don't care!
6652        bne.b           is_nan_x
6653is_inf_x:
6654        mov.b           &INF, %d0
6655        rts
6656is_nan_x:
6657        btst            &0x6, FTEMP_HI(%a0)
6658        beq.b           is_snan_x
6659        mov.b           &QNAN, %d0
6660        rts
6661is_snan_x:
6662        mov.b           &SNAN, %d0
6663        rts
6664
6665#########################################################################
6666# XDEF **************************************************************** #
6667#       set_tag_d(): return the optype of the input dbl fp number       #
6668#                                                                       #
6669# XREF **************************************************************** #
6670#       None                                                            #
6671#                                                                       #
6672# INPUT *************************************************************** #
6673#       a0 = points to double precision operand                         #
6674#                                                                       #
6675# OUTPUT ************************************************************** #
6676#       d0 = value of type tag                                          #
6677#               one of: NORM, INF, QNAN, SNAN, DENORM, ZERO             #
6678#                                                                       #
6679# ALGORITHM *********************************************************** #
6680#       Simply test the exponent, j-bit, and mantissa values to         #
6681# determine the type of operand.                                        #
6682#                                                                       #
6683#########################################################################
6684
6685        global          set_tag_d
6686set_tag_d:
6687        mov.l           FTEMP(%a0), %d0
6688        mov.l           %d0, %d1
6689
6690        andi.l          &0x7ff00000, %d0
6691        beq.b           zero_or_denorm_d
6692
6693        cmpi.l          %d0, &0x7ff00000
6694        beq.b           inf_or_nan_d
6695
6696is_norm_d:
6697        mov.b           &NORM, %d0
6698        rts
6699zero_or_denorm_d:
6700        and.l           &0x000fffff, %d1
6701        bne             is_denorm_d
6702        tst.l           4+FTEMP(%a0)
6703        bne             is_denorm_d
6704is_zero_d:
6705        mov.b           &ZERO, %d0
6706        rts
6707is_denorm_d:
6708        mov.b           &DENORM, %d0
6709        rts
6710inf_or_nan_d:
6711        and.l           &0x000fffff, %d1
6712        bne             is_nan_d
6713        tst.l           4+FTEMP(%a0)
6714        bne             is_nan_d
6715is_inf_d:
6716        mov.b           &INF, %d0
6717        rts
6718is_nan_d:
6719        btst            &19, %d1
6720        bne             is_qnan_d
6721is_snan_d:
6722        mov.b           &SNAN, %d0
6723        rts
6724is_qnan_d:
6725        mov.b           &QNAN, %d0
6726        rts
6727
6728#########################################################################
6729# XDEF **************************************************************** #
6730#       set_tag_s(): return the optype of the input sgl fp number       #
6731#                                                                       #
6732# XREF **************************************************************** #
6733#       None                                                            #
6734#                                                                       #
6735# INPUT *************************************************************** #
6736#       a0 = pointer to single precision operand                        #
6737#                                                                       #
6738# OUTPUT ************************************************************** #
6739#       d0 = value of type tag                                          #
6740#               one of: NORM, INF, QNAN, SNAN, DENORM, ZERO             #
6741#                                                                       #
6742# ALGORITHM *********************************************************** #
6743#       Simply test the exponent, j-bit, and mantissa values to         #
6744# determine the type of operand.                                        #
6745#                                                                       #
6746#########################################################################
6747
6748        global          set_tag_s
6749set_tag_s:
6750        mov.l           FTEMP(%a0), %d0
6751        mov.l           %d0, %d1
6752
6753        andi.l          &0x7f800000, %d0
6754        beq.b           zero_or_denorm_s
6755
6756        cmpi.l          %d0, &0x7f800000
6757        beq.b           inf_or_nan_s
6758
6759is_norm_s:
6760        mov.b           &NORM, %d0
6761        rts
6762zero_or_denorm_s:
6763        and.l           &0x007fffff, %d1
6764        bne             is_denorm_s
6765is_zero_s:
6766        mov.b           &ZERO, %d0
6767        rts
6768is_denorm_s:
6769        mov.b           &DENORM, %d0
6770        rts
6771inf_or_nan_s:
6772        and.l           &0x007fffff, %d1
6773        bne             is_nan_s
6774is_inf_s:
6775        mov.b           &INF, %d0
6776        rts
6777is_nan_s:
6778        btst            &22, %d1
6779        bne             is_qnan_s
6780is_snan_s:
6781        mov.b           &SNAN, %d0
6782        rts
6783is_qnan_s:
6784        mov.b           &QNAN, %d0
6785        rts
6786
6787#########################################################################
6788# XDEF **************************************************************** #
6789#       unf_res(): routine to produce default underflow result of a     #
6790#                  scaled extended precision number; this is used by    #
6791#                  fadd/fdiv/fmul/etc. emulation routines.              #
6792#       unf_res4(): same as above but for fsglmul/fsgldiv which use     #
6793#                   single round prec and extended prec mode.           #
6794#                                                                       #
6795# XREF **************************************************************** #
6796#       _denorm() - denormalize according to scale factor               #
6797#       _round() - round denormalized number according to rnd prec      #
6798#                                                                       #
6799# INPUT *************************************************************** #
6800#       a0 = pointer to extended precison operand                       #
6801#       d0 = scale factor                                               #
6802#       d1 = rounding precision/mode                                    #
6803#                                                                       #
6804# OUTPUT ************************************************************** #
6805#       a0 = pointer to default underflow result in extended precision  #
6806#       d0.b = result FPSR_cc which caller may or may not want to save  #
6807#                                                                       #
6808# ALGORITHM *********************************************************** #
6809#       Convert the input operand to "internal format" which means the  #
6810# exponent is extended to 16 bits and the sign is stored in the unused  #
6811# portion of the extended precison operand. Denormalize the number      #
6812# according to the scale factor passed in d0. Then, round the           #
6813# denormalized result.                                                  #
6814#       Set the FPSR_exc bits as appropriate but return the cc bits in  #
6815# d0 in case the caller doesn't want to save them (as is the case for   #
6816# fmove out).                                                           #
6817#       unf_res4() for fsglmul/fsgldiv forces the denorm to extended    #
6818# precision and the rounding mode to single.                            #
6819#                                                                       #
6820#########################################################################
6821        global          unf_res
6822unf_res:
6823        mov.l           %d1, -(%sp)             # save rnd prec,mode on stack
6824
6825        btst            &0x7, FTEMP_EX(%a0)     # make "internal" format
6826        sne             FTEMP_SGN(%a0)
6827
6828        mov.w           FTEMP_EX(%a0), %d1      # extract exponent
6829        and.w           &0x7fff, %d1
6830        sub.w           %d0, %d1
6831        mov.w           %d1, FTEMP_EX(%a0)      # insert 16 bit exponent
6832
6833        mov.l           %a0, -(%sp)             # save operand ptr during calls
6834
6835        mov.l           0x4(%sp),%d0            # pass rnd prec.
6836        andi.w          &0x00c0,%d0
6837        lsr.w           &0x4,%d0
6838        bsr.l           _denorm                 # denorm result
6839
6840        mov.l           (%sp),%a0
6841        mov.w           0x6(%sp),%d1            # load prec:mode into %d1
6842        andi.w          &0xc0,%d1               # extract rnd prec
6843        lsr.w           &0x4,%d1
6844        swap            %d1
6845        mov.w           0x6(%sp),%d1
6846        andi.w          &0x30,%d1
6847        lsr.w           &0x4,%d1
6848        bsr.l           _round                  # round the denorm
6849
6850        mov.l           (%sp)+, %a0
6851
6852# result is now rounded properly. convert back to normal format
6853        bclr            &0x7, FTEMP_EX(%a0)     # clear sgn first; may have residue
6854        tst.b           FTEMP_SGN(%a0)          # is "internal result" sign set?
6855        beq.b           unf_res_chkifzero       # no; result is positive
6856        bset            &0x7, FTEMP_EX(%a0)     # set result sgn
6857        clr.b           FTEMP_SGN(%a0)          # clear temp sign
6858
6859# the number may have become zero after rounding. set ccodes accordingly.
6860unf_res_chkifzero:
6861        clr.l           %d0
6862        tst.l           FTEMP_HI(%a0)           # is value now a zero?
6863        bne.b           unf_res_cont            # no
6864        tst.l           FTEMP_LO(%a0)
6865        bne.b           unf_res_cont            # no
6866#       bset            &z_bit, FPSR_CC(%a6)    # yes; set zero ccode bit
6867        bset            &z_bit, %d0             # yes; set zero ccode bit
6868
6869unf_res_cont:
6870
6871#
6872# can inex1 also be set along with unfl and inex2???
6873#
6874# we know that underflow has occurred. aunfl should be set if INEX2 is also set.
6875#
6876        btst            &inex2_bit, FPSR_EXCEPT(%a6) # is INEX2 set?
6877        beq.b           unf_res_end             # no
6878        bset            &aunfl_bit, FPSR_AEXCEPT(%a6) # yes; set aunfl
6879
6880unf_res_end:
6881        add.l           &0x4, %sp               # clear stack
6882        rts
6883
6884# unf_res() for fsglmul() and fsgldiv().
6885        global          unf_res4
6886unf_res4:
6887        mov.l           %d1,-(%sp)              # save rnd prec,mode on stack
6888
6889        btst            &0x7,FTEMP_EX(%a0)      # make "internal" format
6890        sne             FTEMP_SGN(%a0)
6891
6892        mov.w           FTEMP_EX(%a0),%d1       # extract exponent
6893        and.w           &0x7fff,%d1
6894        sub.w           %d0,%d1
6895        mov.w           %d1,FTEMP_EX(%a0)       # insert 16 bit exponent
6896
6897        mov.l           %a0,-(%sp)              # save operand ptr during calls
6898
6899        clr.l           %d0                     # force rnd prec = ext
6900        bsr.l           _denorm                 # denorm result
6901
6902        mov.l           (%sp),%a0
6903        mov.w           &s_mode,%d1             # force rnd prec = sgl
6904        swap            %d1
6905        mov.w           0x6(%sp),%d1            # load rnd mode
6906        andi.w          &0x30,%d1               # extract rnd prec
6907        lsr.w           &0x4,%d1
6908        bsr.l           _round                  # round the denorm
6909
6910        mov.l           (%sp)+,%a0
6911
6912# result is now rounded properly. convert back to normal format
6913        bclr            &0x7,FTEMP_EX(%a0)      # clear sgn first; may have residue
6914        tst.b           FTEMP_SGN(%a0)          # is "internal result" sign set?
6915        beq.b           unf_res4_chkifzero      # no; result is positive
6916        bset            &0x7,FTEMP_EX(%a0)      # set result sgn
6917        clr.b           FTEMP_SGN(%a0)          # clear temp sign
6918
6919# the number may have become zero after rounding. set ccodes accordingly.
6920unf_res4_chkifzero:
6921        clr.l           %d0
6922        tst.l           FTEMP_HI(%a0)           # is value now a zero?
6923        bne.b           unf_res4_cont           # no
6924        tst.l           FTEMP_LO(%a0)
6925        bne.b           unf_res4_cont           # no
6926#       bset            &z_bit,FPSR_CC(%a6)     # yes; set zero ccode bit
6927        bset            &z_bit,%d0              # yes; set zero ccode bit
6928
6929unf_res4_cont:
6930
6931#
6932# can inex1 also be set along with unfl and inex2???
6933#
6934# we know that underflow has occurred. aunfl should be set if INEX2 is also set.
6935#
6936        btst            &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
6937        beq.b           unf_res4_end            # no
6938        bset            &aunfl_bit,FPSR_AEXCEPT(%a6) # yes; set aunfl
6939
6940unf_res4_end:
6941        add.l           &0x4,%sp                # clear stack
6942        rts
6943
6944#########################################################################
6945# XDEF **************************************************************** #
6946#       ovf_res(): routine to produce the default overflow result of    #
6947#                  an overflowing number.                               #
6948#       ovf_res2(): same as above but the rnd mode/prec are passed      #
6949#                   differently.                                        #
6950#                                                                       #
6951# XREF **************************************************************** #
6952#       none                                                            #
6953#                                                                       #
6954# INPUT *************************************************************** #
6955#       d1.b    = '-1' => (-); '0' => (+)                               #
6956#   ovf_res():                                                          #
6957#       d0      = rnd mode/prec                                         #
6958#   ovf_res2():                                                         #
6959#       hi(d0)  = rnd prec                                              #
6960#       lo(d0)  = rnd mode                                              #
6961#                                                                       #
6962# OUTPUT ************************************************************** #
6963#       a0      = points to extended precision result                   #
6964#       d0.b    = condition code bits                                   #
6965#                                                                       #
6966# ALGORITHM *********************************************************** #
6967#       The default overflow result can be determined by the sign of    #
6968# the result and the rounding mode/prec in effect. These bits are       #
6969# concatenated together to create an index into the default result      #
6970# table. A pointer to the correct result is returned in a0. The         #
6971# resulting condition codes are returned in d0 in case the caller       #
6972# doesn't want FPSR_cc altered (as is the case for fmove out).          #
6973#                                                                       #
6974#########################################################################
6975
6976        global          ovf_res
6977ovf_res:
6978        andi.w          &0x10,%d1               # keep result sign
6979        lsr.b           &0x4,%d0                # shift prec/mode
6980        or.b            %d0,%d1                 # concat the two
6981        mov.w           %d1,%d0                 # make a copy
6982        lsl.b           &0x1,%d1                # multiply d1 by 2
6983        bra.b           ovf_res_load
6984
6985        global          ovf_res2
6986ovf_res2:
6987        and.w           &0x10, %d1              # keep result sign
6988        or.b            %d0, %d1                # insert rnd mode
6989        swap            %d0
6990        or.b            %d0, %d1                # insert rnd prec
6991        mov.w           %d1, %d0                # make a copy
6992        lsl.b           &0x1, %d1               # shift left by 1
6993
6994#
6995# use the rounding mode, precision, and result sign as in index into the
6996# two tables below to fetch the default result and the result ccodes.
6997#
6998ovf_res_load:
6999        mov.b           (tbl_ovfl_cc.b,%pc,%d0.w*1), %d0 # fetch result ccodes
7000        lea             (tbl_ovfl_result.b,%pc,%d1.w*8), %a0 # return result ptr
7001
7002        rts
7003
7004tbl_ovfl_cc:
7005        byte            0x2, 0x0, 0x0, 0x2
7006        byte            0x2, 0x0, 0x0, 0x2
7007        byte            0x2, 0x0, 0x0, 0x2
7008        byte            0x0, 0x0, 0x0, 0x0
7009        byte            0x2+0x8, 0x8, 0x2+0x8, 0x8
7010        byte            0x2+0x8, 0x8, 0x2+0x8, 0x8
7011        byte            0x2+0x8, 0x8, 0x2+0x8, 0x8
7012
7013tbl_ovfl_result:
7014        long            0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
7015        long            0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RZ
7016        long            0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RM
7017        long            0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP
7018
7019        long            0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
7020        long            0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RZ
7021        long            0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RM
7022        long            0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP
7023
7024        long            0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
7025        long            0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RZ
7026        long            0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RM
7027        long            0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP
7028
7029        long            0x00000000,0x00000000,0x00000000,0x00000000
7030        long            0x00000000,0x00000000,0x00000000,0x00000000
7031        long            0x00000000,0x00000000,0x00000000,0x00000000
7032        long            0x00000000,0x00000000,0x00000000,0x00000000
7033
7034        long            0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
7035        long            0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RZ
7036        long            0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
7037        long            0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RP
7038
7039        long            0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
7040        long            0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RZ
7041        long            0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
7042        long            0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RP
7043
7044        long            0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
7045        long            0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RZ
7046        long            0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
7047        long            0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RP
7048
7049#########################################################################
7050# XDEF **************************************************************** #
7051#       fout(): move from fp register to memory or data register        #
7052#                                                                       #
7053# XREF **************************************************************** #
7054#       _round() - needed to create EXOP for sgl/dbl precision          #
7055#       norm() - needed to create EXOP for extended precision           #
7056#       ovf_res() - create default overflow result for sgl/dbl precision#
7057#       unf_res() - create default underflow result for sgl/dbl prec.   #
7058#       dst_dbl() - create rounded dbl precision result.                #
7059#       dst_sgl() - create rounded sgl precision result.                #
7060#       fetch_dreg() - fetch dynamic k-factor reg for packed.           #
7061#       bindec() - convert FP binary number to packed number.           #
7062#       _mem_write() - write data to memory.                            #
7063#       _mem_write2() - write data to memory unless supv mode -(a7) exc.#
7064#       _dmem_write_{byte,word,long}() - write data to memory.          #
7065#       store_dreg_{b,w,l}() - store data to data register file.        #
7066#       facc_out_{b,w,l,d,x}() - data access error occurred.            #
7067#                                                                       #
7068# INPUT *************************************************************** #
7069#       a0 = pointer to extended precision source operand               #
7070#       d0 = round prec,mode                                            #
7071#                                                                       #
7072# OUTPUT ************************************************************** #
7073#       fp0 : intermediate underflow or overflow result if              #
7074#             OVFL/UNFL occurred for a sgl or dbl operand               #
7075#                                                                       #
7076# ALGORITHM *********************************************************** #
7077#       This routine is accessed by many handlers that need to do an    #
7078# opclass three move of an operand out to memory.                       #
7079#       Decode an fmove out (opclass 3) instruction to determine if     #
7080# it's b,w,l,s,d,x, or p in size. b,w,l can be stored to either a data  #
7081# register or memory. The algorithm uses a standard "fmove" to create   #
7082# the rounded result. Also, since exceptions are disabled, this also    #
7083# create the correct OPERR default result if appropriate.               #
7084#       For sgl or dbl precision, overflow or underflow can occur. If   #
7085# either occurs and is enabled, the EXOP.                               #
7086#       For extended precision, the stacked <ea> must be fixed along    #
7087# w/ the address index register as appropriate w/ _calc_ea_fout(). If   #
7088# the source is a denorm and if underflow is enabled, an EXOP must be   #
7089# created.                                                              #
7090#       For packed, the k-factor must be fetched from the instruction   #
7091# word or a data register. The <ea> must be fixed as w/ extended        #
7092# precision. Then, bindec() is called to create the appropriate         #
7093# packed result.                                                        #
7094#       If at any time an access error is flagged by one of the move-   #
7095# to-memory routines, then a special exit must be made so that the      #
7096# access error can be handled properly.                                 #
7097#                                                                       #
7098#########################################################################
7099
7100        global          fout
7101fout:
7102        bfextu          EXC_CMDREG(%a6){&3:&3},%d1 # extract dst fmt
7103        mov.w           (tbl_fout.b,%pc,%d1.w*2),%a1 # use as index
7104        jmp             (tbl_fout.b,%pc,%a1)    # jump to routine
7105
7106        swbeg           &0x8
7107tbl_fout:
7108        short           fout_long       -       tbl_fout
7109        short           fout_sgl        -       tbl_fout
7110        short           fout_ext        -       tbl_fout
7111        short           fout_pack       -       tbl_fout
7112        short           fout_word       -       tbl_fout
7113        short           fout_dbl        -       tbl_fout
7114        short           fout_byte       -       tbl_fout
7115        short           fout_pack       -       tbl_fout
7116
7117#################################################################
7118# fmove.b out ###################################################
7119#################################################################
7120
7121# Only "Unimplemented Data Type" exceptions enter here. The operand
7122# is either a DENORM or a NORM.
7123fout_byte:
7124        tst.b           STAG(%a6)               # is operand normalized?
7125        bne.b           fout_byte_denorm        # no
7126
7127        fmovm.x         SRC(%a0),&0x80          # load value
7128
7129fout_byte_norm:
7130        fmov.l          %d0,%fpcr               # insert rnd prec,mode
7131
7132        fmov.b          %fp0,%d0                # exec move out w/ correct rnd mode
7133
7134        fmov.l          &0x0,%fpcr              # clear FPCR
7135        fmov.l          %fpsr,%d1               # fetch FPSR
7136        or.w            %d1,2+USER_FPSR(%a6)    # save new exc,accrued bits
7137
7138        mov.b           1+EXC_OPWORD(%a6),%d1   # extract dst mode
7139        andi.b          &0x38,%d1               # is mode == 0? (Dreg dst)
7140        beq.b           fout_byte_dn            # must save to integer regfile
7141
7142        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
7143        bsr.l           _dmem_write_byte        # write byte
7144
7145        tst.l           %d1                     # did dstore fail?
7146        bne.l           facc_out_b              # yes
7147
7148        rts
7149
7150fout_byte_dn:
7151        mov.b           1+EXC_OPWORD(%a6),%d1   # extract Dn
7152        andi.w          &0x7,%d1
7153        bsr.l           store_dreg_b
7154        rts
7155
7156fout_byte_denorm:
7157        mov.l           SRC_EX(%a0),%d1
7158        andi.l          &0x80000000,%d1         # keep DENORM sign
7159        ori.l           &0x00800000,%d1         # make smallest sgl
7160        fmov.s          %d1,%fp0
7161        bra.b           fout_byte_norm
7162
7163#################################################################
7164# fmove.w out ###################################################
7165#################################################################
7166
7167# Only "Unimplemented Data Type" exceptions enter here. The operand
7168# is either a DENORM or a NORM.
7169fout_word:
7170        tst.b           STAG(%a6)               # is operand normalized?
7171        bne.b           fout_word_denorm        # no
7172
7173        fmovm.x         SRC(%a0),&0x80          # load value
7174
7175fout_word_norm:
7176        fmov.l          %d0,%fpcr               # insert rnd prec:mode
7177
7178        fmov.w          %fp0,%d0                # exec move out w/ correct rnd mode
7179
7180        fmov.l          &0x0,%fpcr              # clear FPCR
7181        fmov.l          %fpsr,%d1               # fetch FPSR
7182        or.w            %d1,2+USER_FPSR(%a6)    # save new exc,accrued bits
7183
7184        mov.b           1+EXC_OPWORD(%a6),%d1   # extract dst mode
7185        andi.b          &0x38,%d1               # is mode == 0? (Dreg dst)
7186        beq.b           fout_word_dn            # must save to integer regfile
7187
7188        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
7189        bsr.l           _dmem_write_word        # write word
7190
7191        tst.l           %d1                     # did dstore fail?
7192        bne.l           facc_out_w              # yes
7193
7194        rts
7195
7196fout_word_dn:
7197        mov.b           1+EXC_OPWORD(%a6),%d1   # extract Dn
7198        andi.w          &0x7,%d1
7199        bsr.l           store_dreg_w
7200        rts
7201
7202fout_word_denorm:
7203        mov.l           SRC_EX(%a0),%d1
7204        andi.l          &0x80000000,%d1         # keep DENORM sign
7205        ori.l           &0x00800000,%d1         # make smallest sgl
7206        fmov.s          %d1,%fp0
7207        bra.b           fout_word_norm
7208
7209#################################################################
7210# fmove.l out ###################################################
7211#################################################################
7212
7213# Only "Unimplemented Data Type" exceptions enter here. The operand
7214# is either a DENORM or a NORM.
7215fout_long:
7216        tst.b           STAG(%a6)               # is operand normalized?
7217        bne.b           fout_long_denorm        # no
7218
7219        fmovm.x         SRC(%a0),&0x80          # load value
7220
7221fout_long_norm:
7222        fmov.l          %d0,%fpcr               # insert rnd prec:mode
7223
7224        fmov.l          %fp0,%d0                # exec move out w/ correct rnd mode
7225
7226        fmov.l          &0x0,%fpcr              # clear FPCR
7227        fmov.l          %fpsr,%d1               # fetch FPSR
7228        or.w            %d1,2+USER_FPSR(%a6)    # save new exc,accrued bits
7229
7230fout_long_write:
7231        mov.b           1+EXC_OPWORD(%a6),%d1   # extract dst mode
7232        andi.b          &0x38,%d1               # is mode == 0? (Dreg dst)
7233        beq.b           fout_long_dn            # must save to integer regfile
7234
7235        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
7236        bsr.l           _dmem_write_long        # write long
7237
7238        tst.l           %d1                     # did dstore fail?
7239        bne.l           facc_out_l              # yes
7240
7241        rts
7242
7243fout_long_dn:
7244        mov.b           1+EXC_OPWORD(%a6),%d1   # extract Dn
7245        andi.w          &0x7,%d1
7246        bsr.l           store_dreg_l
7247        rts
7248
7249fout_long_denorm:
7250        mov.l           SRC_EX(%a0),%d1
7251        andi.l          &0x80000000,%d1         # keep DENORM sign
7252        ori.l           &0x00800000,%d1         # make smallest sgl
7253        fmov.s          %d1,%fp0
7254        bra.b           fout_long_norm
7255
7256#################################################################
7257# fmove.x out ###################################################
7258#################################################################
7259
7260# Only "Unimplemented Data Type" exceptions enter here. The operand
7261# is either a DENORM or a NORM.
7262# The DENORM causes an Underflow exception.
7263fout_ext:
7264
7265# we copy the extended precision result to FP_SCR0 so that the reserved
7266# 16-bit field gets zeroed. we do this since we promise not to disturb
7267# what's at SRC(a0).
7268        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
7269        clr.w           2+FP_SCR0_EX(%a6)       # clear reserved field
7270        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
7271        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
7272
7273        fmovm.x         SRC(%a0),&0x80          # return result
7274
7275        bsr.l           _calc_ea_fout           # fix stacked <ea>
7276
7277        mov.l           %a0,%a1                 # pass: dst addr
7278        lea             FP_SCR0(%a6),%a0        # pass: src addr
7279        mov.l           &0xc,%d0                # pass: opsize is 12 bytes
7280
7281# we must not yet write the extended precision data to the stack
7282# in the pre-decrement case from supervisor mode or else we'll corrupt
7283# the stack frame. so, leave it in FP_SRC for now and deal with it later...
7284        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
7285        beq.b           fout_ext_a7
7286
7287        bsr.l           _dmem_write             # write ext prec number to memory
7288
7289        tst.l           %d1                     # did dstore fail?
7290        bne.w           fout_ext_err            # yes
7291
7292        tst.b           STAG(%a6)               # is operand normalized?
7293        bne.b           fout_ext_denorm         # no
7294        rts
7295
7296# the number is a DENORM. must set the underflow exception bit
7297fout_ext_denorm:
7298        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set underflow exc bit
7299
7300        mov.b           FPCR_ENABLE(%a6),%d0
7301        andi.b          &0x0a,%d0               # is UNFL or INEX enabled?
7302        bne.b           fout_ext_exc            # yes
7303        rts
7304
7305# we don't want to do the write if the exception occurred in supervisor mode
7306# so _mem_write2() handles this for us.
7307fout_ext_a7:
7308        bsr.l           _mem_write2             # write ext prec number to memory
7309
7310        tst.l           %d1                     # did dstore fail?
7311        bne.w           fout_ext_err            # yes
7312
7313        tst.b           STAG(%a6)               # is operand normalized?
7314        bne.b           fout_ext_denorm         # no
7315        rts
7316
7317fout_ext_exc:
7318        lea             FP_SCR0(%a6),%a0
7319        bsr.l           norm                    # normalize the mantissa
7320        neg.w           %d0                     # new exp = -(shft amt)
7321        andi.w          &0x7fff,%d0
7322        andi.w          &0x8000,FP_SCR0_EX(%a6) # keep only old sign
7323        or.w            %d0,FP_SCR0_EX(%a6)     # insert new exponent
7324        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
7325        rts
7326
7327fout_ext_err:
7328        mov.l           EXC_A6(%a6),(%a6)       # fix stacked a6
7329        bra.l           facc_out_x
7330
7331#########################################################################
7332# fmove.s out ###########################################################
7333#########################################################################
7334fout_sgl:
7335        andi.b          &0x30,%d0               # clear rnd prec
7336        ori.b           &s_mode*0x10,%d0        # insert sgl prec
7337        mov.l           %d0,L_SCR3(%a6)         # save rnd prec,mode on stack
7338
7339#
7340# operand is a normalized number. first, we check to see if the move out
7341# would cause either an underflow or overflow. these cases are handled
7342# separately. otherwise, set the FPCR to the proper rounding mode and
7343# execute the move.
7344#
7345        mov.w           SRC_EX(%a0),%d0         # extract exponent
7346        andi.w          &0x7fff,%d0             # strip sign
7347
7348        cmpi.w          %d0,&SGL_HI             # will operand overflow?
7349        bgt.w           fout_sgl_ovfl           # yes; go handle OVFL
7350        beq.w           fout_sgl_may_ovfl       # maybe; go handle possible OVFL
7351        cmpi.w          %d0,&SGL_LO             # will operand underflow?
7352        blt.w           fout_sgl_unfl           # yes; go handle underflow
7353
7354#
7355# NORMs(in range) can be stored out by a simple "fmov.s"
7356# Unnormalized inputs can come through this point.
7357#
7358fout_sgl_exg:
7359        fmovm.x         SRC(%a0),&0x80          # fetch fop from stack
7360
7361        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
7362        fmov.l          &0x0,%fpsr              # clear FPSR
7363
7364        fmov.s          %fp0,%d0                # store does convert and round
7365
7366        fmov.l          &0x0,%fpcr              # clear FPCR
7367        fmov.l          %fpsr,%d1               # save FPSR
7368
7369        or.w            %d1,2+USER_FPSR(%a6)    # set possible inex2/ainex
7370
7371fout_sgl_exg_write:
7372        mov.b           1+EXC_OPWORD(%a6),%d1   # extract dst mode
7373        andi.b          &0x38,%d1               # is mode == 0? (Dreg dst)
7374        beq.b           fout_sgl_exg_write_dn   # must save to integer regfile
7375
7376        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
7377        bsr.l           _dmem_write_long        # write long
7378
7379        tst.l           %d1                     # did dstore fail?
7380        bne.l           facc_out_l              # yes
7381
7382        rts
7383
7384fout_sgl_exg_write_dn:
7385        mov.b           1+EXC_OPWORD(%a6),%d1   # extract Dn
7386        andi.w          &0x7,%d1
7387        bsr.l           store_dreg_l
7388        rts
7389
7390#
7391# here, we know that the operand would UNFL if moved out to single prec,
7392# so, denorm and round and then use generic store single routine to
7393# write the value to memory.
7394#
7395fout_sgl_unfl:
7396        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set UNFL
7397
7398        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
7399        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
7400        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
7401        mov.l           %a0,-(%sp)
7402
7403        clr.l           %d0                     # pass: S.F. = 0
7404
7405        cmpi.b          STAG(%a6),&DENORM       # fetch src optype tag
7406        bne.b           fout_sgl_unfl_cont      # let DENORMs fall through
7407
7408        lea             FP_SCR0(%a6),%a0
7409        bsr.l           norm                    # normalize the DENORM
7410
7411fout_sgl_unfl_cont:
7412        lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
7413        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
7414        bsr.l           unf_res                 # calc default underflow result
7415
7416        lea             FP_SCR0(%a6),%a0        # pass: ptr to fop
7417        bsr.l           dst_sgl                 # convert to single prec
7418
7419        mov.b           1+EXC_OPWORD(%a6),%d1   # extract dst mode
7420        andi.b          &0x38,%d1               # is mode == 0? (Dreg dst)
7421        beq.b           fout_sgl_unfl_dn        # must save to integer regfile
7422
7423        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
7424        bsr.l           _dmem_write_long        # write long
7425
7426        tst.l           %d1                     # did dstore fail?
7427        bne.l           facc_out_l              # yes
7428
7429        bra.b           fout_sgl_unfl_chkexc
7430
7431fout_sgl_unfl_dn:
7432        mov.b           1+EXC_OPWORD(%a6),%d1   # extract Dn
7433        andi.w          &0x7,%d1
7434        bsr.l           store_dreg_l
7435
7436fout_sgl_unfl_chkexc:
7437        mov.b           FPCR_ENABLE(%a6),%d1
7438        andi.b          &0x0a,%d1               # is UNFL or INEX enabled?
7439        bne.w           fout_sd_exc_unfl        # yes
7440        addq.l          &0x4,%sp
7441        rts
7442
7443#
7444# it's definitely an overflow so call ovf_res to get the correct answer
7445#
7446fout_sgl_ovfl:
7447        tst.b           3+SRC_HI(%a0)           # is result inexact?
7448        bne.b           fout_sgl_ovfl_inex2
7449        tst.l           SRC_LO(%a0)             # is result inexact?
7450        bne.b           fout_sgl_ovfl_inex2
7451        ori.w           &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex
7452        bra.b           fout_sgl_ovfl_cont
7453fout_sgl_ovfl_inex2:
7454        ori.w           &ovfinx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex/inex2
7455
7456fout_sgl_ovfl_cont:
7457        mov.l           %a0,-(%sp)
7458
7459# call ovf_res() w/ sgl prec and the correct rnd mode to create the default
7460# overflow result. DON'T save the returned ccodes from ovf_res() since
7461# fmove out doesn't alter them.
7462        tst.b           SRC_EX(%a0)             # is operand negative?
7463        smi             %d1                     # set if so
7464        mov.l           L_SCR3(%a6),%d0         # pass: sgl prec,rnd mode
7465        bsr.l           ovf_res                 # calc OVFL result
7466        fmovm.x         (%a0),&0x80             # load default overflow result
7467        fmov.s          %fp0,%d0                # store to single
7468
7469        mov.b           1+EXC_OPWORD(%a6),%d1   # extract dst mode
7470        andi.b          &0x38,%d1               # is mode == 0? (Dreg dst)
7471        beq.b           fout_sgl_ovfl_dn        # must save to integer regfile
7472
7473        mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
7474        bsr.l           _dmem_write_long        # write long
7475
7476        tst.l           %d1                     # did dstore fail?
7477        bne.l           facc_out_l              # yes
7478
7479        bra.b           fout_sgl_ovfl_chkexc
7480
7481fout_sgl_ovfl_dn:
7482        mov.b           1+EXC_OPWORD(%a6),%d1   # extract Dn
7483        andi.w          &0x7,%d1
7484        bsr.l           store_dreg_l
7485
7486fout_sgl_ovfl_chkexc:
7487        mov.b           FPCR_ENABLE(%a6),%d1
7488        andi.b          &0x0a,%d1               # is UNFL or INEX enabled?
7489        bne.w           fout_sd_exc_ovfl        # yes
7490        addq.l          &0x4,%sp
7491        rts
7492
7493#
7494# move out MAY overflow:
7495# (1) force the exp to 0x3fff
7496# (2) do a move w/ appropriate rnd mode
7497# (3) if exp still equals zero, then insert original exponent
7498#       for the correct result.
7499#     if exp now equals one, then it overflowed so call ovf_res.
7500#
7501fout_sgl_may_ovfl:
7502        mov.w           SRC_EX(%a0),%d1         # fetch current sign
7503        andi.w          &0x8000,%d1             # keep it,clear exp
7504        ori.w           &0x3fff,%d1             # insert exp = 0
7505        mov.w           %d1,FP_SCR0_EX(%a6)     # insert scaled exp
7506        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6) # copy hi(man)
7507        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6) # copy lo(man)
7508
7509        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
7510
7511        fmov.x          FP_SCR0(%a6),%fp0       # force fop to be rounded
7512        fmov.l          &0x0,%fpcr              # clear FPCR
7513
7514        fabs.x          %fp0                    # need absolute value
7515        fcmp.b          %fp0,&0x2               # did exponent increase?
7516        fblt.w          fout_sgl_exg            # no; go finish NORM
7517        bra.w           fout_sgl_ovfl           # yes; go handle overflow
7518
7519################
7520
7521fout_sd_exc_unfl:
7522        mov.l           (%sp)+,%a0
7523
7524        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
7525        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
7526        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
7527
7528        cmpi.b          STAG(%a6),&DENORM       # was src a DENORM?
7529        bne.b           fout_sd_exc_cont        # no
7530
7531        lea             FP_SCR0(%a6),%a0
7532        bsr.l           norm
7533        neg.l           %d0
7534        andi.w          &0x7fff,%d0
7535        bfins           %d0,FP_SCR0_EX(%a6){&1:&15}
7536        bra.b           fout_sd_exc_cont
7537
7538fout_sd_exc:
7539fout_sd_exc_ovfl:
7540        mov.l           (%sp)+,%a0              # restore a0
7541
7542        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
7543        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
7544        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
7545
7546fout_sd_exc_cont:
7547        bclr            &0x7,FP_SCR0_EX(%a6)    # clear sign bit
7548        sne.b           2+FP_SCR0_EX(%a6)       # set internal sign bit
7549        lea             FP_SCR0(%a6),%a0        # pass: ptr to DENORM
7550
7551        mov.b           3+L_SCR3(%a6),%d1
7552        lsr.b           &0x4,%d1
7553        andi.w          &0x0c,%d1
7554        swap            %d1
7555        mov.b           3+L_SCR3(%a6),%d1
7556        lsr.b           &0x4,%d1
7557        andi.w          &0x03,%d1
7558        clr.l           %d0                     # pass: zero g,r,s
7559        bsr.l           _round                  # round the DENORM
7560
7561        tst.b           2+FP_SCR0_EX(%a6)       # is EXOP negative?
7562        beq.b           fout_sd_exc_done        # no
7563        bset            &0x7,FP_SCR0_EX(%a6)    # yes
7564
7565fout_sd_exc_done:
7566        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
7567        rts
7568
7569#################################################################
7570# fmove.d out ###################################################
7571#################################################################
7572fout_dbl:
7573        andi.b          &0x30,%d0               # clear rnd prec
7574        ori.b           &d_mode*0x10,%d0        # insert dbl prec
7575        mov.l           %d0,L_SCR3(%a6)         # save rnd prec,mode on stack
7576
7577#
7578# operand is a normalized number. first, we check to see if the move out
7579# would cause either an underflow or overflow. these cases are handled
7580# separately. otherwise, set the FPCR to the proper rounding mode and
7581# execute the move.
7582#
7583        mov.w           SRC_EX(%a0),%d0         # extract exponent
7584        andi.w          &0x7fff,%d0             # strip sign
7585
7586        cmpi.w          %d0,&DBL_HI             # will operand overflow?
7587        bgt.w           fout_dbl_ovfl           # yes; go handle OVFL
7588        beq.w           fout_dbl_may_ovfl       # maybe; go handle possible OVFL
7589        cmpi.w          %d0,&DBL_LO             # will operand underflow?
7590        blt.w           fout_dbl_unfl           # yes; go handle underflow
7591
7592#
7593# NORMs(in range) can be stored out by a simple "fmov.d"
7594# Unnormalized inputs can come through this point.
7595#
7596fout_dbl_exg:
7597        fmovm.x         SRC(%a0),&0x80          # fetch fop from stack
7598
7599        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
7600        fmov.l          &0x0,%fpsr              # clear FPSR
7601
7602        fmov.d          %fp0,L_SCR1(%a6)        # store does convert and round
7603
7604        fmov.l          &0x0,%fpcr              # clear FPCR
7605        fmov.l          %fpsr,%d0               # save FPSR
7606
7607        or.w            %d0,2+USER_FPSR(%a6)    # set possible inex2/ainex
7608
7609        mov.l           EXC_EA(%a6),%a1         # pass: dst addr
7610        lea             L_SCR1(%a6),%a0         # pass: src addr
7611        movq.l          &0x8,%d0                # pass: opsize is 8 bytes
7612        bsr.l           _dmem_write             # store dbl fop to memory
7613
7614        tst.l           %d1                     # did dstore fail?
7615        bne.l           facc_out_d              # yes
7616
7617        rts                                     # no; so we're finished
7618
7619#
7620# here, we know that the operand would UNFL if moved out to double prec,
7621# so, denorm and round and then use generic store double routine to
7622# write the value to memory.
7623#
7624fout_dbl_unfl:
7625        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set UNFL
7626
7627        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
7628        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
7629        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
7630        mov.l           %a0,-(%sp)
7631
7632        clr.l           %d0                     # pass: S.F. = 0
7633
7634        cmpi.b          STAG(%a6),&DENORM       # fetch src optype tag
7635        bne.b           fout_dbl_unfl_cont      # let DENORMs fall through
7636
7637        lea             FP_SCR0(%a6),%a0
7638        bsr.l           norm                    # normalize the DENORM
7639
7640fout_dbl_unfl_cont:
7641        lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
7642        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
7643        bsr.l           unf_res                 # calc default underflow result
7644
7645        lea             FP_SCR0(%a6),%a0        # pass: ptr to fop
7646        bsr.l           dst_dbl                 # convert to single prec
7647        mov.l           %d0,L_SCR1(%a6)
7648        mov.l           %d1,L_SCR2(%a6)
7649
7650        mov.l           EXC_EA(%a6),%a1         # pass: dst addr
7651        lea             L_SCR1(%a6),%a0         # pass: src addr
7652        movq.l          &0x8,%d0                # pass: opsize is 8 bytes
7653        bsr.l           _dmem_write             # store dbl fop to memory
7654
7655        tst.l           %d1                     # did dstore fail?
7656        bne.l           facc_out_d              # yes
7657
7658        mov.b           FPCR_ENABLE(%a6),%d1
7659        andi.b          &0x0a,%d1               # is UNFL or INEX enabled?
7660        bne.w           fout_sd_exc_unfl        # yes
7661        addq.l          &0x4,%sp
7662        rts
7663
7664#
7665# it's definitely an overflow so call ovf_res to get the correct answer
7666#
7667fout_dbl_ovfl:
7668        mov.w           2+SRC_LO(%a0),%d0
7669        andi.w          &0x7ff,%d0
7670        bne.b           fout_dbl_ovfl_inex2
7671
7672        ori.w           &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex
7673        bra.b           fout_dbl_ovfl_cont
7674fout_dbl_ovfl_inex2:
7675        ori.w           &ovfinx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex/inex2
7676
7677fout_dbl_ovfl_cont:
7678        mov.l           %a0,-(%sp)
7679
7680# call ovf_res() w/ dbl prec and the correct rnd mode to create the default
7681# overflow result. DON'T save the returned ccodes from ovf_res() since
7682# fmove out doesn't alter them.
7683        tst.b           SRC_EX(%a0)             # is operand negative?
7684        smi             %d1                     # set if so
7685        mov.l           L_SCR3(%a6),%d0         # pass: dbl prec,rnd mode
7686        bsr.l           ovf_res                 # calc OVFL result
7687        fmovm.x         (%a0),&0x80             # load default overflow result
7688        fmov.d          %fp0,L_SCR1(%a6)        # store to double
7689
7690        mov.l           EXC_EA(%a6),%a1         # pass: dst addr
7691        lea             L_SCR1(%a6),%a0         # pass: src addr
7692        movq.l          &0x8,%d0                # pass: opsize is 8 bytes
7693        bsr.l           _dmem_write             # store dbl fop to memory
7694
7695        tst.l           %d1                     # did dstore fail?
7696        bne.l           facc_out_d              # yes
7697
7698        mov.b           FPCR_ENABLE(%a6),%d1
7699        andi.b          &0x0a,%d1               # is UNFL or INEX enabled?
7700        bne.w           fout_sd_exc_ovfl        # yes
7701        addq.l          &0x4,%sp
7702        rts
7703
7704#
7705# move out MAY overflow:
7706# (1) force the exp to 0x3fff
7707# (2) do a move w/ appropriate rnd mode
7708# (3) if exp still equals zero, then insert original exponent
7709#       for the correct result.
7710#     if exp now equals one, then it overflowed so call ovf_res.
7711#
7712fout_dbl_may_ovfl:
7713        mov.w           SRC_EX(%a0),%d1         # fetch current sign
7714        andi.w          &0x8000,%d1             # keep it,clear exp
7715        ori.w           &0x3fff,%d1             # insert exp = 0
7716        mov.w           %d1,FP_SCR0_EX(%a6)     # insert scaled exp
7717        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6) # copy hi(man)
7718        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6) # copy lo(man)
7719
7720        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
7721
7722        fmov.x          FP_SCR0(%a6),%fp0       # force fop to be rounded
7723        fmov.l          &0x0,%fpcr              # clear FPCR
7724
7725        fabs.x          %fp0                    # need absolute value
7726        fcmp.b          %fp0,&0x2               # did exponent increase?
7727        fblt.w          fout_dbl_exg            # no; go finish NORM
7728        bra.w           fout_dbl_ovfl           # yes; go handle overflow
7729
7730#########################################################################
7731# XDEF **************************************************************** #
7732#       dst_dbl(): create double precision value from extended prec.    #
7733#                                                                       #
7734# XREF **************************************************************** #
7735#       None                                                            #
7736#                                                                       #
7737# INPUT *************************************************************** #
7738#       a0 = pointer to source operand in extended precision            #
7739#                                                                       #
7740# OUTPUT ************************************************************** #
7741#       d0 = hi(double precision result)                                #
7742#       d1 = lo(double precision result)                                #
7743#                                                                       #
7744# ALGORITHM *********************************************************** #
7745#                                                                       #
7746#  Changes extended precision to double precision.                      #
7747#  Note: no attempt is made to round the extended value to double.      #
7748#       dbl_sign = ext_sign                                             #
7749#       dbl_exp = ext_exp - $3fff(ext bias) + $7ff(dbl bias)            #
7750#       get rid of ext integer bit                                      #
7751#       dbl_mant = ext_mant{62:12}                                      #
7752#                                                                       #
7753#               ---------------   ---------------    ---------------    #
7754#  extended ->  |s|    exp    |   |1| ms mant   |    | ls mant     |    #
7755#               ---------------   ---------------    ---------------    #
7756#                95         64    63 62       32      31     11   0     #
7757#                                    |                       |          #
7758#                                    |                       |          #
7759#                                    |                       |          #
7760#                                    v                       v          #
7761#                             ---------------   ---------------         #
7762#  double   ->                |s|exp| mant  |   |  mant       |         #
7763#                             ---------------   ---------------         #
7764#                             63     51   32   31              0        #
7765#                                                                       #
7766#########################################################################
7767
7768dst_dbl:
7769        clr.l           %d0                     # clear d0
7770        mov.w           FTEMP_EX(%a0),%d0       # get exponent
7771        subi.w          &EXT_BIAS,%d0           # subtract extended precision bias
7772        addi.w          &DBL_BIAS,%d0           # add double precision bias
7773        tst.b           FTEMP_HI(%a0)           # is number a denorm?
7774        bmi.b           dst_get_dupper          # no
7775        subq.w          &0x1,%d0                # yes; denorm bias = DBL_BIAS - 1
7776dst_get_dupper:
7777        swap            %d0                     # d0 now in upper word
7778        lsl.l           &0x4,%d0                # d0 in proper place for dbl prec exp
7779        tst.b           FTEMP_EX(%a0)           # test sign
7780        bpl.b           dst_get_dman            # if positive, go process mantissa
7781        bset            &0x1f,%d0               # if negative, set sign
7782dst_get_dman:
7783        mov.l           FTEMP_HI(%a0),%d1       # get ms mantissa
7784        bfextu          %d1{&1:&20},%d1         # get upper 20 bits of ms
7785        or.l            %d1,%d0                 # put these bits in ms word of double
7786        mov.l           %d0,L_SCR1(%a6)         # put the new exp back on the stack
7787        mov.l           FTEMP_HI(%a0),%d1       # get ms mantissa
7788        mov.l           &21,%d0                 # load shift count
7789        lsl.l           %d0,%d1                 # put lower 11 bits in upper bits
7790        mov.l           %d1,L_SCR2(%a6)         # build lower lword in memory
7791        mov.l           FTEMP_LO(%a0),%d1       # get ls mantissa
7792        bfextu          %d1{&0:&21},%d0         # get ls 21 bits of double
7793        mov.l           L_SCR2(%a6),%d1
7794        or.l            %d0,%d1                 # put them in double result
7795        mov.l           L_SCR1(%a6),%d0
7796        rts
7797
7798#########################################################################
7799# XDEF **************************************************************** #
7800#       dst_sgl(): create single precision value from extended prec     #
7801#                                                                       #
7802# XREF **************************************************************** #
7803#                                                                       #
7804# INPUT *************************************************************** #
7805#       a0 = pointer to source operand in extended precision            #
7806#                                                                       #
7807# OUTPUT ************************************************************** #
7808#       d0 = single precision result                                    #
7809#                                                                       #
7810# ALGORITHM *********************************************************** #
7811#                                                                       #
7812# Changes extended precision to single precision.                       #
7813#       sgl_sign = ext_sign                                             #
7814#       sgl_exp = ext_exp - $3fff(ext bias) + $7f(sgl bias)             #
7815#       get rid of ext integer bit                                      #
7816#       sgl_mant = ext_mant{62:12}                                      #
7817#                                                                       #
7818#               ---------------   ---------------    ---------------    #
7819#  extended ->  |s|    exp    |   |1| ms mant   |    | ls mant     |    #
7820#               ---------------   ---------------    ---------------    #
7821#                95         64    63 62    40 32      31     12   0     #
7822#                                    |     |                            #
7823#                                    |     |                            #
7824#                                    |     |                            #
7825#                                    v     v                            #
7826#                             ---------------                           #
7827#  single   ->                |s|exp| mant  |                           #
7828#                             ---------------                           #
7829#                             31     22     0                           #
7830#                                                                       #
7831#########################################################################
7832
7833dst_sgl:
7834        clr.l           %d0
7835        mov.w           FTEMP_EX(%a0),%d0       # get exponent
7836        subi.w          &EXT_BIAS,%d0           # subtract extended precision bias
7837        addi.w          &SGL_BIAS,%d0           # add single precision bias
7838        tst.b           FTEMP_HI(%a0)           # is number a denorm?
7839        bmi.b           dst_get_supper          # no
7840        subq.w          &0x1,%d0                # yes; denorm bias = SGL_BIAS - 1
7841dst_get_supper:
7842        swap            %d0                     # put exp in upper word of d0
7843        lsl.l           &0x7,%d0                # shift it into single exp bits
7844        tst.b           FTEMP_EX(%a0)           # test sign
7845        bpl.b           dst_get_sman            # if positive, continue
7846        bset            &0x1f,%d0               # if negative, put in sign first
7847dst_get_sman:
7848        mov.l           FTEMP_HI(%a0),%d1       # get ms mantissa
7849        andi.l          &0x7fffff00,%d1         # get upper 23 bits of ms
7850        lsr.l           &0x8,%d1                # and put them flush right
7851        or.l            %d1,%d0                 # put these bits in ms word of single
7852        rts
7853
7854##############################################################################
7855fout_pack:
7856        bsr.l           _calc_ea_fout           # fetch the <ea>
7857        mov.l           %a0,-(%sp)
7858
7859        mov.b           STAG(%a6),%d0           # fetch input type
7860        bne.w           fout_pack_not_norm      # input is not NORM
7861
7862fout_pack_norm:
7863        btst            &0x4,EXC_CMDREG(%a6)    # static or dynamic?
7864        beq.b           fout_pack_s             # static
7865
7866fout_pack_d:
7867        mov.b           1+EXC_CMDREG(%a6),%d1   # fetch dynamic reg
7868        lsr.b           &0x4,%d1
7869        andi.w          &0x7,%d1
7870
7871        bsr.l           fetch_dreg              # fetch Dn w/ k-factor
7872
7873        bra.b           fout_pack_type
7874fout_pack_s:
7875        mov.b           1+EXC_CMDREG(%a6),%d0   # fetch static field
7876
7877fout_pack_type:
7878        bfexts          %d0{&25:&7},%d0         # extract k-factor
7879        mov.l   %d0,-(%sp)
7880
7881        lea             FP_SRC(%a6),%a0         # pass: ptr to input
7882
7883# bindec is currently scrambling FP_SRC for denorm inputs.
7884# we'll have to change this, but for now, tough luck!!!
7885        bsr.l           bindec                  # convert xprec to packed
7886
7887#       andi.l          &0xcfff000f,FP_SCR0(%a6) # clear unused fields
7888        andi.l          &0xcffff00f,FP_SCR0(%a6) # clear unused fields
7889
7890        mov.l   (%sp)+,%d0
7891
7892        tst.b           3+FP_SCR0_EX(%a6)
7893        bne.b           fout_pack_set
7894        tst.l           FP_SCR0_HI(%a6)
7895        bne.b           fout_pack_set
7896        tst.l           FP_SCR0_LO(%a6)
7897        bne.b           fout_pack_set
7898
7899# add the extra condition that only if the k-factor was zero, too, should
7900# we zero the exponent
7901        tst.l           %d0
7902        bne.b           fout_pack_set
7903# "mantissa" is all zero which means that the answer is zero. but, the '040
7904# algorithm allows the exponent to be non-zero. the 881/2 do not. Therefore,
7905# if the mantissa is zero, I will zero the exponent, too.
7906# the question now is whether the exponents sign bit is allowed to be non-zero
7907# for a zero, also...
7908        andi.w          &0xf000,FP_SCR0(%a6)
7909
7910fout_pack_set:
7911
7912        lea             FP_SCR0(%a6),%a0        # pass: src addr
7913
7914fout_pack_write:
7915        mov.l           (%sp)+,%a1              # pass: dst addr
7916        mov.l           &0xc,%d0                # pass: opsize is 12 bytes
7917
7918        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
7919        beq.b           fout_pack_a7
7920
7921        bsr.l           _dmem_write             # write ext prec number to memory
7922
7923        tst.l           %d1                     # did dstore fail?
7924        bne.w           fout_ext_err            # yes
7925
7926        rts
7927
7928# we don't want to do the write if the exception occurred in supervisor mode
7929# so _mem_write2() handles this for us.
7930fout_pack_a7:
7931        bsr.l           _mem_write2             # write ext prec number to memory
7932
7933        tst.l           %d1                     # did dstore fail?
7934        bne.w           fout_ext_err            # yes
7935
7936        rts
7937
7938fout_pack_not_norm:
7939        cmpi.b          %d0,&DENORM             # is it a DENORM?
7940        beq.w           fout_pack_norm          # yes
7941        lea             FP_SRC(%a6),%a0
7942        clr.w           2+FP_SRC_EX(%a6)
7943        cmpi.b          %d0,&SNAN               # is it an SNAN?
7944        beq.b           fout_pack_snan          # yes
7945        bra.b           fout_pack_write         # no
7946
7947fout_pack_snan:
7948        ori.w           &snaniop2_mask,FPSR_EXCEPT(%a6) # set SNAN/AIOP
7949        bset            &0x6,FP_SRC_HI(%a6)     # set snan bit
7950        bra.b           fout_pack_write
7951
7952#########################################################################
7953# XDEF **************************************************************** #
7954#       fmul(): emulates the fmul instruction                           #
7955#       fsmul(): emulates the fsmul instruction                         #
7956#       fdmul(): emulates the fdmul instruction                         #
7957#                                                                       #
7958# XREF **************************************************************** #
7959#       scale_to_zero_src() - scale src exponent to zero                #
7960#       scale_to_zero_dst() - scale dst exponent to zero                #
7961#       unf_res() - return default underflow result                     #
7962#       ovf_res() - return default overflow result                      #
7963#       res_qnan() - return QNAN result                                 #
7964#       res_snan() - return SNAN result                                 #
7965#                                                                       #
7966# INPUT *************************************************************** #
7967#       a0 = pointer to extended precision source operand               #
7968#       a1 = pointer to extended precision destination operand          #
7969#       d0  rnd prec,mode                                               #
7970#                                                                       #
7971# OUTPUT ************************************************************** #
7972#       fp0 = result                                                    #
7973#       fp1 = EXOP (if exception occurred)                              #
7974#                                                                       #
7975# ALGORITHM *********************************************************** #
7976#       Handle NANs, infinities, and zeroes as special cases. Divide    #
7977# norms/denorms into ext/sgl/dbl precision.                             #
7978#       For norms/denorms, scale the exponents such that a multiply     #
7979# instruction won't cause an exception. Use the regular fmul to         #
7980# compute a result. Check if the regular operands would have taken      #
7981# an exception. If so, return the default overflow/underflow result     #
7982# and return the EXOP if exceptions are enabled. Else, scale the        #
7983# result operand to the proper exponent.                                #
7984#                                                                       #
7985#########################################################################
7986
7987        align           0x10
7988tbl_fmul_ovfl:
7989        long            0x3fff - 0x7ffe         # ext_max
7990        long            0x3fff - 0x407e         # sgl_max
7991        long            0x3fff - 0x43fe         # dbl_max
7992tbl_fmul_unfl:
7993        long            0x3fff + 0x0001         # ext_unfl
7994        long            0x3fff - 0x3f80         # sgl_unfl
7995        long            0x3fff - 0x3c00         # dbl_unfl
7996
7997        global          fsmul
7998fsmul:
7999        andi.b          &0x30,%d0               # clear rnd prec
8000        ori.b           &s_mode*0x10,%d0        # insert sgl prec
8001        bra.b           fmul
8002
8003        global          fdmul
8004fdmul:
8005        andi.b          &0x30,%d0
8006        ori.b           &d_mode*0x10,%d0        # insert dbl prec
8007
8008        global          fmul
8009fmul:
8010        mov.l           %d0,L_SCR3(%a6)         # store rnd info
8011
8012        clr.w           %d1
8013        mov.b           DTAG(%a6),%d1
8014        lsl.b           &0x3,%d1
8015        or.b            STAG(%a6),%d1           # combine src tags
8016        bne.w           fmul_not_norm           # optimize on non-norm input
8017
8018fmul_norm:
8019        mov.w           DST_EX(%a1),FP_SCR1_EX(%a6)
8020        mov.l           DST_HI(%a1),FP_SCR1_HI(%a6)
8021        mov.l           DST_LO(%a1),FP_SCR1_LO(%a6)
8022
8023        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
8024        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
8025        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
8026
8027        bsr.l           scale_to_zero_src       # scale src exponent
8028        mov.l           %d0,-(%sp)              # save scale factor 1
8029
8030        bsr.l           scale_to_zero_dst       # scale dst exponent
8031
8032        add.l           %d0,(%sp)               # SCALE_FACTOR = scale1 + scale2
8033
8034        mov.w           2+L_SCR3(%a6),%d1       # fetch precision
8035        lsr.b           &0x6,%d1                # shift to lo bits
8036        mov.l           (%sp)+,%d0              # load S.F.
8037        cmp.l           %d0,(tbl_fmul_ovfl.w,%pc,%d1.w*4) # would result ovfl?
8038        beq.w           fmul_may_ovfl           # result may rnd to overflow
8039        blt.w           fmul_ovfl               # result will overflow
8040
8041        cmp.l           %d0,(tbl_fmul_unfl.w,%pc,%d1.w*4) # would result unfl?
8042        beq.w           fmul_may_unfl           # result may rnd to no unfl
8043        bgt.w           fmul_unfl               # result will underflow
8044
8045#
8046# NORMAL:
8047# - the result of the multiply operation will neither overflow nor underflow.
8048# - do the multiply to the proper precision and rounding mode.
8049# - scale the result exponent using the scale factor. if both operands were
8050# normalized then we really don't need to go through this scaling. but for now,
8051# this will do.
8052#
8053fmul_normal:
8054        fmovm.x         FP_SCR1(%a6),&0x80      # load dst operand
8055
8056        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
8057        fmov.l          &0x0,%fpsr              # clear FPSR
8058
8059        fmul.x          FP_SCR0(%a6),%fp0       # execute multiply
8060
8061        fmov.l          %fpsr,%d1               # save status
8062        fmov.l          &0x0,%fpcr              # clear FPCR
8063
8064        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
8065
8066fmul_normal_exit:
8067        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
8068        mov.l           %d2,-(%sp)              # save d2
8069        mov.w           FP_SCR0_EX(%a6),%d1     # load {sgn,exp}
8070        mov.l           %d1,%d2                 # make a copy
8071        andi.l          &0x7fff,%d1             # strip sign
8072        andi.w          &0x8000,%d2             # keep old sign
8073        sub.l           %d0,%d1                 # add scale factor
8074        or.w            %d2,%d1                 # concat old sign,new exp
8075        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
8076        mov.l           (%sp)+,%d2              # restore d2
8077        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
8078        rts
8079
8080#
8081# OVERFLOW:
8082# - the result of the multiply operation is an overflow.
8083# - do the multiply to the proper precision and rounding mode in order to
8084# set the inexact bits.
8085# - calculate the default result and return it in fp0.
8086# - if overflow or inexact is enabled, we need a multiply result rounded to
8087# extended precision. if the original operation was extended, then we have this
8088# result. if the original operation was single or double, we have to do another
8089# multiply using extended precision and the correct rounding mode. the result
8090# of this operation then has its exponent scaled by -0x6000 to create the
8091# exceptional operand.
8092#
8093fmul_ovfl:
8094        fmovm.x         FP_SCR1(%a6),&0x80      # load dst operand
8095
8096        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
8097        fmov.l          &0x0,%fpsr              # clear FPSR
8098
8099        fmul.x          FP_SCR0(%a6),%fp0       # execute multiply
8100
8101        fmov.l          %fpsr,%d1               # save status
8102        fmov.l          &0x0,%fpcr              # clear FPCR
8103
8104        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
8105
8106# save setting this until now because this is where fmul_may_ovfl may jump in
8107fmul_ovfl_tst:
8108        or.l            &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
8109
8110        mov.b           FPCR_ENABLE(%a6),%d1
8111        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
8112        bne.b           fmul_ovfl_ena           # yes
8113
8114# calculate the default result
8115fmul_ovfl_dis:
8116        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
8117        sne             %d1                     # set sign param accordingly
8118        mov.l           L_SCR3(%a6),%d0         # pass rnd prec,mode
8119        bsr.l           ovf_res                 # calculate default result
8120        or.b            %d0,FPSR_CC(%a6)        # set INF,N if applicable
8121        fmovm.x         (%a0),&0x80             # return default result in fp0
8122        rts
8123
8124#
8125# OVFL is enabled; Create EXOP:
8126# - if precision is extended, then we have the EXOP. simply bias the exponent
8127# with an extra -0x6000. if the precision is single or double, we need to
8128# calculate a result rounded to extended precision.
8129#
8130fmul_ovfl_ena:
8131        mov.l           L_SCR3(%a6),%d1
8132        andi.b          &0xc0,%d1               # test the rnd prec
8133        bne.b           fmul_ovfl_ena_sd        # it's sgl or dbl
8134
8135fmul_ovfl_ena_cont:
8136        fmovm.x         &0x80,FP_SCR0(%a6)      # move result to stack
8137
8138        mov.l           %d2,-(%sp)              # save d2
8139        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
8140        mov.w           %d1,%d2                 # make a copy
8141        andi.l          &0x7fff,%d1             # strip sign
8142        sub.l           %d0,%d1                 # add scale factor
8143        subi.l          &0x6000,%d1             # subtract bias
8144        andi.w          &0x7fff,%d1             # clear sign bit
8145        andi.w          &0x8000,%d2             # keep old sign
8146        or.w            %d2,%d1                 # concat old sign,new exp
8147        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
8148        mov.l           (%sp)+,%d2              # restore d2
8149        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
8150        bra.b           fmul_ovfl_dis
8151
8152fmul_ovfl_ena_sd:
8153        fmovm.x         FP_SCR1(%a6),&0x80      # load dst operand
8154
8155        mov.l           L_SCR3(%a6),%d1
8156        andi.b          &0x30,%d1               # keep rnd mode only
8157        fmov.l          %d1,%fpcr               # set FPCR
8158
8159        fmul.x          FP_SCR0(%a6),%fp0       # execute multiply
8160
8161        fmov.l          &0x0,%fpcr              # clear FPCR
8162        bra.b           fmul_ovfl_ena_cont
8163
8164#
8165# may OVERFLOW:
8166# - the result of the multiply operation MAY overflow.
8167# - do the multiply to the proper precision and rounding mode in order to
8168# set the inexact bits.
8169# - calculate the default result and return it in fp0.
8170#
8171fmul_may_ovfl:
8172        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
8173
8174        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
8175        fmov.l          &0x0,%fpsr              # clear FPSR
8176
8177        fmul.x          FP_SCR0(%a6),%fp0       # execute multiply
8178
8179        fmov.l          %fpsr,%d1               # save status
8180        fmov.l          &0x0,%fpcr              # clear FPCR
8181
8182        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
8183
8184        fabs.x          %fp0,%fp1               # make a copy of result
8185        fcmp.b          %fp1,&0x2               # is |result| >= 2.b?
8186        fbge.w          fmul_ovfl_tst           # yes; overflow has occurred
8187
8188# no, it didn't overflow; we have correct result
8189        bra.w           fmul_normal_exit
8190
8191#
8192# UNDERFLOW:
8193# - the result of the multiply operation is an underflow.
8194# - do the multiply to the proper precision and rounding mode in order to
8195# set the inexact bits.
8196# - calculate the default result and return it in fp0.
8197# - if overflow or inexact is enabled, we need a multiply result rounded to
8198# extended precision. if the original operation was extended, then we have this
8199# result. if the original operation was single or double, we have to do another
8200# multiply using extended precision and the correct rounding mode. the result
8201# of this operation then has its exponent scaled by -0x6000 to create the
8202# exceptional operand.
8203#
8204fmul_unfl:
8205        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
8206
8207# for fun, let's use only extended precision, round to zero. then, let
8208# the unf_res() routine figure out all the rest.
8209# will we get the correct answer.
8210        fmovm.x         FP_SCR1(%a6),&0x80      # load dst operand
8211
8212        fmov.l          &rz_mode*0x10,%fpcr     # set FPCR
8213        fmov.l          &0x0,%fpsr              # clear FPSR
8214
8215        fmul.x          FP_SCR0(%a6),%fp0       # execute multiply
8216
8217        fmov.l          %fpsr,%d1               # save status
8218        fmov.l          &0x0,%fpcr              # clear FPCR
8219
8220        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
8221
8222        mov.b           FPCR_ENABLE(%a6),%d1
8223        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
8224        bne.b           fmul_unfl_ena           # yes
8225
8226fmul_unfl_dis:
8227        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
8228
8229        lea             FP_SCR0(%a6),%a0        # pass: result addr
8230        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
8231        bsr.l           unf_res                 # calculate default result
8232        or.b            %d0,FPSR_CC(%a6)        # unf_res2 may have set 'Z'
8233        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
8234        rts
8235
8236#
8237# UNFL is enabled.
8238#
8239fmul_unfl_ena:
8240        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op
8241
8242        mov.l           L_SCR3(%a6),%d1
8243        andi.b          &0xc0,%d1               # is precision extended?
8244        bne.b           fmul_unfl_ena_sd        # no, sgl or dbl
8245
8246# if the rnd mode is anything but RZ, then we have to re-do the above
8247# multiplication because we used RZ for all.
8248        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
8249
8250fmul_unfl_ena_cont:
8251        fmov.l          &0x0,%fpsr              # clear FPSR
8252
8253        fmul.x          FP_SCR0(%a6),%fp1       # execute multiply
8254
8255        fmov.l          &0x0,%fpcr              # clear FPCR
8256
8257        fmovm.x         &0x40,FP_SCR0(%a6)      # save result to stack
8258        mov.l           %d2,-(%sp)              # save d2
8259        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
8260        mov.l           %d1,%d2                 # make a copy
8261        andi.l          &0x7fff,%d1             # strip sign
8262        andi.w          &0x8000,%d2             # keep old sign
8263        sub.l           %d0,%d1                 # add scale factor
8264        addi.l          &0x6000,%d1             # add bias
8265        andi.w          &0x7fff,%d1
8266        or.w            %d2,%d1                 # concat old sign,new exp
8267        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
8268        mov.l           (%sp)+,%d2              # restore d2
8269        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
8270        bra.w           fmul_unfl_dis
8271
8272fmul_unfl_ena_sd:
8273        mov.l           L_SCR3(%a6),%d1
8274        andi.b          &0x30,%d1               # use only rnd mode
8275        fmov.l          %d1,%fpcr               # set FPCR
8276
8277        bra.b           fmul_unfl_ena_cont
8278
8279# MAY UNDERFLOW:
8280# -use the correct rounding mode and precision. this code favors operations
8281# that do not underflow.
8282fmul_may_unfl:
8283        fmovm.x         FP_SCR1(%a6),&0x80      # load dst operand
8284
8285        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
8286        fmov.l          &0x0,%fpsr              # clear FPSR
8287
8288        fmul.x          FP_SCR0(%a6),%fp0       # execute multiply
8289
8290        fmov.l          %fpsr,%d1               # save status
8291        fmov.l          &0x0,%fpcr              # clear FPCR
8292
8293        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
8294
8295        fabs.x          %fp0,%fp1               # make a copy of result
8296        fcmp.b          %fp1,&0x2               # is |result| > 2.b?
8297        fbgt.w          fmul_normal_exit        # no; no underflow occurred
8298        fblt.w          fmul_unfl               # yes; underflow occurred
8299
8300#
8301# we still don't know if underflow occurred. result is ~ equal to 2. but,
8302# we don't know if the result was an underflow that rounded up to a 2 or
8303# a normalized number that rounded down to a 2. so, redo the entire operation
8304# using RZ as the rounding mode to see what the pre-rounded result is.
8305# this case should be relatively rare.
8306#
8307        fmovm.x         FP_SCR1(%a6),&0x40      # load dst operand
8308
8309        mov.l           L_SCR3(%a6),%d1
8310        andi.b          &0xc0,%d1               # keep rnd prec
8311        ori.b           &rz_mode*0x10,%d1       # insert RZ
8312
8313        fmov.l          %d1,%fpcr               # set FPCR
8314        fmov.l          &0x0,%fpsr              # clear FPSR
8315
8316        fmul.x          FP_SCR0(%a6),%fp1       # execute multiply
8317
8318        fmov.l          &0x0,%fpcr              # clear FPCR
8319        fabs.x          %fp1                    # make absolute value
8320        fcmp.b          %fp1,&0x2               # is |result| < 2.b?
8321        fbge.w          fmul_normal_exit        # no; no underflow occurred
8322        bra.w           fmul_unfl               # yes, underflow occurred
8323
8324################################################################################
8325
8326#
8327# Multiply: inputs are not both normalized; what are they?
8328#
8329fmul_not_norm:
8330        mov.w           (tbl_fmul_op.b,%pc,%d1.w*2),%d1
8331        jmp             (tbl_fmul_op.b,%pc,%d1.w)
8332
8333        swbeg           &48
8334tbl_fmul_op:
8335        short           fmul_norm       - tbl_fmul_op # NORM x NORM
8336        short           fmul_zero       - tbl_fmul_op # NORM x ZERO
8337        short           fmul_inf_src    - tbl_fmul_op # NORM x INF
8338        short           fmul_res_qnan   - tbl_fmul_op # NORM x QNAN
8339        short           fmul_norm       - tbl_fmul_op # NORM x DENORM
8340        short           fmul_res_snan   - tbl_fmul_op # NORM x SNAN
8341        short           tbl_fmul_op     - tbl_fmul_op #
8342        short           tbl_fmul_op     - tbl_fmul_op #
8343
8344        short           fmul_zero       - tbl_fmul_op # ZERO x NORM
8345        short           fmul_zero       - tbl_fmul_op # ZERO x ZERO
8346        short           fmul_res_operr  - tbl_fmul_op # ZERO x INF
8347        short           fmul_res_qnan   - tbl_fmul_op # ZERO x QNAN
8348        short           fmul_zero       - tbl_fmul_op # ZERO x DENORM
8349        short           fmul_res_snan   - tbl_fmul_op # ZERO x SNAN
8350        short           tbl_fmul_op     - tbl_fmul_op #
8351        short           tbl_fmul_op     - tbl_fmul_op #
8352
8353        short           fmul_inf_dst    - tbl_fmul_op # INF x NORM
8354        short           fmul_res_operr  - tbl_fmul_op # INF x ZERO
8355        short           fmul_inf_dst    - tbl_fmul_op # INF x INF
8356        short           fmul_res_qnan   - tbl_fmul_op # INF x QNAN
8357        short           fmul_inf_dst    - tbl_fmul_op # INF x DENORM
8358        short           fmul_res_snan   - tbl_fmul_op # INF x SNAN
8359        short           tbl_fmul_op     - tbl_fmul_op #
8360        short           tbl_fmul_op     - tbl_fmul_op #
8361
8362        short           fmul_res_qnan   - tbl_fmul_op # QNAN x NORM
8363        short           fmul_res_qnan   - tbl_fmul_op # QNAN x ZERO
8364        short           fmul_res_qnan   - tbl_fmul_op # QNAN x INF
8365        short           fmul_res_qnan   - tbl_fmul_op # QNAN x QNAN
8366        short           fmul_res_qnan   - tbl_fmul_op # QNAN x DENORM
8367        short           fmul_res_snan   - tbl_fmul_op # QNAN x SNAN
8368        short           tbl_fmul_op     - tbl_fmul_op #
8369        short           tbl_fmul_op     - tbl_fmul_op #
8370
8371        short           fmul_norm       - tbl_fmul_op # NORM x NORM
8372        short           fmul_zero       - tbl_fmul_op # NORM x ZERO
8373        short           fmul_inf_src    - tbl_fmul_op # NORM x INF
8374        short           fmul_res_qnan   - tbl_fmul_op # NORM x QNAN
8375        short           fmul_norm       - tbl_fmul_op # NORM x DENORM
8376        short           fmul_res_snan   - tbl_fmul_op # NORM x SNAN
8377        short           tbl_fmul_op     - tbl_fmul_op #
8378        short           tbl_fmul_op     - tbl_fmul_op #
8379
8380        short           fmul_res_snan   - tbl_fmul_op # SNAN x NORM
8381        short           fmul_res_snan   - tbl_fmul_op # SNAN x ZERO
8382        short           fmul_res_snan   - tbl_fmul_op # SNAN x INF
8383        short           fmul_res_snan   - tbl_fmul_op # SNAN x QNAN
8384        short           fmul_res_snan   - tbl_fmul_op # SNAN x DENORM
8385        short           fmul_res_snan   - tbl_fmul_op # SNAN x SNAN
8386        short           tbl_fmul_op     - tbl_fmul_op #
8387        short           tbl_fmul_op     - tbl_fmul_op #
8388
8389fmul_res_operr:
8390        bra.l           res_operr
8391fmul_res_snan:
8392        bra.l           res_snan
8393fmul_res_qnan:
8394        bra.l           res_qnan
8395
8396#
8397# Multiply: (Zero x Zero) || (Zero x norm) || (Zero x denorm)
8398#
8399        global          fmul_zero               # global for fsglmul
8400fmul_zero:
8401        mov.b           SRC_EX(%a0),%d0         # exclusive or the signs
8402        mov.b           DST_EX(%a1),%d1
8403        eor.b           %d0,%d1
8404        bpl.b           fmul_zero_p             # result ZERO is pos.
8405fmul_zero_n:
8406        fmov.s          &0x80000000,%fp0        # load -ZERO
8407        mov.b           &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/N
8408        rts
8409fmul_zero_p:
8410        fmov.s          &0x00000000,%fp0        # load +ZERO
8411        mov.b           &z_bmask,FPSR_CC(%a6)   # set Z
8412        rts
8413
8414#
8415# Multiply: (inf x inf) || (inf x norm) || (inf x denorm)
8416#
8417# Note: The j-bit for an infinity is a don't-care. However, to be
8418# strictly compatible w/ the 68881/882, we make sure to return an
8419# INF w/ the j-bit set if the input INF j-bit was set. Destination
8420# INFs take priority.
8421#
8422        global          fmul_inf_dst            # global for fsglmul
8423fmul_inf_dst:
8424        fmovm.x         DST(%a1),&0x80          # return INF result in fp0
8425        mov.b           SRC_EX(%a0),%d0         # exclusive or the signs
8426        mov.b           DST_EX(%a1),%d1
8427        eor.b           %d0,%d1
8428        bpl.b           fmul_inf_dst_p          # result INF is pos.
8429fmul_inf_dst_n:
8430        fabs.x          %fp0                    # clear result sign
8431        fneg.x          %fp0                    # set result sign
8432        mov.b           &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/N
8433        rts
8434fmul_inf_dst_p:
8435        fabs.x          %fp0                    # clear result sign
8436        mov.b           &inf_bmask,FPSR_CC(%a6) # set INF
8437        rts
8438
8439        global          fmul_inf_src            # global for fsglmul
8440fmul_inf_src:
8441        fmovm.x         SRC(%a0),&0x80          # return INF result in fp0
8442        mov.b           SRC_EX(%a0),%d0         # exclusive or the signs
8443        mov.b           DST_EX(%a1),%d1
8444        eor.b           %d0,%d1
8445        bpl.b           fmul_inf_dst_p          # result INF is pos.
8446        bra.b           fmul_inf_dst_n
8447
8448#########################################################################
8449# XDEF **************************************************************** #
8450#       fin(): emulates the fmove instruction                           #
8451#       fsin(): emulates the fsmove instruction                         #
8452#       fdin(): emulates the fdmove instruction                         #
8453#                                                                       #
8454# XREF **************************************************************** #
8455#       norm() - normalize mantissa for EXOP on denorm                  #
8456#       scale_to_zero_src() - scale src exponent to zero                #
8457#       ovf_res() - return default overflow result                      #
8458#       unf_res() - return default underflow result                     #
8459#       res_qnan_1op() - return QNAN result                             #
8460#       res_snan_1op() - return SNAN result                             #
8461#                                                                       #
8462# INPUT *************************************************************** #
8463#       a0 = pointer to extended precision source operand               #
8464#       d0 = round prec/mode                                            #
8465#                                                                       #
8466# OUTPUT ************************************************************** #
8467#       fp0 = result                                                    #
8468#       fp1 = EXOP (if exception occurred)                              #
8469#                                                                       #
8470# ALGORITHM *********************************************************** #
8471#       Handle NANs, infinities, and zeroes as special cases. Divide    #
8472# norms into extended, single, and double precision.                    #
8473#       Norms can be emulated w/ a regular fmove instruction. For       #
8474# sgl/dbl, must scale exponent and perform an "fmove". Check to see     #
8475# if the result would have overflowed/underflowed. If so, use unf_res() #
8476# or ovf_res() to return the default result. Also return EXOP if        #
8477# exception is enabled. If no exception, return the default result.     #
8478#       Unnorms don't pass through here.                                #
8479#                                                                       #
8480#########################################################################
8481
8482        global          fsin
8483fsin:
8484        andi.b          &0x30,%d0               # clear rnd prec
8485        ori.b           &s_mode*0x10,%d0        # insert sgl precision
8486        bra.b           fin
8487
8488        global          fdin
8489fdin:
8490        andi.b          &0x30,%d0               # clear rnd prec
8491        ori.b           &d_mode*0x10,%d0        # insert dbl precision
8492
8493        global          fin
8494fin:
8495        mov.l           %d0,L_SCR3(%a6)         # store rnd info
8496
8497        mov.b           STAG(%a6),%d1           # fetch src optype tag
8498        bne.w           fin_not_norm            # optimize on non-norm input
8499
8500#
8501# FP MOVE IN: NORMs and DENORMs ONLY!
8502#
8503fin_norm:
8504        andi.b          &0xc0,%d0               # is precision extended?
8505        bne.w           fin_not_ext             # no, so go handle dbl or sgl
8506
8507#
8508# precision selected is extended. so...we cannot get an underflow
8509# or overflow because of rounding to the correct precision. so...
8510# skip the scaling and unscaling...
8511#
8512        tst.b           SRC_EX(%a0)             # is the operand negative?
8513        bpl.b           fin_norm_done           # no
8514        bset            &neg_bit,FPSR_CC(%a6)   # yes, so set 'N' ccode bit
8515fin_norm_done:
8516        fmovm.x         SRC(%a0),&0x80          # return result in fp0
8517        rts
8518
8519#
8520# for an extended precision DENORM, the UNFL exception bit is set
8521# the accrued bit is NOT set in this instance(no inexactness!)
8522#
8523fin_denorm:
8524        andi.b          &0xc0,%d0               # is precision extended?
8525        bne.w           fin_not_ext             # no, so go handle dbl or sgl
8526
8527        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
8528        tst.b           SRC_EX(%a0)             # is the operand negative?
8529        bpl.b           fin_denorm_done         # no
8530        bset            &neg_bit,FPSR_CC(%a6)   # yes, so set 'N' ccode bit
8531fin_denorm_done:
8532        fmovm.x         SRC(%a0),&0x80          # return result in fp0
8533        btst            &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled?
8534        bne.b           fin_denorm_unfl_ena     # yes
8535        rts
8536
8537#
8538# the input is an extended DENORM and underflow is enabled in the FPCR.
8539# normalize the mantissa and add the bias of 0x6000 to the resulting negative
8540# exponent and insert back into the operand.
8541#
8542fin_denorm_unfl_ena:
8543        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
8544        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
8545        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
8546        lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
8547        bsr.l           norm                    # normalize result
8548        neg.w           %d0                     # new exponent = -(shft val)
8549        addi.w          &0x6000,%d0             # add new bias to exponent
8550        mov.w           FP_SCR0_EX(%a6),%d1     # fetch old sign,exp
8551        andi.w          &0x8000,%d1             # keep old sign
8552        andi.w          &0x7fff,%d0             # clear sign position
8553        or.w            %d1,%d0                 # concat new exo,old sign
8554        mov.w           %d0,FP_SCR0_EX(%a6)     # insert new exponent
8555        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
8556        rts
8557
8558#
8559# operand is to be rounded to single or double precision
8560#
8561fin_not_ext:
8562        cmpi.b          %d0,&s_mode*0x10        # separate sgl/dbl prec
8563        bne.b           fin_dbl
8564
8565#
8566# operand is to be rounded to single precision
8567#
8568fin_sgl:
8569        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
8570        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
8571        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
8572        bsr.l           scale_to_zero_src       # calculate scale factor
8573
8574        cmpi.l          %d0,&0x3fff-0x3f80      # will move in underflow?
8575        bge.w           fin_sd_unfl             # yes; go handle underflow
8576        cmpi.l          %d0,&0x3fff-0x407e      # will move in overflow?
8577        beq.w           fin_sd_may_ovfl         # maybe; go check
8578        blt.w           fin_sd_ovfl             # yes; go handle overflow
8579
8580#
8581# operand will NOT overflow or underflow when moved into the fp reg file
8582#
8583fin_sd_normal:
8584        fmov.l          &0x0,%fpsr              # clear FPSR
8585        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
8586
8587        fmov.x          FP_SCR0(%a6),%fp0       # perform move
8588
8589        fmov.l          %fpsr,%d1               # save FPSR
8590        fmov.l          &0x0,%fpcr              # clear FPCR
8591
8592        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
8593
8594fin_sd_normal_exit:
8595        mov.l           %d2,-(%sp)              # save d2
8596        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
8597        mov.w           FP_SCR0_EX(%a6),%d1     # load {sgn,exp}
8598        mov.w           %d1,%d2                 # make a copy
8599        andi.l          &0x7fff,%d1             # strip sign
8600        sub.l           %d0,%d1                 # add scale factor
8601        andi.w          &0x8000,%d2             # keep old sign
8602        or.w            %d1,%d2                 # concat old sign,new exponent
8603        mov.w           %d2,FP_SCR0_EX(%a6)     # insert new exponent
8604        mov.l           (%sp)+,%d2              # restore d2
8605        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
8606        rts
8607
8608#
8609# operand is to be rounded to double precision
8610#
8611fin_dbl:
8612        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
8613        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
8614        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
8615        bsr.l           scale_to_zero_src       # calculate scale factor
8616
8617        cmpi.l          %d0,&0x3fff-0x3c00      # will move in underflow?
8618        bge.w           fin_sd_unfl             # yes; go handle underflow
8619        cmpi.l          %d0,&0x3fff-0x43fe      # will move in overflow?
8620        beq.w           fin_sd_may_ovfl         # maybe; go check
8621        blt.w           fin_sd_ovfl             # yes; go handle overflow
8622        bra.w           fin_sd_normal           # no; ho handle normalized op
8623
8624#
8625# operand WILL underflow when moved in to the fp register file
8626#
8627fin_sd_unfl:
8628        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
8629
8630        tst.b           FP_SCR0_EX(%a6)         # is operand negative?
8631        bpl.b           fin_sd_unfl_tst
8632        bset            &neg_bit,FPSR_CC(%a6)   # set 'N' ccode bit
8633
8634# if underflow or inexact is enabled, then go calculate the EXOP first.
8635fin_sd_unfl_tst:
8636        mov.b           FPCR_ENABLE(%a6),%d1
8637        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
8638        bne.b           fin_sd_unfl_ena         # yes
8639
8640fin_sd_unfl_dis:
8641        lea             FP_SCR0(%a6),%a0        # pass: result addr
8642        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
8643        bsr.l           unf_res                 # calculate default result
8644        or.b            %d0,FPSR_CC(%a6)        # unf_res may have set 'Z'
8645        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
8646        rts
8647
8648#
8649# operand will underflow AND underflow or inexact is enabled.
8650# Therefore, we must return the result rounded to extended precision.
8651#
8652fin_sd_unfl_ena:
8653        mov.l           FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
8654        mov.l           FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
8655        mov.w           FP_SCR0_EX(%a6),%d1     # load current exponent
8656
8657        mov.l           %d2,-(%sp)              # save d2
8658        mov.w           %d1,%d2                 # make a copy
8659        andi.l          &0x7fff,%d1             # strip sign
8660        sub.l           %d0,%d1                 # subtract scale factor
8661        andi.w          &0x8000,%d2             # extract old sign
8662        addi.l          &0x6000,%d1             # add new bias
8663        andi.w          &0x7fff,%d1
8664        or.w            %d1,%d2                 # concat old sign,new exp
8665        mov.w           %d2,FP_SCR1_EX(%a6)     # insert new exponent
8666        fmovm.x         FP_SCR1(%a6),&0x40      # return EXOP in fp1
8667        mov.l           (%sp)+,%d2              # restore d2
8668        bra.b           fin_sd_unfl_dis
8669
8670#
8671# operand WILL overflow.
8672#
8673fin_sd_ovfl:
8674        fmov.l          &0x0,%fpsr              # clear FPSR
8675        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
8676
8677        fmov.x          FP_SCR0(%a6),%fp0       # perform move
8678
8679        fmov.l          &0x0,%fpcr              # clear FPCR
8680        fmov.l          %fpsr,%d1               # save FPSR
8681
8682        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
8683
8684fin_sd_ovfl_tst:
8685        or.l            &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
8686
8687        mov.b           FPCR_ENABLE(%a6),%d1
8688        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
8689        bne.b           fin_sd_ovfl_ena         # yes
8690
8691#
8692# OVFL is not enabled; therefore, we must create the default result by
8693# calling ovf_res().
8694#
8695fin_sd_ovfl_dis:
8696        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
8697        sne             %d1                     # set sign param accordingly
8698        mov.l           L_SCR3(%a6),%d0         # pass: prec,mode
8699        bsr.l           ovf_res                 # calculate default result
8700        or.b            %d0,FPSR_CC(%a6)        # set INF,N if applicable
8701        fmovm.x         (%a0),&0x80             # return default result in fp0
8702        rts
8703
8704#
8705# OVFL is enabled.
8706# the INEX2 bit has already been updated by the round to the correct precision.
8707# now, round to extended(and don't alter the FPSR).
8708#
8709fin_sd_ovfl_ena:
8710        mov.l           %d2,-(%sp)              # save d2
8711        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
8712        mov.l           %d1,%d2                 # make a copy
8713        andi.l          &0x7fff,%d1             # strip sign
8714        andi.w          &0x8000,%d2             # keep old sign
8715        sub.l           %d0,%d1                 # add scale factor
8716        sub.l           &0x6000,%d1             # subtract bias
8717        andi.w          &0x7fff,%d1
8718        or.w            %d2,%d1
8719        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
8720        mov.l           (%sp)+,%d2              # restore d2
8721        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
8722        bra.b           fin_sd_ovfl_dis
8723
8724#
8725# the move in MAY overflow. so...
8726#
8727fin_sd_may_ovfl:
8728        fmov.l          &0x0,%fpsr              # clear FPSR
8729        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
8730
8731        fmov.x          FP_SCR0(%a6),%fp0       # perform the move
8732
8733        fmov.l          %fpsr,%d1               # save status
8734        fmov.l          &0x0,%fpcr              # clear FPCR
8735
8736        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
8737
8738        fabs.x          %fp0,%fp1               # make a copy of result
8739        fcmp.b          %fp1,&0x2               # is |result| >= 2.b?
8740        fbge.w          fin_sd_ovfl_tst         # yes; overflow has occurred
8741
8742# no, it didn't overflow; we have correct result
8743        bra.w           fin_sd_normal_exit
8744
8745##########################################################################
8746
8747#
8748# operand is not a NORM: check its optype and branch accordingly
8749#
8750fin_not_norm:
8751        cmpi.b          %d1,&DENORM             # weed out DENORM
8752        beq.w           fin_denorm
8753        cmpi.b          %d1,&SNAN               # weed out SNANs
8754        beq.l           res_snan_1op
8755        cmpi.b          %d1,&QNAN               # weed out QNANs
8756        beq.l           res_qnan_1op
8757
8758#
8759# do the fmove in; at this point, only possible ops are ZERO and INF.
8760# use fmov to determine ccodes.
8761# prec:mode should be zero at this point but it won't affect answer anyways.
8762#
8763        fmov.x          SRC(%a0),%fp0           # do fmove in
8764        fmov.l          %fpsr,%d0               # no exceptions possible
8765        rol.l           &0x8,%d0                # put ccodes in lo byte
8766        mov.b           %d0,FPSR_CC(%a6)        # insert correct ccodes
8767        rts
8768
8769#########################################################################
8770# XDEF **************************************************************** #
8771#       fdiv(): emulates the fdiv instruction                           #
8772#       fsdiv(): emulates the fsdiv instruction                         #
8773#       fddiv(): emulates the fddiv instruction                         #
8774#                                                                       #
8775# XREF **************************************************************** #
8776#       scale_to_zero_src() - scale src exponent to zero                #
8777#       scale_to_zero_dst() - scale dst exponent to zero                #
8778#       unf_res() - return default underflow result                     #
8779#       ovf_res() - return default overflow result                      #
8780#       res_qnan() - return QNAN result                                 #
8781#       res_snan() - return SNAN result                                 #
8782#                                                                       #
8783# INPUT *************************************************************** #
8784#       a0 = pointer to extended precision source operand               #
8785#       a1 = pointer to extended precision destination operand          #
8786#       d0  rnd prec,mode                                               #
8787#                                                                       #
8788# OUTPUT ************************************************************** #
8789#       fp0 = result                                                    #
8790#       fp1 = EXOP (if exception occurred)                              #
8791#                                                                       #
8792# ALGORITHM *********************************************************** #
8793#       Handle NANs, infinities, and zeroes as special cases. Divide    #
8794# norms/denorms into ext/sgl/dbl precision.                             #
8795#       For norms/denorms, scale the exponents such that a divide       #
8796# instruction won't cause an exception. Use the regular fdiv to         #
8797# compute a result. Check if the regular operands would have taken      #
8798# an exception. If so, return the default overflow/underflow result     #
8799# and return the EXOP if exceptions are enabled. Else, scale the        #
8800# result operand to the proper exponent.                                #
8801#                                                                       #
8802#########################################################################
8803
8804        align           0x10
8805tbl_fdiv_unfl:
8806        long            0x3fff - 0x0000         # ext_unfl
8807        long            0x3fff - 0x3f81         # sgl_unfl
8808        long            0x3fff - 0x3c01         # dbl_unfl
8809
8810tbl_fdiv_ovfl:
8811        long            0x3fff - 0x7ffe         # ext overflow exponent
8812        long            0x3fff - 0x407e         # sgl overflow exponent
8813        long            0x3fff - 0x43fe         # dbl overflow exponent
8814
8815        global          fsdiv
8816fsdiv:
8817        andi.b          &0x30,%d0               # clear rnd prec
8818        ori.b           &s_mode*0x10,%d0        # insert sgl prec
8819        bra.b           fdiv
8820
8821        global          fddiv
8822fddiv:
8823        andi.b          &0x30,%d0               # clear rnd prec
8824        ori.b           &d_mode*0x10,%d0        # insert dbl prec
8825
8826        global          fdiv
8827fdiv:
8828        mov.l           %d0,L_SCR3(%a6)         # store rnd info
8829
8830        clr.w           %d1
8831        mov.b           DTAG(%a6),%d1
8832        lsl.b           &0x3,%d1
8833        or.b            STAG(%a6),%d1           # combine src tags
8834
8835        bne.w           fdiv_not_norm           # optimize on non-norm input
8836
8837#
8838# DIVIDE: NORMs and DENORMs ONLY!
8839#
8840fdiv_norm:
8841        mov.w           DST_EX(%a1),FP_SCR1_EX(%a6)
8842        mov.l           DST_HI(%a1),FP_SCR1_HI(%a6)
8843        mov.l           DST_LO(%a1),FP_SCR1_LO(%a6)
8844
8845        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
8846        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
8847        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
8848
8849        bsr.l           scale_to_zero_src       # scale src exponent
8850        mov.l           %d0,-(%sp)              # save scale factor 1
8851
8852        bsr.l           scale_to_zero_dst       # scale dst exponent
8853
8854        neg.l           (%sp)                   # SCALE FACTOR = scale1 - scale2
8855        add.l           %d0,(%sp)
8856
8857        mov.w           2+L_SCR3(%a6),%d1       # fetch precision
8858        lsr.b           &0x6,%d1                # shift to lo bits
8859        mov.l           (%sp)+,%d0              # load S.F.
8860        cmp.l           %d0,(tbl_fdiv_ovfl.b,%pc,%d1.w*4) # will result overflow?
8861        ble.w           fdiv_may_ovfl           # result will overflow
8862
8863        cmp.l           %d0,(tbl_fdiv_unfl.w,%pc,%d1.w*4) # will result underflow?
8864        beq.w           fdiv_may_unfl           # maybe
8865        bgt.w           fdiv_unfl               # yes; go handle underflow
8866
8867fdiv_normal:
8868        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
8869
8870        fmov.l          L_SCR3(%a6),%fpcr       # save FPCR
8871        fmov.l          &0x0,%fpsr              # clear FPSR
8872
8873        fdiv.x          FP_SCR0(%a6),%fp0       # perform divide
8874
8875        fmov.l          %fpsr,%d1               # save FPSR
8876        fmov.l          &0x0,%fpcr              # clear FPCR
8877
8878        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
8879
8880fdiv_normal_exit:
8881        fmovm.x         &0x80,FP_SCR0(%a6)      # store result on stack
8882        mov.l           %d2,-(%sp)              # store d2
8883        mov.w           FP_SCR0_EX(%a6),%d1     # load {sgn,exp}
8884        mov.l           %d1,%d2                 # make a copy
8885        andi.l          &0x7fff,%d1             # strip sign
8886        andi.w          &0x8000,%d2             # keep old sign
8887        sub.l           %d0,%d1                 # add scale factor
8888        or.w            %d2,%d1                 # concat old sign,new exp
8889        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
8890        mov.l           (%sp)+,%d2              # restore d2
8891        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
8892        rts
8893
8894tbl_fdiv_ovfl2:
8895        long            0x7fff
8896        long            0x407f
8897        long            0x43ff
8898
8899fdiv_no_ovfl:
8900        mov.l           (%sp)+,%d0              # restore scale factor
8901        bra.b           fdiv_normal_exit
8902
8903fdiv_may_ovfl:
8904        mov.l           %d0,-(%sp)              # save scale factor
8905
8906        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
8907
8908        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
8909        fmov.l          &0x0,%fpsr              # set FPSR
8910
8911        fdiv.x          FP_SCR0(%a6),%fp0       # execute divide
8912
8913        fmov.l          %fpsr,%d0
8914        fmov.l          &0x0,%fpcr
8915
8916        or.l            %d0,USER_FPSR(%a6)      # save INEX,N
8917
8918        fmovm.x         &0x01,-(%sp)            # save result to stack
8919        mov.w           (%sp),%d0               # fetch new exponent
8920        add.l           &0xc,%sp                # clear result from stack
8921        andi.l          &0x7fff,%d0             # strip sign
8922        sub.l           (%sp),%d0               # add scale factor
8923        cmp.l           %d0,(tbl_fdiv_ovfl2.b,%pc,%d1.w*4)
8924        blt.b           fdiv_no_ovfl
8925        mov.l           (%sp)+,%d0
8926
8927fdiv_ovfl_tst:
8928        or.l            &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
8929
8930        mov.b           FPCR_ENABLE(%a6),%d1
8931        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
8932        bne.b           fdiv_ovfl_ena           # yes
8933
8934fdiv_ovfl_dis:
8935        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
8936        sne             %d1                     # set sign param accordingly
8937        mov.l           L_SCR3(%a6),%d0         # pass prec:rnd
8938        bsr.l           ovf_res                 # calculate default result
8939        or.b            %d0,FPSR_CC(%a6)        # set INF if applicable
8940        fmovm.x         (%a0),&0x80             # return default result in fp0
8941        rts
8942
8943fdiv_ovfl_ena:
8944        mov.l           L_SCR3(%a6),%d1
8945        andi.b          &0xc0,%d1               # is precision extended?
8946        bne.b           fdiv_ovfl_ena_sd        # no, do sgl or dbl
8947
8948fdiv_ovfl_ena_cont:
8949        fmovm.x         &0x80,FP_SCR0(%a6)      # move result to stack
8950
8951        mov.l           %d2,-(%sp)              # save d2
8952        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
8953        mov.w           %d1,%d2                 # make a copy
8954        andi.l          &0x7fff,%d1             # strip sign
8955        sub.l           %d0,%d1                 # add scale factor
8956        subi.l          &0x6000,%d1             # subtract bias
8957        andi.w          &0x7fff,%d1             # clear sign bit
8958        andi.w          &0x8000,%d2             # keep old sign
8959        or.w            %d2,%d1                 # concat old sign,new exp
8960        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
8961        mov.l           (%sp)+,%d2              # restore d2
8962        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
8963        bra.b           fdiv_ovfl_dis
8964
8965fdiv_ovfl_ena_sd:
8966        fmovm.x         FP_SCR1(%a6),&0x80      # load dst operand
8967
8968        mov.l           L_SCR3(%a6),%d1
8969        andi.b          &0x30,%d1               # keep rnd mode
8970        fmov.l          %d1,%fpcr               # set FPCR
8971
8972        fdiv.x          FP_SCR0(%a6),%fp0       # execute divide
8973
8974        fmov.l          &0x0,%fpcr              # clear FPCR
8975        bra.b           fdiv_ovfl_ena_cont
8976
8977fdiv_unfl:
8978        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
8979
8980        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
8981
8982        fmov.l          &rz_mode*0x10,%fpcr     # set FPCR
8983        fmov.l          &0x0,%fpsr              # clear FPSR
8984
8985        fdiv.x          FP_SCR0(%a6),%fp0       # execute divide
8986
8987        fmov.l          %fpsr,%d1               # save status
8988        fmov.l          &0x0,%fpcr              # clear FPCR
8989
8990        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
8991
8992        mov.b           FPCR_ENABLE(%a6),%d1
8993        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
8994        bne.b           fdiv_unfl_ena           # yes
8995
8996fdiv_unfl_dis:
8997        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
8998
8999        lea             FP_SCR0(%a6),%a0        # pass: result addr
9000        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
9001        bsr.l           unf_res                 # calculate default result
9002        or.b            %d0,FPSR_CC(%a6)        # 'Z' may have been set
9003        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
9004        rts
9005
9006#
9007# UNFL is enabled.
9008#
9009fdiv_unfl_ena:
9010        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op
9011
9012        mov.l           L_SCR3(%a6),%d1
9013        andi.b          &0xc0,%d1               # is precision extended?
9014        bne.b           fdiv_unfl_ena_sd        # no, sgl or dbl
9015
9016        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
9017
9018fdiv_unfl_ena_cont:
9019        fmov.l          &0x0,%fpsr              # clear FPSR
9020
9021        fdiv.x          FP_SCR0(%a6),%fp1       # execute divide
9022
9023        fmov.l          &0x0,%fpcr              # clear FPCR
9024
9025        fmovm.x         &0x40,FP_SCR0(%a6)      # save result to stack
9026        mov.l           %d2,-(%sp)              # save d2
9027        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
9028        mov.l           %d1,%d2                 # make a copy
9029        andi.l          &0x7fff,%d1             # strip sign
9030        andi.w          &0x8000,%d2             # keep old sign
9031        sub.l           %d0,%d1                 # add scale factoer
9032        addi.l          &0x6000,%d1             # add bias
9033        andi.w          &0x7fff,%d1
9034        or.w            %d2,%d1                 # concat old sign,new exp
9035        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exp
9036        mov.l           (%sp)+,%d2              # restore d2
9037        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
9038        bra.w           fdiv_unfl_dis
9039
9040fdiv_unfl_ena_sd:
9041        mov.l           L_SCR3(%a6),%d1
9042        andi.b          &0x30,%d1               # use only rnd mode
9043        fmov.l          %d1,%fpcr               # set FPCR
9044
9045        bra.b           fdiv_unfl_ena_cont
9046
9047#
9048# the divide operation MAY underflow:
9049#
9050fdiv_may_unfl:
9051        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
9052
9053        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
9054        fmov.l          &0x0,%fpsr              # clear FPSR
9055
9056        fdiv.x          FP_SCR0(%a6),%fp0       # execute divide
9057
9058        fmov.l          %fpsr,%d1               # save status
9059        fmov.l          &0x0,%fpcr              # clear FPCR
9060
9061        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
9062
9063        fabs.x          %fp0,%fp1               # make a copy of result
9064        fcmp.b          %fp1,&0x1               # is |result| > 1.b?
9065        fbgt.w          fdiv_normal_exit        # no; no underflow occurred
9066        fblt.w          fdiv_unfl               # yes; underflow occurred
9067
9068#
9069# we still don't know if underflow occurred. result is ~ equal to 1. but,
9070# we don't know if the result was an underflow that rounded up to a 1
9071# or a normalized number that rounded down to a 1. so, redo the entire
9072# operation using RZ as the rounding mode to see what the pre-rounded
9073# result is. this case should be relatively rare.
9074#
9075        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op into fp1
9076
9077        mov.l           L_SCR3(%a6),%d1
9078        andi.b          &0xc0,%d1               # keep rnd prec
9079        ori.b           &rz_mode*0x10,%d1       # insert RZ
9080
9081        fmov.l          %d1,%fpcr               # set FPCR
9082        fmov.l          &0x0,%fpsr              # clear FPSR
9083
9084        fdiv.x          FP_SCR0(%a6),%fp1       # execute divide
9085
9086        fmov.l          &0x0,%fpcr              # clear FPCR
9087        fabs.x          %fp1                    # make absolute value
9088        fcmp.b          %fp1,&0x1               # is |result| < 1.b?
9089        fbge.w          fdiv_normal_exit        # no; no underflow occurred
9090        bra.w           fdiv_unfl               # yes; underflow occurred
9091
9092############################################################################
9093
9094#
9095# Divide: inputs are not both normalized; what are they?
9096#
9097fdiv_not_norm:
9098        mov.w           (tbl_fdiv_op.b,%pc,%d1.w*2),%d1
9099        jmp             (tbl_fdiv_op.b,%pc,%d1.w*1)
9100
9101        swbeg           &48
9102tbl_fdiv_op:
9103        short           fdiv_norm       - tbl_fdiv_op # NORM / NORM
9104        short           fdiv_inf_load   - tbl_fdiv_op # NORM / ZERO
9105        short           fdiv_zero_load  - tbl_fdiv_op # NORM / INF
9106        short           fdiv_res_qnan   - tbl_fdiv_op # NORM / QNAN
9107        short           fdiv_norm       - tbl_fdiv_op # NORM / DENORM
9108        short           fdiv_res_snan   - tbl_fdiv_op # NORM / SNAN
9109        short           tbl_fdiv_op     - tbl_fdiv_op #
9110        short           tbl_fdiv_op     - tbl_fdiv_op #
9111
9112        short           fdiv_zero_load  - tbl_fdiv_op # ZERO / NORM
9113        short           fdiv_res_operr  - tbl_fdiv_op # ZERO / ZERO
9114        short           fdiv_zero_load  - tbl_fdiv_op # ZERO / INF
9115        short           fdiv_res_qnan   - tbl_fdiv_op # ZERO / QNAN
9116        short           fdiv_zero_load  - tbl_fdiv_op # ZERO / DENORM
9117        short           fdiv_res_snan   - tbl_fdiv_op # ZERO / SNAN
9118        short           tbl_fdiv_op     - tbl_fdiv_op #
9119        short           tbl_fdiv_op     - tbl_fdiv_op #
9120
9121        short           fdiv_inf_dst    - tbl_fdiv_op # INF / NORM
9122        short           fdiv_inf_dst    - tbl_fdiv_op # INF / ZERO
9123        short           fdiv_res_operr  - tbl_fdiv_op # INF / INF
9124        short           fdiv_res_qnan   - tbl_fdiv_op # INF / QNAN
9125        short           fdiv_inf_dst    - tbl_fdiv_op # INF / DENORM
9126        short           fdiv_res_snan   - tbl_fdiv_op # INF / SNAN
9127        short           tbl_fdiv_op     - tbl_fdiv_op #
9128        short           tbl_fdiv_op     - tbl_fdiv_op #
9129
9130        short           fdiv_res_qnan   - tbl_fdiv_op # QNAN / NORM
9131        short           fdiv_res_qnan   - tbl_fdiv_op # QNAN / ZERO
9132        short           fdiv_res_qnan   - tbl_fdiv_op # QNAN / INF
9133        short           fdiv_res_qnan   - tbl_fdiv_op # QNAN / QNAN
9134        short           fdiv_res_qnan   - tbl_fdiv_op # QNAN / DENORM
9135        short           fdiv_res_snan   - tbl_fdiv_op # QNAN / SNAN
9136        short           tbl_fdiv_op     - tbl_fdiv_op #
9137        short           tbl_fdiv_op     - tbl_fdiv_op #
9138
9139        short           fdiv_norm       - tbl_fdiv_op # DENORM / NORM
9140        short           fdiv_inf_load   - tbl_fdiv_op # DENORM / ZERO
9141        short           fdiv_zero_load  - tbl_fdiv_op # DENORM / INF
9142        short           fdiv_res_qnan   - tbl_fdiv_op # DENORM / QNAN
9143        short           fdiv_norm       - tbl_fdiv_op # DENORM / DENORM
9144        short           fdiv_res_snan   - tbl_fdiv_op # DENORM / SNAN
9145        short           tbl_fdiv_op     - tbl_fdiv_op #
9146        short           tbl_fdiv_op     - tbl_fdiv_op #
9147
9148        short           fdiv_res_snan   - tbl_fdiv_op # SNAN / NORM
9149        short           fdiv_res_snan   - tbl_fdiv_op # SNAN / ZERO
9150        short           fdiv_res_snan   - tbl_fdiv_op # SNAN / INF
9151        short           fdiv_res_snan   - tbl_fdiv_op # SNAN / QNAN
9152        short           fdiv_res_snan   - tbl_fdiv_op # SNAN / DENORM
9153        short           fdiv_res_snan   - tbl_fdiv_op # SNAN / SNAN
9154        short           tbl_fdiv_op     - tbl_fdiv_op #
9155        short           tbl_fdiv_op     - tbl_fdiv_op #
9156
9157fdiv_res_qnan:
9158        bra.l           res_qnan
9159fdiv_res_snan:
9160        bra.l           res_snan
9161fdiv_res_operr:
9162        bra.l           res_operr
9163
9164        global          fdiv_zero_load          # global for fsgldiv
9165fdiv_zero_load:
9166        mov.b           SRC_EX(%a0),%d0         # result sign is exclusive
9167        mov.b           DST_EX(%a1),%d1         # or of input signs.
9168        eor.b           %d0,%d1
9169        bpl.b           fdiv_zero_load_p        # result is positive
9170        fmov.s          &0x80000000,%fp0        # load a -ZERO
9171        mov.b           &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/N
9172        rts
9173fdiv_zero_load_p:
9174        fmov.s          &0x00000000,%fp0        # load a +ZERO
9175        mov.b           &z_bmask,FPSR_CC(%a6)   # set Z
9176        rts
9177
9178#
9179# The destination was In Range and the source was a ZERO. The result,
9180# Therefore, is an INF w/ the proper sign.
9181# So, determine the sign and return a new INF (w/ the j-bit cleared).
9182#
9183        global          fdiv_inf_load           # global for fsgldiv
9184fdiv_inf_load:
9185        ori.w           &dz_mask+adz_mask,2+USER_FPSR(%a6) # no; set DZ/ADZ
9186        mov.b           SRC_EX(%a0),%d0         # load both signs
9187        mov.b           DST_EX(%a1),%d1
9188        eor.b           %d0,%d1
9189        bpl.b           fdiv_inf_load_p         # result is positive
9190        fmov.s          &0xff800000,%fp0        # make result -INF
9191        mov.b           &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/N
9192        rts
9193fdiv_inf_load_p:
9194        fmov.s          &0x7f800000,%fp0        # make result +INF
9195        mov.b           &inf_bmask,FPSR_CC(%a6) # set INF
9196        rts
9197
9198#
9199# The destination was an INF w/ an In Range or ZERO source, the result is
9200# an INF w/ the proper sign.
9201# The 68881/882 returns the destination INF w/ the new sign(if the j-bit of the
9202# dst INF is set, then then j-bit of the result INF is also set).
9203#
9204        global          fdiv_inf_dst            # global for fsgldiv
9205fdiv_inf_dst:
9206        mov.b           DST_EX(%a1),%d0         # load both signs
9207        mov.b           SRC_EX(%a0),%d1
9208        eor.b           %d0,%d1
9209        bpl.b           fdiv_inf_dst_p          # result is positive
9210
9211        fmovm.x         DST(%a1),&0x80          # return result in fp0
9212        fabs.x          %fp0                    # clear sign bit
9213        fneg.x          %fp0                    # set sign bit
9214        mov.b           &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/NEG
9215        rts
9216
9217fdiv_inf_dst_p:
9218        fmovm.x         DST(%a1),&0x80          # return result in fp0
9219        fabs.x          %fp0                    # return positive INF
9220        mov.b           &inf_bmask,FPSR_CC(%a6) # set INF
9221        rts
9222
9223#########################################################################
9224# XDEF **************************************************************** #
9225#       fneg(): emulates the fneg instruction                           #
9226#       fsneg(): emulates the fsneg instruction                         #
9227#       fdneg(): emulates the fdneg instruction                         #
9228#                                                                       #
9229# XREF **************************************************************** #
9230#       norm() - normalize a denorm to provide EXOP                     #
9231#       scale_to_zero_src() - scale sgl/dbl source exponent             #
9232#       ovf_res() - return default overflow result                      #
9233#       unf_res() - return default underflow result                     #
9234#       res_qnan_1op() - return QNAN result                             #
9235#       res_snan_1op() - return SNAN result                             #
9236#                                                                       #
9237# INPUT *************************************************************** #
9238#       a0 = pointer to extended precision source operand               #
9239#       d0 = rnd prec,mode                                              #
9240#                                                                       #
9241# OUTPUT ************************************************************** #
9242#       fp0 = result                                                    #
9243#       fp1 = EXOP (if exception occurred)                              #
9244#                                                                       #
9245# ALGORITHM *********************************************************** #
9246#       Handle NANs, zeroes, and infinities as special cases. Separate  #
9247# norms/denorms into ext/sgl/dbl precisions. Extended precision can be  #
9248# emulated by simply setting sign bit. Sgl/dbl operands must be scaled  #
9249# and an actual fneg performed to see if overflow/underflow would have  #
9250# occurred. If so, return default underflow/overflow result. Else,      #
9251# scale the result exponent and return result. FPSR gets set based on   #
9252# the result value.                                                     #
9253#                                                                       #
9254#########################################################################
9255
9256        global          fsneg
9257fsneg:
9258        andi.b          &0x30,%d0               # clear rnd prec
9259        ori.b           &s_mode*0x10,%d0        # insert sgl precision
9260        bra.b           fneg
9261
9262        global          fdneg
9263fdneg:
9264        andi.b          &0x30,%d0               # clear rnd prec
9265        ori.b           &d_mode*0x10,%d0        # insert dbl prec
9266
9267        global          fneg
9268fneg:
9269        mov.l           %d0,L_SCR3(%a6)         # store rnd info
9270        mov.b           STAG(%a6),%d1
9271        bne.w           fneg_not_norm           # optimize on non-norm input
9272
9273#
9274# NEGATE SIGN : norms and denorms ONLY!
9275#
9276fneg_norm:
9277        andi.b          &0xc0,%d0               # is precision extended?
9278        bne.w           fneg_not_ext            # no; go handle sgl or dbl
9279
9280#
9281# precision selected is extended. so...we can not get an underflow
9282# or overflow because of rounding to the correct precision. so...
9283# skip the scaling and unscaling...
9284#
9285        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
9286        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
9287        mov.w           SRC_EX(%a0),%d0
9288        eori.w          &0x8000,%d0             # negate sign
9289        bpl.b           fneg_norm_load          # sign is positive
9290        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
9291fneg_norm_load:
9292        mov.w           %d0,FP_SCR0_EX(%a6)
9293        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
9294        rts
9295
9296#
9297# for an extended precision DENORM, the UNFL exception bit is set
9298# the accrued bit is NOT set in this instance(no inexactness!)
9299#
9300fneg_denorm:
9301        andi.b          &0xc0,%d0               # is precision extended?
9302        bne.b           fneg_not_ext            # no; go handle sgl or dbl
9303
9304        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
9305
9306        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
9307        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
9308        mov.w           SRC_EX(%a0),%d0
9309        eori.w          &0x8000,%d0             # negate sign
9310        bpl.b           fneg_denorm_done        # no
9311        mov.b           &neg_bmask,FPSR_CC(%a6) # yes, set 'N' ccode bit
9312fneg_denorm_done:
9313        mov.w           %d0,FP_SCR0_EX(%a6)
9314        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
9315
9316        btst            &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled?
9317        bne.b           fneg_ext_unfl_ena       # yes
9318        rts
9319
9320#
9321# the input is an extended DENORM and underflow is enabled in the FPCR.
9322# normalize the mantissa and add the bias of 0x6000 to the resulting negative
9323# exponent and insert back into the operand.
9324#
9325fneg_ext_unfl_ena:
9326        lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
9327        bsr.l           norm                    # normalize result
9328        neg.w           %d0                     # new exponent = -(shft val)
9329        addi.w          &0x6000,%d0             # add new bias to exponent
9330        mov.w           FP_SCR0_EX(%a6),%d1     # fetch old sign,exp
9331        andi.w          &0x8000,%d1             # keep old sign
9332        andi.w          &0x7fff,%d0             # clear sign position
9333        or.w            %d1,%d0                 # concat old sign, new exponent
9334        mov.w           %d0,FP_SCR0_EX(%a6)     # insert new exponent
9335        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
9336        rts
9337
9338#
9339# operand is either single or double
9340#
9341fneg_not_ext:
9342        cmpi.b          %d0,&s_mode*0x10        # separate sgl/dbl prec
9343        bne.b           fneg_dbl
9344
9345#
9346# operand is to be rounded to single precision
9347#
9348fneg_sgl:
9349        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
9350        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
9351        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
9352        bsr.l           scale_to_zero_src       # calculate scale factor
9353
9354        cmpi.l          %d0,&0x3fff-0x3f80      # will move in underflow?
9355        bge.w           fneg_sd_unfl            # yes; go handle underflow
9356        cmpi.l          %d0,&0x3fff-0x407e      # will move in overflow?
9357        beq.w           fneg_sd_may_ovfl        # maybe; go check
9358        blt.w           fneg_sd_ovfl            # yes; go handle overflow
9359
9360#
9361# operand will NOT overflow or underflow when moved in to the fp reg file
9362#
9363fneg_sd_normal:
9364        fmov.l          &0x0,%fpsr              # clear FPSR
9365        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
9366
9367        fneg.x          FP_SCR0(%a6),%fp0       # perform negation
9368
9369        fmov.l          %fpsr,%d1               # save FPSR
9370        fmov.l          &0x0,%fpcr              # clear FPCR
9371
9372        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
9373
9374fneg_sd_normal_exit:
9375        mov.l           %d2,-(%sp)              # save d2
9376        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
9377        mov.w           FP_SCR0_EX(%a6),%d1     # load sgn,exp
9378        mov.w           %d1,%d2                 # make a copy
9379        andi.l          &0x7fff,%d1             # strip sign
9380        sub.l           %d0,%d1                 # add scale factor
9381        andi.w          &0x8000,%d2             # keep old sign
9382        or.w            %d1,%d2                 # concat old sign,new exp
9383        mov.w           %d2,FP_SCR0_EX(%a6)     # insert new exponent
9384        mov.l           (%sp)+,%d2              # restore d2
9385        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
9386        rts
9387
9388#
9389# operand is to be rounded to double precision
9390#
9391fneg_dbl:
9392        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
9393        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
9394        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
9395        bsr.l           scale_to_zero_src       # calculate scale factor
9396
9397        cmpi.l          %d0,&0x3fff-0x3c00      # will move in underflow?
9398        bge.b           fneg_sd_unfl            # yes; go handle underflow
9399        cmpi.l          %d0,&0x3fff-0x43fe      # will move in overflow?
9400        beq.w           fneg_sd_may_ovfl        # maybe; go check
9401        blt.w           fneg_sd_ovfl            # yes; go handle overflow
9402        bra.w           fneg_sd_normal          # no; ho handle normalized op
9403
9404#
9405# operand WILL underflow when moved in to the fp register file
9406#
9407fneg_sd_unfl:
9408        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
9409
9410        eori.b          &0x80,FP_SCR0_EX(%a6)   # negate sign
9411        bpl.b           fneg_sd_unfl_tst
9412        bset            &neg_bit,FPSR_CC(%a6)   # set 'N' ccode bit
9413
9414# if underflow or inexact is enabled, go calculate EXOP first.
9415fneg_sd_unfl_tst:
9416        mov.b           FPCR_ENABLE(%a6),%d1
9417        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
9418        bne.b           fneg_sd_unfl_ena        # yes
9419
9420fneg_sd_unfl_dis:
9421        lea             FP_SCR0(%a6),%a0        # pass: result addr
9422        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
9423        bsr.l           unf_res                 # calculate default result
9424        or.b            %d0,FPSR_CC(%a6)        # unf_res may have set 'Z'
9425        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
9426        rts
9427
9428#
9429# operand will underflow AND underflow is enabled.
9430# Therefore, we must return the result rounded to extended precision.
9431#
9432fneg_sd_unfl_ena:
9433        mov.l           FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
9434        mov.l           FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
9435        mov.w           FP_SCR0_EX(%a6),%d1     # load current exponent
9436
9437        mov.l           %d2,-(%sp)              # save d2
9438        mov.l           %d1,%d2                 # make a copy
9439        andi.l          &0x7fff,%d1             # strip sign
9440        andi.w          &0x8000,%d2             # keep old sign
9441        sub.l           %d0,%d1                 # subtract scale factor
9442        addi.l          &0x6000,%d1             # add new bias
9443        andi.w          &0x7fff,%d1
9444        or.w            %d2,%d1                 # concat new sign,new exp
9445        mov.w           %d1,FP_SCR1_EX(%a6)     # insert new exp
9446        fmovm.x         FP_SCR1(%a6),&0x40      # return EXOP in fp1
9447        mov.l           (%sp)+,%d2              # restore d2
9448        bra.b           fneg_sd_unfl_dis
9449
9450#
9451# operand WILL overflow.
9452#
9453fneg_sd_ovfl:
9454        fmov.l          &0x0,%fpsr              # clear FPSR
9455        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
9456
9457        fneg.x          FP_SCR0(%a6),%fp0       # perform negation
9458
9459        fmov.l          &0x0,%fpcr              # clear FPCR
9460        fmov.l          %fpsr,%d1               # save FPSR
9461
9462        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
9463
9464fneg_sd_ovfl_tst:
9465        or.l            &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
9466
9467        mov.b           FPCR_ENABLE(%a6),%d1
9468        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
9469        bne.b           fneg_sd_ovfl_ena        # yes
9470
9471#
9472# OVFL is not enabled; therefore, we must create the default result by
9473# calling ovf_res().
9474#
9475fneg_sd_ovfl_dis:
9476        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
9477        sne             %d1                     # set sign param accordingly
9478        mov.l           L_SCR3(%a6),%d0         # pass: prec,mode
9479        bsr.l           ovf_res                 # calculate default result
9480        or.b            %d0,FPSR_CC(%a6)        # set INF,N if applicable
9481        fmovm.x         (%a0),&0x80             # return default result in fp0
9482        rts
9483
9484#
9485# OVFL is enabled.
9486# the INEX2 bit has already been updated by the round to the correct precision.
9487# now, round to extended(and don't alter the FPSR).
9488#
9489fneg_sd_ovfl_ena:
9490        mov.l           %d2,-(%sp)              # save d2
9491        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
9492        mov.l           %d1,%d2                 # make a copy
9493        andi.l          &0x7fff,%d1             # strip sign
9494        andi.w          &0x8000,%d2             # keep old sign
9495        sub.l           %d0,%d1                 # add scale factor
9496        subi.l          &0x6000,%d1             # subtract bias
9497        andi.w          &0x7fff,%d1
9498        or.w            %d2,%d1                 # concat sign,exp
9499        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
9500        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
9501        mov.l           (%sp)+,%d2              # restore d2
9502        bra.b           fneg_sd_ovfl_dis
9503
9504#
9505# the move in MAY underflow. so...
9506#
9507fneg_sd_may_ovfl:
9508        fmov.l          &0x0,%fpsr              # clear FPSR
9509        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
9510
9511        fneg.x          FP_SCR0(%a6),%fp0       # perform negation
9512
9513        fmov.l          %fpsr,%d1               # save status
9514        fmov.l          &0x0,%fpcr              # clear FPCR
9515
9516        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
9517
9518        fabs.x          %fp0,%fp1               # make a copy of result
9519        fcmp.b          %fp1,&0x2               # is |result| >= 2.b?
9520        fbge.w          fneg_sd_ovfl_tst        # yes; overflow has occurred
9521
9522# no, it didn't overflow; we have correct result
9523        bra.w           fneg_sd_normal_exit
9524
9525##########################################################################
9526
9527#
9528# input is not normalized; what is it?
9529#
9530fneg_not_norm:
9531        cmpi.b          %d1,&DENORM             # weed out DENORM
9532        beq.w           fneg_denorm
9533        cmpi.b          %d1,&SNAN               # weed out SNAN
9534        beq.l           res_snan_1op
9535        cmpi.b          %d1,&QNAN               # weed out QNAN
9536        beq.l           res_qnan_1op
9537
9538#
9539# do the fneg; at this point, only possible ops are ZERO and INF.
9540# use fneg to determine ccodes.
9541# prec:mode should be zero at this point but it won't affect answer anyways.
9542#
9543        fneg.x          SRC_EX(%a0),%fp0        # do fneg
9544        fmov.l          %fpsr,%d0
9545        rol.l           &0x8,%d0                # put ccodes in lo byte
9546        mov.b           %d0,FPSR_CC(%a6)        # insert correct ccodes
9547        rts
9548
9549#########################################################################
9550# XDEF **************************************************************** #
9551#       ftst(): emulates the ftest instruction                          #
9552#                                                                       #
9553# XREF **************************************************************** #
9554#       res{s,q}nan_1op() - set NAN result for monadic instruction      #
9555#                                                                       #
9556# INPUT *************************************************************** #
9557#       a0 = pointer to extended precision source operand               #
9558#                                                                       #
9559# OUTPUT ************************************************************** #
9560#       none                                                            #
9561#                                                                       #
9562# ALGORITHM *********************************************************** #
9563#       Check the source operand tag (STAG) and set the FPCR according  #
9564# to the operand type and sign.                                         #
9565#                                                                       #
9566#########################################################################
9567
9568        global          ftst
9569ftst:
9570        mov.b           STAG(%a6),%d1
9571        bne.b           ftst_not_norm           # optimize on non-norm input
9572
9573#
9574# Norm:
9575#
9576ftst_norm:
9577        tst.b           SRC_EX(%a0)             # is operand negative?
9578        bmi.b           ftst_norm_m             # yes
9579        rts
9580ftst_norm_m:
9581        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
9582        rts
9583
9584#
9585# input is not normalized; what is it?
9586#
9587ftst_not_norm:
9588        cmpi.b          %d1,&ZERO               # weed out ZERO
9589        beq.b           ftst_zero
9590        cmpi.b          %d1,&INF                # weed out INF
9591        beq.b           ftst_inf
9592        cmpi.b          %d1,&SNAN               # weed out SNAN
9593        beq.l           res_snan_1op
9594        cmpi.b          %d1,&QNAN               # weed out QNAN
9595        beq.l           res_qnan_1op
9596
9597#
9598# Denorm:
9599#
9600ftst_denorm:
9601        tst.b           SRC_EX(%a0)             # is operand negative?
9602        bmi.b           ftst_denorm_m           # yes
9603        rts
9604ftst_denorm_m:
9605        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
9606        rts
9607
9608#
9609# Infinity:
9610#
9611ftst_inf:
9612        tst.b           SRC_EX(%a0)             # is operand negative?
9613        bmi.b           ftst_inf_m              # yes
9614ftst_inf_p:
9615        mov.b           &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
9616        rts
9617ftst_inf_m:
9618        mov.b           &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'I','N' ccode bits
9619        rts
9620
9621#
9622# Zero:
9623#
9624ftst_zero:
9625        tst.b           SRC_EX(%a0)             # is operand negative?
9626        bmi.b           ftst_zero_m             # yes
9627ftst_zero_p:
9628        mov.b           &z_bmask,FPSR_CC(%a6)   # set 'N' ccode bit
9629        rts
9630ftst_zero_m:
9631        mov.b           &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
9632        rts
9633
9634#########################################################################
9635# XDEF **************************************************************** #
9636#       fint(): emulates the fint instruction                           #
9637#                                                                       #
9638# XREF **************************************************************** #
9639#       res_{s,q}nan_1op() - set NAN result for monadic operation       #
9640#                                                                       #
9641# INPUT *************************************************************** #
9642#       a0 = pointer to extended precision source operand               #
9643#       d0 = round precision/mode                                       #
9644#                                                                       #
9645# OUTPUT ************************************************************** #
9646#       fp0 = result                                                    #
9647#                                                                       #
9648# ALGORITHM *********************************************************** #
9649#       Separate according to operand type. Unnorms don't pass through  #
9650# here. For norms, load the rounding mode/prec, execute a "fint", then  #
9651# store the resulting FPSR bits.                                        #
9652#       For denorms, force the j-bit to a one and do the same as for    #
9653# norms. Denorms are so low that the answer will either be a zero or a  #
9654# one.                                                                  #
9655#       For zeroes/infs/NANs, return the same while setting the FPSR    #
9656# as appropriate.                                                       #
9657#                                                                       #
9658#########################################################################
9659
9660        global          fint
9661fint:
9662        mov.b           STAG(%a6),%d1
9663        bne.b           fint_not_norm           # optimize on non-norm input
9664
9665#
9666# Norm:
9667#
9668fint_norm:
9669        andi.b          &0x30,%d0               # set prec = ext
9670
9671        fmov.l          %d0,%fpcr               # set FPCR
9672        fmov.l          &0x0,%fpsr              # clear FPSR
9673
9674        fint.x          SRC(%a0),%fp0           # execute fint
9675
9676        fmov.l          &0x0,%fpcr              # clear FPCR
9677        fmov.l          %fpsr,%d0               # save FPSR
9678        or.l            %d0,USER_FPSR(%a6)      # set exception bits
9679
9680        rts
9681
9682#
9683# input is not normalized; what is it?
9684#
9685fint_not_norm:
9686        cmpi.b          %d1,&ZERO               # weed out ZERO
9687        beq.b           fint_zero
9688        cmpi.b          %d1,&INF                # weed out INF
9689        beq.b           fint_inf
9690        cmpi.b          %d1,&DENORM             # weed out DENORM
9691        beq.b           fint_denorm
9692        cmpi.b          %d1,&SNAN               # weed out SNAN
9693        beq.l           res_snan_1op
9694        bra.l           res_qnan_1op            # weed out QNAN
9695
9696#
9697# Denorm:
9698#
9699# for DENORMs, the result will be either (+/-)ZERO or (+/-)1.
9700# also, the INEX2 and AINEX exception bits will be set.
9701# so, we could either set these manually or force the DENORM
9702# to a very small NORM and ship it to the NORM routine.
9703# I do the latter.
9704#
9705fint_denorm:
9706        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6) # copy sign, zero exp
9707        mov.b           &0x80,FP_SCR0_HI(%a6)   # force DENORM ==> small NORM
9708        lea             FP_SCR0(%a6),%a0
9709        bra.b           fint_norm
9710
9711#
9712# Zero:
9713#
9714fint_zero:
9715        tst.b           SRC_EX(%a0)             # is ZERO negative?
9716        bmi.b           fint_zero_m             # yes
9717fint_zero_p:
9718        fmov.s          &0x00000000,%fp0        # return +ZERO in fp0
9719        mov.b           &z_bmask,FPSR_CC(%a6)   # set 'Z' ccode bit
9720        rts
9721fint_zero_m:
9722        fmov.s          &0x80000000,%fp0        # return -ZERO in fp0
9723        mov.b           &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
9724        rts
9725
9726#
9727# Infinity:
9728#
9729fint_inf:
9730        fmovm.x         SRC(%a0),&0x80          # return result in fp0
9731        tst.b           SRC_EX(%a0)             # is INF negative?
9732        bmi.b           fint_inf_m              # yes
9733fint_inf_p:
9734        mov.b           &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
9735        rts
9736fint_inf_m:
9737        mov.b           &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits
9738        rts
9739
9740#########################################################################
9741# XDEF **************************************************************** #
9742#       fintrz(): emulates the fintrz instruction                       #
9743#                                                                       #
9744# XREF **************************************************************** #
9745#       res_{s,q}nan_1op() - set NAN result for monadic operation       #
9746#                                                                       #
9747# INPUT *************************************************************** #
9748#       a0 = pointer to extended precision source operand               #
9749#       d0 = round precision/mode                                       #
9750#                                                                       #
9751# OUTPUT ************************************************************** #
9752#       fp0 = result                                                    #
9753#                                                                       #
9754# ALGORITHM *********************************************************** #
9755#       Separate according to operand type. Unnorms don't pass through  #
9756# here. For norms, load the rounding mode/prec, execute a "fintrz",     #
9757# then store the resulting FPSR bits.                                   #
9758#       For denorms, force the j-bit to a one and do the same as for    #
9759# norms. Denorms are so low that the answer will either be a zero or a  #
9760# one.                                                                  #
9761#       For zeroes/infs/NANs, return the same while setting the FPSR    #
9762# as appropriate.                                                       #
9763#                                                                       #
9764#########################################################################
9765
9766        global          fintrz
9767fintrz:
9768        mov.b           STAG(%a6),%d1
9769        bne.b           fintrz_not_norm         # optimize on non-norm input
9770
9771#
9772# Norm:
9773#
9774fintrz_norm:
9775        fmov.l          &0x0,%fpsr              # clear FPSR
9776
9777        fintrz.x        SRC(%a0),%fp0           # execute fintrz
9778
9779        fmov.l          %fpsr,%d0               # save FPSR
9780        or.l            %d0,USER_FPSR(%a6)      # set exception bits
9781
9782        rts
9783
9784#
9785# input is not normalized; what is it?
9786#
9787fintrz_not_norm:
9788        cmpi.b          %d1,&ZERO               # weed out ZERO
9789        beq.b           fintrz_zero
9790        cmpi.b          %d1,&INF                # weed out INF
9791        beq.b           fintrz_inf
9792        cmpi.b          %d1,&DENORM             # weed out DENORM
9793        beq.b           fintrz_denorm
9794        cmpi.b          %d1,&SNAN               # weed out SNAN
9795        beq.l           res_snan_1op
9796        bra.l           res_qnan_1op            # weed out QNAN
9797
9798#
9799# Denorm:
9800#
9801# for DENORMs, the result will be (+/-)ZERO.
9802# also, the INEX2 and AINEX exception bits will be set.
9803# so, we could either set these manually or force the DENORM
9804# to a very small NORM and ship it to the NORM routine.
9805# I do the latter.
9806#
9807fintrz_denorm:
9808        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6) # copy sign, zero exp
9809        mov.b           &0x80,FP_SCR0_HI(%a6)   # force DENORM ==> small NORM
9810        lea             FP_SCR0(%a6),%a0
9811        bra.b           fintrz_norm
9812
9813#
9814# Zero:
9815#
9816fintrz_zero:
9817        tst.b           SRC_EX(%a0)             # is ZERO negative?
9818        bmi.b           fintrz_zero_m           # yes
9819fintrz_zero_p:
9820        fmov.s          &0x00000000,%fp0        # return +ZERO in fp0
9821        mov.b           &z_bmask,FPSR_CC(%a6)   # set 'Z' ccode bit
9822        rts
9823fintrz_zero_m:
9824        fmov.s          &0x80000000,%fp0        # return -ZERO in fp0
9825        mov.b           &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
9826        rts
9827
9828#
9829# Infinity:
9830#
9831fintrz_inf:
9832        fmovm.x         SRC(%a0),&0x80          # return result in fp0
9833        tst.b           SRC_EX(%a0)             # is INF negative?
9834        bmi.b           fintrz_inf_m            # yes
9835fintrz_inf_p:
9836        mov.b           &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
9837        rts
9838fintrz_inf_m:
9839        mov.b           &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits
9840        rts
9841
9842#########################################################################
9843# XDEF **************************************************************** #
9844#       fabs():  emulates the fabs instruction                          #
9845#       fsabs(): emulates the fsabs instruction                         #
9846#       fdabs(): emulates the fdabs instruction                         #
9847#                                                                       #
9848# XREF **************************************************************** #
9849#       norm() - normalize denorm mantissa to provide EXOP              #
9850#       scale_to_zero_src() - make exponent. = 0; get scale factor      #
9851#       unf_res() - calculate underflow result                          #
9852#       ovf_res() - calculate overflow result                           #
9853#       res_{s,q}nan_1op() - set NAN result for monadic operation       #
9854#                                                                       #
9855# INPUT *************************************************************** #
9856#       a0 = pointer to extended precision source operand               #
9857#       d0 = rnd precision/mode                                         #
9858#                                                                       #
9859# OUTPUT ************************************************************** #
9860#       fp0 = result                                                    #
9861#       fp1 = EXOP (if exception occurred)                              #
9862#                                                                       #
9863# ALGORITHM *********************************************************** #
9864#       Handle NANs, infinities, and zeroes as special cases. Divide    #
9865# norms into extended, single, and double precision.                    #
9866#       Simply clear sign for extended precision norm. Ext prec denorm  #
9867# gets an EXOP created for it since it's an underflow.                  #
9868#       Double and single precision can overflow and underflow. First,  #
9869# scale the operand such that the exponent is zero. Perform an "fabs"   #
9870# using the correct rnd mode/prec. Check to see if the original         #
9871# exponent would take an exception. If so, use unf_res() or ovf_res()   #
9872# to calculate the default result. Also, create the EXOP for the        #
9873# exceptional case. If no exception should occur, insert the correct    #
9874# result exponent and return.                                           #
9875#       Unnorms don't pass through here.                                #
9876#                                                                       #
9877#########################################################################
9878
9879        global          fsabs
9880fsabs:
9881        andi.b          &0x30,%d0               # clear rnd prec
9882        ori.b           &s_mode*0x10,%d0        # insert sgl precision
9883        bra.b           fabs
9884
9885        global          fdabs
9886fdabs:
9887        andi.b          &0x30,%d0               # clear rnd prec
9888        ori.b           &d_mode*0x10,%d0        # insert dbl precision
9889
9890        global          fabs
9891fabs:
9892        mov.l           %d0,L_SCR3(%a6)         # store rnd info
9893        mov.b           STAG(%a6),%d1
9894        bne.w           fabs_not_norm           # optimize on non-norm input
9895
9896#
9897# ABSOLUTE VALUE: norms and denorms ONLY!
9898#
9899fabs_norm:
9900        andi.b          &0xc0,%d0               # is precision extended?
9901        bne.b           fabs_not_ext            # no; go handle sgl or dbl
9902
9903#
9904# precision selected is extended. so...we can not get an underflow
9905# or overflow because of rounding to the correct precision. so...
9906# skip the scaling and unscaling...
9907#
9908        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
9909        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
9910        mov.w           SRC_EX(%a0),%d1
9911        bclr            &15,%d1                 # force absolute value
9912        mov.w           %d1,FP_SCR0_EX(%a6)     # insert exponent
9913        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
9914        rts
9915
9916#
9917# for an extended precision DENORM, the UNFL exception bit is set
9918# the accrued bit is NOT set in this instance(no inexactness!)
9919#
9920fabs_denorm:
9921        andi.b          &0xc0,%d0               # is precision extended?
9922        bne.b           fabs_not_ext            # no
9923
9924        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
9925
9926        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
9927        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
9928        mov.w           SRC_EX(%a0),%d0
9929        bclr            &15,%d0                 # clear sign
9930        mov.w           %d0,FP_SCR0_EX(%a6)     # insert exponent
9931
9932        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
9933
9934        btst            &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled?
9935        bne.b           fabs_ext_unfl_ena
9936        rts
9937
9938#
9939# the input is an extended DENORM and underflow is enabled in the FPCR.
9940# normalize the mantissa and add the bias of 0x6000 to the resulting negative
9941# exponent and insert back into the operand.
9942#
9943fabs_ext_unfl_ena:
9944        lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
9945        bsr.l           norm                    # normalize result
9946        neg.w           %d0                     # new exponent = -(shft val)
9947        addi.w          &0x6000,%d0             # add new bias to exponent
9948        mov.w           FP_SCR0_EX(%a6),%d1     # fetch old sign,exp
9949        andi.w          &0x8000,%d1             # keep old sign
9950        andi.w          &0x7fff,%d0             # clear sign position
9951        or.w            %d1,%d0                 # concat old sign, new exponent
9952        mov.w           %d0,FP_SCR0_EX(%a6)     # insert new exponent
9953        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
9954        rts
9955
9956#
9957# operand is either single or double
9958#
9959fabs_not_ext:
9960        cmpi.b          %d0,&s_mode*0x10        # separate sgl/dbl prec
9961        bne.b           fabs_dbl
9962
9963#
9964# operand is to be rounded to single precision
9965#
9966fabs_sgl:
9967        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
9968        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
9969        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
9970        bsr.l           scale_to_zero_src       # calculate scale factor
9971
9972        cmpi.l          %d0,&0x3fff-0x3f80      # will move in underflow?
9973        bge.w           fabs_sd_unfl            # yes; go handle underflow
9974        cmpi.l          %d0,&0x3fff-0x407e      # will move in overflow?
9975        beq.w           fabs_sd_may_ovfl        # maybe; go check
9976        blt.w           fabs_sd_ovfl            # yes; go handle overflow
9977
9978#
9979# operand will NOT overflow or underflow when moved in to the fp reg file
9980#
9981fabs_sd_normal:
9982        fmov.l          &0x0,%fpsr              # clear FPSR
9983        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
9984
9985        fabs.x          FP_SCR0(%a6),%fp0       # perform absolute
9986
9987        fmov.l          %fpsr,%d1               # save FPSR
9988        fmov.l          &0x0,%fpcr              # clear FPCR
9989
9990        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
9991
9992fabs_sd_normal_exit:
9993        mov.l           %d2,-(%sp)              # save d2
9994        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
9995        mov.w           FP_SCR0_EX(%a6),%d1     # load sgn,exp
9996        mov.l           %d1,%d2                 # make a copy
9997        andi.l          &0x7fff,%d1             # strip sign
9998        sub.l           %d0,%d1                 # add scale factor
9999        andi.w          &0x8000,%d2             # keep old sign
10000        or.w            %d1,%d2                 # concat old sign,new exp
10001        mov.w           %d2,FP_SCR0_EX(%a6)     # insert new exponent
10002        mov.l           (%sp)+,%d2              # restore d2
10003        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
10004        rts
10005
10006#
10007# operand is to be rounded to double precision
10008#
10009fabs_dbl:
10010        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
10011        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
10012        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
10013        bsr.l           scale_to_zero_src       # calculate scale factor
10014
10015        cmpi.l          %d0,&0x3fff-0x3c00      # will move in underflow?
10016        bge.b           fabs_sd_unfl            # yes; go handle underflow
10017        cmpi.l          %d0,&0x3fff-0x43fe      # will move in overflow?
10018        beq.w           fabs_sd_may_ovfl        # maybe; go check
10019        blt.w           fabs_sd_ovfl            # yes; go handle overflow
10020        bra.w           fabs_sd_normal          # no; ho handle normalized op
10021
10022#
10023# operand WILL underflow when moved in to the fp register file
10024#
10025fabs_sd_unfl:
10026        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
10027
10028        bclr            &0x7,FP_SCR0_EX(%a6)    # force absolute value
10029
10030# if underflow or inexact is enabled, go calculate EXOP first.
10031        mov.b           FPCR_ENABLE(%a6),%d1
10032        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
10033        bne.b           fabs_sd_unfl_ena        # yes
10034
10035fabs_sd_unfl_dis:
10036        lea             FP_SCR0(%a6),%a0        # pass: result addr
10037        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
10038        bsr.l           unf_res                 # calculate default result
10039        or.b            %d0,FPSR_CC(%a6)        # set possible 'Z' ccode
10040        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
10041        rts
10042
10043#
10044# operand will underflow AND underflow is enabled.
10045# Therefore, we must return the result rounded to extended precision.
10046#
10047fabs_sd_unfl_ena:
10048        mov.l           FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
10049        mov.l           FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
10050        mov.w           FP_SCR0_EX(%a6),%d1     # load current exponent
10051
10052        mov.l           %d2,-(%sp)              # save d2
10053        mov.l           %d1,%d2                 # make a copy
10054        andi.l          &0x7fff,%d1             # strip sign
10055        andi.w          &0x8000,%d2             # keep old sign
10056        sub.l           %d0,%d1                 # subtract scale factor
10057        addi.l          &0x6000,%d1             # add new bias
10058        andi.w          &0x7fff,%d1
10059        or.w            %d2,%d1                 # concat new sign,new exp
10060        mov.w           %d1,FP_SCR1_EX(%a6)     # insert new exp
10061        fmovm.x         FP_SCR1(%a6),&0x40      # return EXOP in fp1
10062        mov.l           (%sp)+,%d2              # restore d2
10063        bra.b           fabs_sd_unfl_dis
10064
10065#
10066# operand WILL overflow.
10067#
10068fabs_sd_ovfl:
10069        fmov.l          &0x0,%fpsr              # clear FPSR
10070        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
10071
10072        fabs.x          FP_SCR0(%a6),%fp0       # perform absolute
10073
10074        fmov.l          &0x0,%fpcr              # clear FPCR
10075        fmov.l          %fpsr,%d1               # save FPSR
10076
10077        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
10078
10079fabs_sd_ovfl_tst:
10080        or.l            &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
10081
10082        mov.b           FPCR_ENABLE(%a6),%d1
10083        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
10084        bne.b           fabs_sd_ovfl_ena        # yes
10085
10086#
10087# OVFL is not enabled; therefore, we must create the default result by
10088# calling ovf_res().
10089#
10090fabs_sd_ovfl_dis:
10091        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
10092        sne             %d1                     # set sign param accordingly
10093        mov.l           L_SCR3(%a6),%d0         # pass: prec,mode
10094        bsr.l           ovf_res                 # calculate default result
10095        or.b            %d0,FPSR_CC(%a6)        # set INF,N if applicable
10096        fmovm.x         (%a0),&0x80             # return default result in fp0
10097        rts
10098
10099#
10100# OVFL is enabled.
10101# the INEX2 bit has already been updated by the round to the correct precision.
10102# now, round to extended(and don't alter the FPSR).
10103#
10104fabs_sd_ovfl_ena:
10105        mov.l           %d2,-(%sp)              # save d2
10106        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
10107        mov.l           %d1,%d2                 # make a copy
10108        andi.l          &0x7fff,%d1             # strip sign
10109        andi.w          &0x8000,%d2             # keep old sign
10110        sub.l           %d0,%d1                 # add scale factor
10111        subi.l          &0x6000,%d1             # subtract bias
10112        andi.w          &0x7fff,%d1
10113        or.w            %d2,%d1                 # concat sign,exp
10114        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
10115        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
10116        mov.l           (%sp)+,%d2              # restore d2
10117        bra.b           fabs_sd_ovfl_dis
10118
10119#
10120# the move in MAY underflow. so...
10121#
10122fabs_sd_may_ovfl:
10123        fmov.l          &0x0,%fpsr              # clear FPSR
10124        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
10125
10126        fabs.x          FP_SCR0(%a6),%fp0       # perform absolute
10127
10128        fmov.l          %fpsr,%d1               # save status
10129        fmov.l          &0x0,%fpcr              # clear FPCR
10130
10131        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
10132
10133        fabs.x          %fp0,%fp1               # make a copy of result
10134        fcmp.b          %fp1,&0x2               # is |result| >= 2.b?
10135        fbge.w          fabs_sd_ovfl_tst        # yes; overflow has occurred
10136
10137# no, it didn't overflow; we have correct result
10138        bra.w           fabs_sd_normal_exit
10139
10140##########################################################################
10141
10142#
10143# input is not normalized; what is it?
10144#
10145fabs_not_norm:
10146        cmpi.b          %d1,&DENORM             # weed out DENORM
10147        beq.w           fabs_denorm
10148        cmpi.b          %d1,&SNAN               # weed out SNAN
10149        beq.l           res_snan_1op
10150        cmpi.b          %d1,&QNAN               # weed out QNAN
10151        beq.l           res_qnan_1op
10152
10153        fabs.x          SRC(%a0),%fp0           # force absolute value
10154
10155        cmpi.b          %d1,&INF                # weed out INF
10156        beq.b           fabs_inf
10157fabs_zero:
10158        mov.b           &z_bmask,FPSR_CC(%a6)   # set 'Z' ccode bit
10159        rts
10160fabs_inf:
10161        mov.b           &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
10162        rts
10163
10164#########################################################################
10165# XDEF **************************************************************** #
10166#       fcmp(): fp compare op routine                                   #
10167#                                                                       #
10168# XREF **************************************************************** #
10169#       res_qnan() - return QNAN result                                 #
10170#       res_snan() - return SNAN result                                 #
10171#                                                                       #
10172# INPUT *************************************************************** #
10173#       a0 = pointer to extended precision source operand               #
10174#       a1 = pointer to extended precision destination operand          #
10175#       d0 = round prec/mode                                            #
10176#                                                                       #
10177# OUTPUT ************************************************************** #
10178#       None                                                            #
10179#                                                                       #
10180# ALGORITHM *********************************************************** #
10181#       Handle NANs and denorms as special cases. For everything else,  #
10182# just use the actual fcmp instruction to produce the correct condition #
10183# codes.                                                                #
10184#                                                                       #
10185#########################################################################
10186
10187        global          fcmp
10188fcmp:
10189        clr.w           %d1
10190        mov.b           DTAG(%a6),%d1
10191        lsl.b           &0x3,%d1
10192        or.b            STAG(%a6),%d1
10193        bne.b           fcmp_not_norm           # optimize on non-norm input
10194
10195#
10196# COMPARE FP OPs : NORMs, ZEROs, INFs, and "corrected" DENORMs
10197#
10198fcmp_norm:
10199        fmovm.x         DST(%a1),&0x80          # load dst op
10200
10201        fcmp.x          %fp0,SRC(%a0)           # do compare
10202
10203        fmov.l          %fpsr,%d0               # save FPSR
10204        rol.l           &0x8,%d0                # extract ccode bits
10205        mov.b           %d0,FPSR_CC(%a6)        # set ccode bits(no exc bits are set)
10206
10207        rts
10208
10209#
10210# fcmp: inputs are not both normalized; what are they?
10211#
10212fcmp_not_norm:
10213        mov.w           (tbl_fcmp_op.b,%pc,%d1.w*2),%d1
10214        jmp             (tbl_fcmp_op.b,%pc,%d1.w*1)
10215
10216        swbeg           &48
10217tbl_fcmp_op:
10218        short           fcmp_norm       - tbl_fcmp_op # NORM - NORM
10219        short           fcmp_norm       - tbl_fcmp_op # NORM - ZERO
10220        short           fcmp_norm       - tbl_fcmp_op # NORM - INF
10221        short           fcmp_res_qnan   - tbl_fcmp_op # NORM - QNAN
10222        short           fcmp_nrm_dnrm   - tbl_fcmp_op # NORM - DENORM
10223        short           fcmp_res_snan   - tbl_fcmp_op # NORM - SNAN
10224        short           tbl_fcmp_op     - tbl_fcmp_op #
10225        short           tbl_fcmp_op     - tbl_fcmp_op #
10226
10227        short           fcmp_norm       - tbl_fcmp_op # ZERO - NORM
10228        short           fcmp_norm       - tbl_fcmp_op # ZERO - ZERO
10229        short           fcmp_norm       - tbl_fcmp_op # ZERO - INF
10230        short           fcmp_res_qnan   - tbl_fcmp_op # ZERO - QNAN
10231        short           fcmp_dnrm_s     - tbl_fcmp_op # ZERO - DENORM
10232        short           fcmp_res_snan   - tbl_fcmp_op # ZERO - SNAN
10233        short           tbl_fcmp_op     - tbl_fcmp_op #
10234        short           tbl_fcmp_op     - tbl_fcmp_op #
10235
10236        short           fcmp_norm       - tbl_fcmp_op # INF - NORM
10237        short           fcmp_norm       - tbl_fcmp_op # INF - ZERO
10238        short           fcmp_norm       - tbl_fcmp_op # INF - INF
10239        short           fcmp_res_qnan   - tbl_fcmp_op # INF - QNAN
10240        short           fcmp_dnrm_s     - tbl_fcmp_op # INF - DENORM
10241        short           fcmp_res_snan   - tbl_fcmp_op # INF - SNAN
10242        short           tbl_fcmp_op     - tbl_fcmp_op #
10243        short           tbl_fcmp_op     - tbl_fcmp_op #
10244
10245        short           fcmp_res_qnan   - tbl_fcmp_op # QNAN - NORM
10246        short           fcmp_res_qnan   - tbl_fcmp_op # QNAN - ZERO
10247        short           fcmp_res_qnan   - tbl_fcmp_op # QNAN - INF
10248        short           fcmp_res_qnan   - tbl_fcmp_op # QNAN - QNAN
10249        short           fcmp_res_qnan   - tbl_fcmp_op # QNAN - DENORM
10250        short           fcmp_res_snan   - tbl_fcmp_op # QNAN - SNAN
10251        short           tbl_fcmp_op     - tbl_fcmp_op #
10252        short           tbl_fcmp_op     - tbl_fcmp_op #
10253
10254        short           fcmp_dnrm_nrm   - tbl_fcmp_op # DENORM - NORM
10255        short           fcmp_dnrm_d     - tbl_fcmp_op # DENORM - ZERO
10256        short           fcmp_dnrm_d     - tbl_fcmp_op # DENORM - INF
10257        short           fcmp_res_qnan   - tbl_fcmp_op # DENORM - QNAN
10258        short           fcmp_dnrm_sd    - tbl_fcmp_op # DENORM - DENORM
10259        short           fcmp_res_snan   - tbl_fcmp_op # DENORM - SNAN
10260        short           tbl_fcmp_op     - tbl_fcmp_op #
10261        short           tbl_fcmp_op     - tbl_fcmp_op #
10262
10263        short           fcmp_res_snan   - tbl_fcmp_op # SNAN - NORM
10264        short           fcmp_res_snan   - tbl_fcmp_op # SNAN - ZERO
10265        short           fcmp_res_snan   - tbl_fcmp_op # SNAN - INF
10266        short           fcmp_res_snan   - tbl_fcmp_op # SNAN - QNAN
10267        short           fcmp_res_snan   - tbl_fcmp_op # SNAN - DENORM
10268        short           fcmp_res_snan   - tbl_fcmp_op # SNAN - SNAN
10269        short           tbl_fcmp_op     - tbl_fcmp_op #
10270        short           tbl_fcmp_op     - tbl_fcmp_op #
10271
10272# unlike all other functions for QNAN and SNAN, fcmp does NOT set the
10273# 'N' bit for a negative QNAN or SNAN input so we must squelch it here.
10274fcmp_res_qnan:
10275        bsr.l           res_qnan
10276        andi.b          &0xf7,FPSR_CC(%a6)
10277        rts
10278fcmp_res_snan:
10279        bsr.l           res_snan
10280        andi.b          &0xf7,FPSR_CC(%a6)
10281        rts
10282
10283#
10284# DENORMs are a little more difficult.
10285# If you have a 2 DENORMs, then you can just force the j-bit to a one
10286# and use the fcmp_norm routine.
10287# If you have a DENORM and an INF or ZERO, just force the DENORM's j-bit to a one
10288# and use the fcmp_norm routine.
10289# If you have a DENORM and a NORM with opposite signs, then use fcmp_norm, also.
10290# But with a DENORM and a NORM of the same sign, the neg bit is set if the
10291# (1) signs are (+) and the DENORM is the dst or
10292# (2) signs are (-) and the DENORM is the src
10293#
10294
10295fcmp_dnrm_s:
10296        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
10297        mov.l           SRC_HI(%a0),%d0
10298        bset            &31,%d0                 # DENORM src; make into small norm
10299        mov.l           %d0,FP_SCR0_HI(%a6)
10300        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
10301        lea             FP_SCR0(%a6),%a0
10302        bra.w           fcmp_norm
10303
10304fcmp_dnrm_d:
10305        mov.l           DST_EX(%a1),FP_SCR0_EX(%a6)
10306        mov.l           DST_HI(%a1),%d0
10307        bset            &31,%d0                 # DENORM src; make into small norm
10308        mov.l           %d0,FP_SCR0_HI(%a6)
10309        mov.l           DST_LO(%a1),FP_SCR0_LO(%a6)
10310        lea             FP_SCR0(%a6),%a1
10311        bra.w           fcmp_norm
10312
10313fcmp_dnrm_sd:
10314        mov.w           DST_EX(%a1),FP_SCR1_EX(%a6)
10315        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
10316        mov.l           DST_HI(%a1),%d0
10317        bset            &31,%d0                 # DENORM dst; make into small norm
10318        mov.l           %d0,FP_SCR1_HI(%a6)
10319        mov.l           SRC_HI(%a0),%d0
10320        bset            &31,%d0                 # DENORM dst; make into small norm
10321        mov.l           %d0,FP_SCR0_HI(%a6)
10322        mov.l           DST_LO(%a1),FP_SCR1_LO(%a6)
10323        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
10324        lea             FP_SCR1(%a6),%a1
10325        lea             FP_SCR0(%a6),%a0
10326        bra.w           fcmp_norm
10327
10328fcmp_nrm_dnrm:
10329        mov.b           SRC_EX(%a0),%d0         # determine if like signs
10330        mov.b           DST_EX(%a1),%d1
10331        eor.b           %d0,%d1
10332        bmi.w           fcmp_dnrm_s
10333
10334# signs are the same, so must determine the answer ourselves.
10335        tst.b           %d0                     # is src op negative?
10336        bmi.b           fcmp_nrm_dnrm_m         # yes
10337        rts
10338fcmp_nrm_dnrm_m:
10339        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'Z' ccode bit
10340        rts
10341
10342fcmp_dnrm_nrm:
10343        mov.b           SRC_EX(%a0),%d0         # determine if like signs
10344        mov.b           DST_EX(%a1),%d1
10345        eor.b           %d0,%d1
10346        bmi.w           fcmp_dnrm_d
10347
10348# signs are the same, so must determine the answer ourselves.
10349        tst.b           %d0                     # is src op negative?
10350        bpl.b           fcmp_dnrm_nrm_m         # no
10351        rts
10352fcmp_dnrm_nrm_m:
10353        mov.b           &neg_bmask,FPSR_CC(%a6) # set 'Z' ccode bit
10354        rts
10355
10356#########################################################################
10357# XDEF **************************************************************** #
10358#       fsglmul(): emulates the fsglmul instruction                     #
10359#                                                                       #
10360# XREF **************************************************************** #
10361#       scale_to_zero_src() - scale src exponent to zero                #
10362#       scale_to_zero_dst() - scale dst exponent to zero                #
10363#       unf_res4() - return default underflow result for sglop          #
10364#       ovf_res() - return default overflow result                      #
10365#       res_qnan() - return QNAN result                                 #
10366#       res_snan() - return SNAN result                                 #
10367#                                                                       #
10368# INPUT *************************************************************** #
10369#       a0 = pointer to extended precision source operand               #
10370#       a1 = pointer to extended precision destination operand          #
10371#       d0  rnd prec,mode                                               #
10372#                                                                       #
10373# OUTPUT ************************************************************** #
10374#       fp0 = result                                                    #
10375#       fp1 = EXOP (if exception occurred)                              #
10376#                                                                       #
10377# ALGORITHM *********************************************************** #
10378#       Handle NANs, infinities, and zeroes as special cases. Divide    #
10379# norms/denorms into ext/sgl/dbl precision.                             #
10380#       For norms/denorms, scale the exponents such that a multiply     #
10381# instruction won't cause an exception. Use the regular fsglmul to      #
10382# compute a result. Check if the regular operands would have taken      #
10383# an exception. If so, return the default overflow/underflow result     #
10384# and return the EXOP if exceptions are enabled. Else, scale the        #
10385# result operand to the proper exponent.                                #
10386#                                                                       #
10387#########################################################################
10388
10389        global          fsglmul
10390fsglmul:
10391        mov.l           %d0,L_SCR3(%a6)         # store rnd info
10392
10393        clr.w           %d1
10394        mov.b           DTAG(%a6),%d1
10395        lsl.b           &0x3,%d1
10396        or.b            STAG(%a6),%d1
10397
10398        bne.w           fsglmul_not_norm        # optimize on non-norm input
10399
10400fsglmul_norm:
10401        mov.w           DST_EX(%a1),FP_SCR1_EX(%a6)
10402        mov.l           DST_HI(%a1),FP_SCR1_HI(%a6)
10403        mov.l           DST_LO(%a1),FP_SCR1_LO(%a6)
10404
10405        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
10406        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
10407        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
10408
10409        bsr.l           scale_to_zero_src       # scale exponent
10410        mov.l           %d0,-(%sp)              # save scale factor 1
10411
10412        bsr.l           scale_to_zero_dst       # scale dst exponent
10413
10414        add.l           (%sp)+,%d0              # SCALE_FACTOR = scale1 + scale2
10415
10416        cmpi.l          %d0,&0x3fff-0x7ffe      # would result ovfl?
10417        beq.w           fsglmul_may_ovfl        # result may rnd to overflow
10418        blt.w           fsglmul_ovfl            # result will overflow
10419
10420        cmpi.l          %d0,&0x3fff+0x0001      # would result unfl?
10421        beq.w           fsglmul_may_unfl        # result may rnd to no unfl
10422        bgt.w           fsglmul_unfl            # result will underflow
10423
10424fsglmul_normal:
10425        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
10426
10427        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
10428        fmov.l          &0x0,%fpsr              # clear FPSR
10429
10430        fsglmul.x       FP_SCR0(%a6),%fp0       # execute sgl multiply
10431
10432        fmov.l          %fpsr,%d1               # save status
10433        fmov.l          &0x0,%fpcr              # clear FPCR
10434
10435        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
10436
10437fsglmul_normal_exit:
10438        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
10439        mov.l           %d2,-(%sp)              # save d2
10440        mov.w           FP_SCR0_EX(%a6),%d1     # load {sgn,exp}
10441        mov.l           %d1,%d2                 # make a copy
10442        andi.l          &0x7fff,%d1             # strip sign
10443        andi.w          &0x8000,%d2             # keep old sign
10444        sub.l           %d0,%d1                 # add scale factor
10445        or.w            %d2,%d1                 # concat old sign,new exp
10446        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
10447        mov.l           (%sp)+,%d2              # restore d2
10448        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
10449        rts
10450
10451fsglmul_ovfl:
10452        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
10453
10454        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
10455        fmov.l          &0x0,%fpsr              # clear FPSR
10456
10457        fsglmul.x       FP_SCR0(%a6),%fp0       # execute sgl multiply
10458
10459        fmov.l          %fpsr,%d1               # save status
10460        fmov.l          &0x0,%fpcr              # clear FPCR
10461
10462        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
10463
10464fsglmul_ovfl_tst:
10465
10466# save setting this until now because this is where fsglmul_may_ovfl may jump in
10467        or.l            &ovfl_inx_mask, USER_FPSR(%a6) # set ovfl/aovfl/ainex
10468
10469        mov.b           FPCR_ENABLE(%a6),%d1
10470        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
10471        bne.b           fsglmul_ovfl_ena        # yes
10472
10473fsglmul_ovfl_dis:
10474        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
10475        sne             %d1                     # set sign param accordingly
10476        mov.l           L_SCR3(%a6),%d0         # pass prec:rnd
10477        andi.b          &0x30,%d0               # force prec = ext
10478        bsr.l           ovf_res                 # calculate default result
10479        or.b            %d0,FPSR_CC(%a6)        # set INF,N if applicable
10480        fmovm.x         (%a0),&0x80             # return default result in fp0
10481        rts
10482
10483fsglmul_ovfl_ena:
10484        fmovm.x         &0x80,FP_SCR0(%a6)      # move result to stack
10485
10486        mov.l           %d2,-(%sp)              # save d2
10487        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
10488        mov.l           %d1,%d2                 # make a copy
10489        andi.l          &0x7fff,%d1             # strip sign
10490        sub.l           %d0,%d1                 # add scale factor
10491        subi.l          &0x6000,%d1             # subtract bias
10492        andi.w          &0x7fff,%d1
10493        andi.w          &0x8000,%d2             # keep old sign
10494        or.w            %d2,%d1                 # concat old sign,new exp
10495        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
10496        mov.l           (%sp)+,%d2              # restore d2
10497        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
10498        bra.b           fsglmul_ovfl_dis
10499
10500fsglmul_may_ovfl:
10501        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
10502
10503        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
10504        fmov.l          &0x0,%fpsr              # clear FPSR
10505
10506        fsglmul.x       FP_SCR0(%a6),%fp0       # execute sgl multiply
10507
10508        fmov.l          %fpsr,%d1               # save status
10509        fmov.l          &0x0,%fpcr              # clear FPCR
10510
10511        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
10512
10513        fabs.x          %fp0,%fp1               # make a copy of result
10514        fcmp.b          %fp1,&0x2               # is |result| >= 2.b?
10515        fbge.w          fsglmul_ovfl_tst        # yes; overflow has occurred
10516
10517# no, it didn't overflow; we have correct result
10518        bra.w           fsglmul_normal_exit
10519
10520fsglmul_unfl:
10521        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
10522
10523        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
10524
10525        fmov.l          &rz_mode*0x10,%fpcr     # set FPCR
10526        fmov.l          &0x0,%fpsr              # clear FPSR
10527
10528        fsglmul.x       FP_SCR0(%a6),%fp0       # execute sgl multiply
10529
10530        fmov.l          %fpsr,%d1               # save status
10531        fmov.l          &0x0,%fpcr              # clear FPCR
10532
10533        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
10534
10535        mov.b           FPCR_ENABLE(%a6),%d1
10536        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
10537        bne.b           fsglmul_unfl_ena        # yes
10538
10539fsglmul_unfl_dis:
10540        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
10541
10542        lea             FP_SCR0(%a6),%a0        # pass: result addr
10543        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
10544        bsr.l           unf_res4                # calculate default result
10545        or.b            %d0,FPSR_CC(%a6)        # 'Z' bit may have been set
10546        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
10547        rts
10548
10549#
10550# UNFL is enabled.
10551#
10552fsglmul_unfl_ena:
10553        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op
10554
10555        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
10556        fmov.l          &0x0,%fpsr              # clear FPSR
10557
10558        fsglmul.x       FP_SCR0(%a6),%fp1       # execute sgl multiply
10559
10560        fmov.l          &0x0,%fpcr              # clear FPCR
10561
10562        fmovm.x         &0x40,FP_SCR0(%a6)      # save result to stack
10563        mov.l           %d2,-(%sp)              # save d2
10564        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
10565        mov.l           %d1,%d2                 # make a copy
10566        andi.l          &0x7fff,%d1             # strip sign
10567        andi.w          &0x8000,%d2             # keep old sign
10568        sub.l           %d0,%d1                 # add scale factor
10569        addi.l          &0x6000,%d1             # add bias
10570        andi.w          &0x7fff,%d1
10571        or.w            %d2,%d1                 # concat old sign,new exp
10572        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
10573        mov.l           (%sp)+,%d2              # restore d2
10574        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
10575        bra.w           fsglmul_unfl_dis
10576
10577fsglmul_may_unfl:
10578        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
10579
10580        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
10581        fmov.l          &0x0,%fpsr              # clear FPSR
10582
10583        fsglmul.x       FP_SCR0(%a6),%fp0       # execute sgl multiply
10584
10585        fmov.l          %fpsr,%d1               # save status
10586        fmov.l          &0x0,%fpcr              # clear FPCR
10587
10588        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
10589
10590        fabs.x          %fp0,%fp1               # make a copy of result
10591        fcmp.b          %fp1,&0x2               # is |result| > 2.b?
10592        fbgt.w          fsglmul_normal_exit     # no; no underflow occurred
10593        fblt.w          fsglmul_unfl            # yes; underflow occurred
10594
10595#
10596# we still don't know if underflow occurred. result is ~ equal to 2. but,
10597# we don't know if the result was an underflow that rounded up to a 2 or
10598# a normalized number that rounded down to a 2. so, redo the entire operation
10599# using RZ as the rounding mode to see what the pre-rounded result is.
10600# this case should be relatively rare.
10601#
10602        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op into fp1
10603
10604        mov.l           L_SCR3(%a6),%d1
10605        andi.b          &0xc0,%d1               # keep rnd prec
10606        ori.b           &rz_mode*0x10,%d1       # insert RZ
10607
10608        fmov.l          %d1,%fpcr               # set FPCR
10609        fmov.l          &0x0,%fpsr              # clear FPSR
10610
10611        fsglmul.x       FP_SCR0(%a6),%fp1       # execute sgl multiply
10612
10613        fmov.l          &0x0,%fpcr              # clear FPCR
10614        fabs.x          %fp1                    # make absolute value
10615        fcmp.b          %fp1,&0x2               # is |result| < 2.b?
10616        fbge.w          fsglmul_normal_exit     # no; no underflow occurred
10617        bra.w           fsglmul_unfl            # yes, underflow occurred
10618
10619##############################################################################
10620
10621#
10622# Single Precision Multiply: inputs are not both normalized; what are they?
10623#
10624fsglmul_not_norm:
10625        mov.w           (tbl_fsglmul_op.b,%pc,%d1.w*2),%d1
10626        jmp             (tbl_fsglmul_op.b,%pc,%d1.w*1)
10627
10628        swbeg           &48
10629tbl_fsglmul_op:
10630        short           fsglmul_norm            - tbl_fsglmul_op # NORM x NORM
10631        short           fsglmul_zero            - tbl_fsglmul_op # NORM x ZERO
10632        short           fsglmul_inf_src         - tbl_fsglmul_op # NORM x INF
10633        short           fsglmul_res_qnan        - tbl_fsglmul_op # NORM x QNAN
10634        short           fsglmul_norm            - tbl_fsglmul_op # NORM x DENORM
10635        short           fsglmul_res_snan        - tbl_fsglmul_op # NORM x SNAN
10636        short           tbl_fsglmul_op          - tbl_fsglmul_op #
10637        short           tbl_fsglmul_op          - tbl_fsglmul_op #
10638
10639        short           fsglmul_zero            - tbl_fsglmul_op # ZERO x NORM
10640        short           fsglmul_zero            - tbl_fsglmul_op # ZERO x ZERO
10641        short           fsglmul_res_operr       - tbl_fsglmul_op # ZERO x INF
10642        short           fsglmul_res_qnan        - tbl_fsglmul_op # ZERO x QNAN
10643        short           fsglmul_zero            - tbl_fsglmul_op # ZERO x DENORM
10644        short           fsglmul_res_snan        - tbl_fsglmul_op # ZERO x SNAN
10645        short           tbl_fsglmul_op          - tbl_fsglmul_op #
10646        short           tbl_fsglmul_op          - tbl_fsglmul_op #
10647
10648        short           fsglmul_inf_dst         - tbl_fsglmul_op # INF x NORM
10649        short           fsglmul_res_operr       - tbl_fsglmul_op # INF x ZERO
10650        short           fsglmul_inf_dst         - tbl_fsglmul_op # INF x INF
10651        short           fsglmul_res_qnan        - tbl_fsglmul_op # INF x QNAN
10652        short           fsglmul_inf_dst         - tbl_fsglmul_op # INF x DENORM
10653        short           fsglmul_res_snan        - tbl_fsglmul_op # INF x SNAN
10654        short           tbl_fsglmul_op          - tbl_fsglmul_op #
10655        short           tbl_fsglmul_op          - tbl_fsglmul_op #
10656
10657        short           fsglmul_res_qnan        - tbl_fsglmul_op # QNAN x NORM
10658        short           fsglmul_res_qnan        - tbl_fsglmul_op # QNAN x ZERO
10659        short           fsglmul_res_qnan        - tbl_fsglmul_op # QNAN x INF
10660        short           fsglmul_res_qnan        - tbl_fsglmul_op # QNAN x QNAN
10661        short           fsglmul_res_qnan        - tbl_fsglmul_op # QNAN x DENORM
10662        short           fsglmul_res_snan        - tbl_fsglmul_op # QNAN x SNAN
10663        short           tbl_fsglmul_op          - tbl_fsglmul_op #
10664        short           tbl_fsglmul_op          - tbl_fsglmul_op #
10665
10666        short           fsglmul_norm            - tbl_fsglmul_op # NORM x NORM
10667        short           fsglmul_zero            - tbl_fsglmul_op # NORM x ZERO
10668        short           fsglmul_inf_src         - tbl_fsglmul_op # NORM x INF
10669        short           fsglmul_res_qnan        - tbl_fsglmul_op # NORM x QNAN
10670        short           fsglmul_norm            - tbl_fsglmul_op # NORM x DENORM
10671        short           fsglmul_res_snan        - tbl_fsglmul_op # NORM x SNAN
10672        short           tbl_fsglmul_op          - tbl_fsglmul_op #
10673        short           tbl_fsglmul_op          - tbl_fsglmul_op #
10674
10675        short           fsglmul_res_snan        - tbl_fsglmul_op # SNAN x NORM
10676        short           fsglmul_res_snan        - tbl_fsglmul_op # SNAN x ZERO
10677        short           fsglmul_res_snan        - tbl_fsglmul_op # SNAN x INF
10678        short           fsglmul_res_snan        - tbl_fsglmul_op # SNAN x QNAN
10679        short           fsglmul_res_snan        - tbl_fsglmul_op # SNAN x DENORM
10680        short           fsglmul_res_snan        - tbl_fsglmul_op # SNAN x SNAN
10681        short           tbl_fsglmul_op          - tbl_fsglmul_op #
10682        short           tbl_fsglmul_op          - tbl_fsglmul_op #
10683
10684fsglmul_res_operr:
10685        bra.l           res_operr
10686fsglmul_res_snan:
10687        bra.l           res_snan
10688fsglmul_res_qnan:
10689        bra.l           res_qnan
10690fsglmul_zero:
10691        bra.l           fmul_zero
10692fsglmul_inf_src:
10693        bra.l           fmul_inf_src
10694fsglmul_inf_dst:
10695        bra.l           fmul_inf_dst
10696
10697#########################################################################
10698# XDEF **************************************************************** #
10699#       fsgldiv(): emulates the fsgldiv instruction                     #
10700#                                                                       #
10701# XREF **************************************************************** #
10702#       scale_to_zero_src() - scale src exponent to zero                #
10703#       scale_to_zero_dst() - scale dst exponent to zero                #
10704#       unf_res4() - return default underflow result for sglop          #
10705#       ovf_res() - return default overflow result                      #
10706#       res_qnan() - return QNAN result                                 #
10707#       res_snan() - return SNAN result                                 #
10708#                                                                       #
10709# INPUT *************************************************************** #
10710#       a0 = pointer to extended precision source operand               #
10711#       a1 = pointer to extended precision destination operand          #
10712#       d0  rnd prec,mode                                               #
10713#                                                                       #
10714# OUTPUT ************************************************************** #
10715#       fp0 = result                                                    #
10716#       fp1 = EXOP (if exception occurred)                              #
10717#                                                                       #
10718# ALGORITHM *********************************************************** #
10719#       Handle NANs, infinities, and zeroes as special cases. Divide    #
10720# norms/denorms into ext/sgl/dbl precision.                             #
10721#       For norms/denorms, scale the exponents such that a divide       #
10722# instruction won't cause an exception. Use the regular fsgldiv to      #
10723# compute a result. Check if the regular operands would have taken      #
10724# an exception. If so, return the default overflow/underflow result     #
10725# and return the EXOP if exceptions are enabled. Else, scale the        #
10726# result operand to the proper exponent.                                #
10727#                                                                       #
10728#########################################################################
10729
10730        global          fsgldiv
10731fsgldiv:
10732        mov.l           %d0,L_SCR3(%a6)         # store rnd info
10733
10734        clr.w           %d1
10735        mov.b           DTAG(%a6),%d1
10736        lsl.b           &0x3,%d1
10737        or.b            STAG(%a6),%d1           # combine src tags
10738
10739        bne.w           fsgldiv_not_norm        # optimize on non-norm input
10740
10741#
10742# DIVIDE: NORMs and DENORMs ONLY!
10743#
10744fsgldiv_norm:
10745        mov.w           DST_EX(%a1),FP_SCR1_EX(%a6)
10746        mov.l           DST_HI(%a1),FP_SCR1_HI(%a6)
10747        mov.l           DST_LO(%a1),FP_SCR1_LO(%a6)
10748
10749        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
10750        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
10751        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
10752
10753        bsr.l           scale_to_zero_src       # calculate scale factor 1
10754        mov.l           %d0,-(%sp)              # save scale factor 1
10755
10756        bsr.l           scale_to_zero_dst       # calculate scale factor 2
10757
10758        neg.l           (%sp)                   # S.F. = scale1 - scale2
10759        add.l           %d0,(%sp)
10760
10761        mov.w           2+L_SCR3(%a6),%d1       # fetch precision,mode
10762        lsr.b           &0x6,%d1
10763        mov.l           (%sp)+,%d0
10764        cmpi.l          %d0,&0x3fff-0x7ffe
10765        ble.w           fsgldiv_may_ovfl
10766
10767        cmpi.l          %d0,&0x3fff-0x0000      # will result underflow?
10768        beq.w           fsgldiv_may_unfl        # maybe
10769        bgt.w           fsgldiv_unfl            # yes; go handle underflow
10770
10771fsgldiv_normal:
10772        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
10773
10774        fmov.l          L_SCR3(%a6),%fpcr       # save FPCR
10775        fmov.l          &0x0,%fpsr              # clear FPSR
10776
10777        fsgldiv.x       FP_SCR0(%a6),%fp0       # perform sgl divide
10778
10779        fmov.l          %fpsr,%d1               # save FPSR
10780        fmov.l          &0x0,%fpcr              # clear FPCR
10781
10782        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
10783
10784fsgldiv_normal_exit:
10785        fmovm.x         &0x80,FP_SCR0(%a6)      # store result on stack
10786        mov.l           %d2,-(%sp)              # save d2
10787        mov.w           FP_SCR0_EX(%a6),%d1     # load {sgn,exp}
10788        mov.l           %d1,%d2                 # make a copy
10789        andi.l          &0x7fff,%d1             # strip sign
10790        andi.w          &0x8000,%d2             # keep old sign
10791        sub.l           %d0,%d1                 # add scale factor
10792        or.w            %d2,%d1                 # concat old sign,new exp
10793        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
10794        mov.l           (%sp)+,%d2              # restore d2
10795        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
10796        rts
10797
10798fsgldiv_may_ovfl:
10799        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
10800
10801        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
10802        fmov.l          &0x0,%fpsr              # set FPSR
10803
10804        fsgldiv.x       FP_SCR0(%a6),%fp0       # execute divide
10805
10806        fmov.l          %fpsr,%d1
10807        fmov.l          &0x0,%fpcr
10808
10809        or.l            %d1,USER_FPSR(%a6)      # save INEX,N
10810
10811        fmovm.x         &0x01,-(%sp)            # save result to stack
10812        mov.w           (%sp),%d1               # fetch new exponent
10813        add.l           &0xc,%sp                # clear result
10814        andi.l          &0x7fff,%d1             # strip sign
10815        sub.l           %d0,%d1                 # add scale factor
10816        cmp.l           %d1,&0x7fff             # did divide overflow?
10817        blt.b           fsgldiv_normal_exit
10818
10819fsgldiv_ovfl_tst:
10820        or.w            &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex
10821
10822        mov.b           FPCR_ENABLE(%a6),%d1
10823        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
10824        bne.b           fsgldiv_ovfl_ena        # yes
10825
10826fsgldiv_ovfl_dis:
10827        btst            &neg_bit,FPSR_CC(%a6)   # is result negative
10828        sne             %d1                     # set sign param accordingly
10829        mov.l           L_SCR3(%a6),%d0         # pass prec:rnd
10830        andi.b          &0x30,%d0               # kill precision
10831        bsr.l           ovf_res                 # calculate default result
10832        or.b            %d0,FPSR_CC(%a6)        # set INF if applicable
10833        fmovm.x         (%a0),&0x80             # return default result in fp0
10834        rts
10835
10836fsgldiv_ovfl_ena:
10837        fmovm.x         &0x80,FP_SCR0(%a6)      # move result to stack
10838
10839        mov.l           %d2,-(%sp)              # save d2
10840        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
10841        mov.l           %d1,%d2                 # make a copy
10842        andi.l          &0x7fff,%d1             # strip sign
10843        andi.w          &0x8000,%d2             # keep old sign
10844        sub.l           %d0,%d1                 # add scale factor
10845        subi.l          &0x6000,%d1             # subtract new bias
10846        andi.w          &0x7fff,%d1             # clear ms bit
10847        or.w            %d2,%d1                 # concat old sign,new exp
10848        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
10849        mov.l           (%sp)+,%d2              # restore d2
10850        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
10851        bra.b           fsgldiv_ovfl_dis
10852
10853fsgldiv_unfl:
10854        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
10855
10856        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
10857
10858        fmov.l          &rz_mode*0x10,%fpcr     # set FPCR
10859        fmov.l          &0x0,%fpsr              # clear FPSR
10860
10861        fsgldiv.x       FP_SCR0(%a6),%fp0       # execute sgl divide
10862
10863        fmov.l          %fpsr,%d1               # save status
10864        fmov.l          &0x0,%fpcr              # clear FPCR
10865
10866        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
10867
10868        mov.b           FPCR_ENABLE(%a6),%d1
10869        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
10870        bne.b           fsgldiv_unfl_ena        # yes
10871
10872fsgldiv_unfl_dis:
10873        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
10874
10875        lea             FP_SCR0(%a6),%a0        # pass: result addr
10876        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
10877        bsr.l           unf_res4                # calculate default result
10878        or.b            %d0,FPSR_CC(%a6)        # 'Z' bit may have been set
10879        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
10880        rts
10881
10882#
10883# UNFL is enabled.
10884#
10885fsgldiv_unfl_ena:
10886        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op
10887
10888        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
10889        fmov.l          &0x0,%fpsr              # clear FPSR
10890
10891        fsgldiv.x       FP_SCR0(%a6),%fp1       # execute sgl divide
10892
10893        fmov.l          &0x0,%fpcr              # clear FPCR
10894
10895        fmovm.x         &0x40,FP_SCR0(%a6)      # save result to stack
10896        mov.l           %d2,-(%sp)              # save d2
10897        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
10898        mov.l           %d1,%d2                 # make a copy
10899        andi.l          &0x7fff,%d1             # strip sign
10900        andi.w          &0x8000,%d2             # keep old sign
10901        sub.l           %d0,%d1                 # add scale factor
10902        addi.l          &0x6000,%d1             # add bias
10903        andi.w          &0x7fff,%d1             # clear top bit
10904        or.w            %d2,%d1                 # concat old sign, new exp
10905        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
10906        mov.l           (%sp)+,%d2              # restore d2
10907        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
10908        bra.b           fsgldiv_unfl_dis
10909
10910#
10911# the divide operation MAY underflow:
10912#
10913fsgldiv_may_unfl:
10914        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
10915
10916        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
10917        fmov.l          &0x0,%fpsr              # clear FPSR
10918
10919        fsgldiv.x       FP_SCR0(%a6),%fp0       # execute sgl divide
10920
10921        fmov.l          %fpsr,%d1               # save status
10922        fmov.l          &0x0,%fpcr              # clear FPCR
10923
10924        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
10925
10926        fabs.x          %fp0,%fp1               # make a copy of result
10927        fcmp.b          %fp1,&0x1               # is |result| > 1.b?
10928        fbgt.w          fsgldiv_normal_exit     # no; no underflow occurred
10929        fblt.w          fsgldiv_unfl            # yes; underflow occurred
10930
10931#
10932# we still don't know if underflow occurred. result is ~ equal to 1. but,
10933# we don't know if the result was an underflow that rounded up to a 1
10934# or a normalized number that rounded down to a 1. so, redo the entire
10935# operation using RZ as the rounding mode to see what the pre-rounded
10936# result is. this case should be relatively rare.
10937#
10938        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op into %fp1
10939
10940        clr.l           %d1                     # clear scratch register
10941        ori.b           &rz_mode*0x10,%d1       # force RZ rnd mode
10942
10943        fmov.l          %d1,%fpcr               # set FPCR
10944        fmov.l          &0x0,%fpsr              # clear FPSR
10945
10946        fsgldiv.x       FP_SCR0(%a6),%fp1       # execute sgl divide
10947
10948        fmov.l          &0x0,%fpcr              # clear FPCR
10949        fabs.x          %fp1                    # make absolute value
10950        fcmp.b          %fp1,&0x1               # is |result| < 1.b?
10951        fbge.w          fsgldiv_normal_exit     # no; no underflow occurred
10952        bra.w           fsgldiv_unfl            # yes; underflow occurred
10953
10954############################################################################
10955
10956#
10957# Divide: inputs are not both normalized; what are they?
10958#
10959fsgldiv_not_norm:
10960        mov.w           (tbl_fsgldiv_op.b,%pc,%d1.w*2),%d1
10961        jmp             (tbl_fsgldiv_op.b,%pc,%d1.w*1)
10962
10963        swbeg           &48
10964tbl_fsgldiv_op:
10965        short           fsgldiv_norm            - tbl_fsgldiv_op # NORM / NORM
10966        short           fsgldiv_inf_load        - tbl_fsgldiv_op # NORM / ZERO
10967        short           fsgldiv_zero_load       - tbl_fsgldiv_op # NORM / INF
10968        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # NORM / QNAN
10969        short           fsgldiv_norm            - tbl_fsgldiv_op # NORM / DENORM
10970        short           fsgldiv_res_snan        - tbl_fsgldiv_op # NORM / SNAN
10971        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
10972        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
10973
10974        short           fsgldiv_zero_load       - tbl_fsgldiv_op # ZERO / NORM
10975        short           fsgldiv_res_operr       - tbl_fsgldiv_op # ZERO / ZERO
10976        short           fsgldiv_zero_load       - tbl_fsgldiv_op # ZERO / INF
10977        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # ZERO / QNAN
10978        short           fsgldiv_zero_load       - tbl_fsgldiv_op # ZERO / DENORM
10979        short           fsgldiv_res_snan        - tbl_fsgldiv_op # ZERO / SNAN
10980        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
10981        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
10982
10983        short           fsgldiv_inf_dst         - tbl_fsgldiv_op # INF / NORM
10984        short           fsgldiv_inf_dst         - tbl_fsgldiv_op # INF / ZERO
10985        short           fsgldiv_res_operr       - tbl_fsgldiv_op # INF / INF
10986        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # INF / QNAN
10987        short           fsgldiv_inf_dst         - tbl_fsgldiv_op # INF / DENORM
10988        short           fsgldiv_res_snan        - tbl_fsgldiv_op # INF / SNAN
10989        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
10990        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
10991
10992        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # QNAN / NORM
10993        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # QNAN / ZERO
10994        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # QNAN / INF
10995        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # QNAN / QNAN
10996        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # QNAN / DENORM
10997        short           fsgldiv_res_snan        - tbl_fsgldiv_op # QNAN / SNAN
10998        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
10999        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
11000
11001        short           fsgldiv_norm            - tbl_fsgldiv_op # DENORM / NORM
11002        short           fsgldiv_inf_load        - tbl_fsgldiv_op # DENORM / ZERO
11003        short           fsgldiv_zero_load       - tbl_fsgldiv_op # DENORM / INF
11004        short           fsgldiv_res_qnan        - tbl_fsgldiv_op # DENORM / QNAN
11005        short           fsgldiv_norm            - tbl_fsgldiv_op # DENORM / DENORM
11006        short           fsgldiv_res_snan        - tbl_fsgldiv_op # DENORM / SNAN
11007        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
11008        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
11009
11010        short           fsgldiv_res_snan        - tbl_fsgldiv_op # SNAN / NORM
11011        short           fsgldiv_res_snan        - tbl_fsgldiv_op # SNAN / ZERO
11012        short           fsgldiv_res_snan        - tbl_fsgldiv_op # SNAN / INF
11013        short           fsgldiv_res_snan        - tbl_fsgldiv_op # SNAN / QNAN
11014        short           fsgldiv_res_snan        - tbl_fsgldiv_op # SNAN / DENORM
11015        short           fsgldiv_res_snan        - tbl_fsgldiv_op # SNAN / SNAN
11016        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
11017        short           tbl_fsgldiv_op          - tbl_fsgldiv_op #
11018
11019fsgldiv_res_qnan:
11020        bra.l           res_qnan
11021fsgldiv_res_snan:
11022        bra.l           res_snan
11023fsgldiv_res_operr:
11024        bra.l           res_operr
11025fsgldiv_inf_load:
11026        bra.l           fdiv_inf_load
11027fsgldiv_zero_load:
11028        bra.l           fdiv_zero_load
11029fsgldiv_inf_dst:
11030        bra.l           fdiv_inf_dst
11031
11032#########################################################################
11033# XDEF **************************************************************** #
11034#       fadd(): emulates the fadd instruction                           #
11035#       fsadd(): emulates the fadd instruction                          #
11036#       fdadd(): emulates the fdadd instruction                         #
11037#                                                                       #
11038# XREF **************************************************************** #
11039#       addsub_scaler2() - scale the operands so they won't take exc    #
11040#       ovf_res() - return default overflow result                      #
11041#       unf_res() - return default underflow result                     #
11042#       res_qnan() - set QNAN result                                    #
11043#       res_snan() - set SNAN result                                    #
11044#       res_operr() - set OPERR result                                  #
11045#       scale_to_zero_src() - set src operand exponent equal to zero    #
11046#       scale_to_zero_dst() - set dst operand exponent equal to zero    #
11047#                                                                       #
11048# INPUT *************************************************************** #
11049#       a0 = pointer to extended precision source operand               #
11050#       a1 = pointer to extended precision destination operand          #
11051#                                                                       #
11052# OUTPUT ************************************************************** #
11053#       fp0 = result                                                    #
11054#       fp1 = EXOP (if exception occurred)                              #
11055#                                                                       #
11056# ALGORITHM *********************************************************** #
11057#       Handle NANs, infinities, and zeroes as special cases. Divide    #
11058# norms into extended, single, and double precision.                    #
11059#       Do addition after scaling exponents such that exception won't   #
11060# occur. Then, check result exponent to see if exception would have     #
11061# occurred. If so, return default result and maybe EXOP. Else, insert   #
11062# the correct result exponent and return. Set FPSR bits as appropriate. #
11063#                                                                       #
11064#########################################################################
11065
11066        global          fsadd
11067fsadd:
11068        andi.b          &0x30,%d0               # clear rnd prec
11069        ori.b           &s_mode*0x10,%d0        # insert sgl prec
11070        bra.b           fadd
11071
11072        global          fdadd
11073fdadd:
11074        andi.b          &0x30,%d0               # clear rnd prec
11075        ori.b           &d_mode*0x10,%d0        # insert dbl prec
11076
11077        global          fadd
11078fadd:
11079        mov.l           %d0,L_SCR3(%a6)         # store rnd info
11080
11081        clr.w           %d1
11082        mov.b           DTAG(%a6),%d1
11083        lsl.b           &0x3,%d1
11084        or.b            STAG(%a6),%d1           # combine src tags
11085
11086        bne.w           fadd_not_norm           # optimize on non-norm input
11087
11088#
11089# ADD: norms and denorms
11090#
11091fadd_norm:
11092        bsr.l           addsub_scaler2          # scale exponents
11093
11094fadd_zero_entry:
11095        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
11096
11097        fmov.l          &0x0,%fpsr              # clear FPSR
11098        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
11099
11100        fadd.x          FP_SCR0(%a6),%fp0       # execute add
11101
11102        fmov.l          &0x0,%fpcr              # clear FPCR
11103        fmov.l          %fpsr,%d1               # fetch INEX2,N,Z
11104
11105        or.l            %d1,USER_FPSR(%a6)      # save exc and ccode bits
11106
11107        fbeq.w          fadd_zero_exit          # if result is zero, end now
11108
11109        mov.l           %d2,-(%sp)              # save d2
11110
11111        fmovm.x         &0x01,-(%sp)            # save result to stack
11112
11113        mov.w           2+L_SCR3(%a6),%d1
11114        lsr.b           &0x6,%d1
11115
11116        mov.w           (%sp),%d2               # fetch new sign, exp
11117        andi.l          &0x7fff,%d2             # strip sign
11118        sub.l           %d0,%d2                 # add scale factor
11119
11120        cmp.l           %d2,(tbl_fadd_ovfl.b,%pc,%d1.w*4) # is it an overflow?
11121        bge.b           fadd_ovfl               # yes
11122
11123        cmp.l           %d2,(tbl_fadd_unfl.b,%pc,%d1.w*4) # is it an underflow?
11124        blt.w           fadd_unfl               # yes
11125        beq.w           fadd_may_unfl           # maybe; go find out
11126
11127fadd_normal:
11128        mov.w           (%sp),%d1
11129        andi.w          &0x8000,%d1             # keep sign
11130        or.w            %d2,%d1                 # concat sign,new exp
11131        mov.w           %d1,(%sp)               # insert new exponent
11132
11133        fmovm.x         (%sp)+,&0x80            # return result in fp0
11134
11135        mov.l           (%sp)+,%d2              # restore d2
11136        rts
11137
11138fadd_zero_exit:
11139#       fmov.s          &0x00000000,%fp0        # return zero in fp0
11140        rts
11141
11142tbl_fadd_ovfl:
11143        long            0x7fff                  # ext ovfl
11144        long            0x407f                  # sgl ovfl
11145        long            0x43ff                  # dbl ovfl
11146
11147tbl_fadd_unfl:
11148        long            0x0000                  # ext unfl
11149        long            0x3f81                  # sgl unfl
11150        long            0x3c01                  # dbl unfl
11151
11152fadd_ovfl:
11153        or.l            &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
11154
11155        mov.b           FPCR_ENABLE(%a6),%d1
11156        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
11157        bne.b           fadd_ovfl_ena           # yes
11158
11159        add.l           &0xc,%sp
11160fadd_ovfl_dis:
11161        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
11162        sne             %d1                     # set sign param accordingly
11163        mov.l           L_SCR3(%a6),%d0         # pass prec:rnd
11164        bsr.l           ovf_res                 # calculate default result
11165        or.b            %d0,FPSR_CC(%a6)        # set INF,N if applicable
11166        fmovm.x         (%a0),&0x80             # return default result in fp0
11167        mov.l           (%sp)+,%d2              # restore d2
11168        rts
11169
11170fadd_ovfl_ena:
11171        mov.b           L_SCR3(%a6),%d1
11172        andi.b          &0xc0,%d1               # is precision extended?
11173        bne.b           fadd_ovfl_ena_sd        # no; prec = sgl or dbl
11174
11175fadd_ovfl_ena_cont:
11176        mov.w           (%sp),%d1
11177        andi.w          &0x8000,%d1             # keep sign
11178        subi.l          &0x6000,%d2             # add extra bias
11179        andi.w          &0x7fff,%d2
11180        or.w            %d2,%d1                 # concat sign,new exp
11181        mov.w           %d1,(%sp)               # insert new exponent
11182
11183        fmovm.x         (%sp)+,&0x40            # return EXOP in fp1
11184        bra.b           fadd_ovfl_dis
11185
11186fadd_ovfl_ena_sd:
11187        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
11188
11189        mov.l           L_SCR3(%a6),%d1
11190        andi.b          &0x30,%d1               # keep rnd mode
11191        fmov.l          %d1,%fpcr               # set FPCR
11192
11193        fadd.x          FP_SCR0(%a6),%fp0       # execute add
11194
11195        fmov.l          &0x0,%fpcr              # clear FPCR
11196
11197        add.l           &0xc,%sp
11198        fmovm.x         &0x01,-(%sp)
11199        bra.b           fadd_ovfl_ena_cont
11200
11201fadd_unfl:
11202        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
11203
11204        add.l           &0xc,%sp
11205
11206        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
11207
11208        fmov.l          &rz_mode*0x10,%fpcr     # set FPCR
11209        fmov.l          &0x0,%fpsr              # clear FPSR
11210
11211        fadd.x          FP_SCR0(%a6),%fp0       # execute add
11212
11213        fmov.l          &0x0,%fpcr              # clear FPCR
11214        fmov.l          %fpsr,%d1               # save status
11215
11216        or.l            %d1,USER_FPSR(%a6)      # save INEX,N
11217
11218        mov.b           FPCR_ENABLE(%a6),%d1
11219        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
11220        bne.b           fadd_unfl_ena           # yes
11221
11222fadd_unfl_dis:
11223        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
11224
11225        lea             FP_SCR0(%a6),%a0        # pass: result addr
11226        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
11227        bsr.l           unf_res                 # calculate default result
11228        or.b            %d0,FPSR_CC(%a6)        # 'Z' bit may have been set
11229        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
11230        mov.l           (%sp)+,%d2              # restore d2
11231        rts
11232
11233fadd_unfl_ena:
11234        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op
11235
11236        mov.l           L_SCR3(%a6),%d1
11237        andi.b          &0xc0,%d1               # is precision extended?
11238        bne.b           fadd_unfl_ena_sd        # no; sgl or dbl
11239
11240        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
11241
11242fadd_unfl_ena_cont:
11243        fmov.l          &0x0,%fpsr              # clear FPSR
11244
11245        fadd.x          FP_SCR0(%a6),%fp1       # execute multiply
11246
11247        fmov.l          &0x0,%fpcr              # clear FPCR
11248
11249        fmovm.x         &0x40,FP_SCR0(%a6)      # save result to stack
11250        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
11251        mov.l           %d1,%d2                 # make a copy
11252        andi.l          &0x7fff,%d1             # strip sign
11253        andi.w          &0x8000,%d2             # keep old sign
11254        sub.l           %d0,%d1                 # add scale factor
11255        addi.l          &0x6000,%d1             # add new bias
11256        andi.w          &0x7fff,%d1             # clear top bit
11257        or.w            %d2,%d1                 # concat sign,new exp
11258        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
11259        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
11260        bra.w           fadd_unfl_dis
11261
11262fadd_unfl_ena_sd:
11263        mov.l           L_SCR3(%a6),%d1
11264        andi.b          &0x30,%d1               # use only rnd mode
11265        fmov.l          %d1,%fpcr               # set FPCR
11266
11267        bra.b           fadd_unfl_ena_cont
11268
11269#
11270# result is equal to the smallest normalized number in the selected precision
11271# if the precision is extended, this result could not have come from an
11272# underflow that rounded up.
11273#
11274fadd_may_unfl:
11275        mov.l           L_SCR3(%a6),%d1
11276        andi.b          &0xc0,%d1
11277        beq.w           fadd_normal             # yes; no underflow occurred
11278
11279        mov.l           0x4(%sp),%d1            # extract hi(man)
11280        cmpi.l          %d1,&0x80000000         # is hi(man) = 0x80000000?
11281        bne.w           fadd_normal             # no; no underflow occurred
11282
11283        tst.l           0x8(%sp)                # is lo(man) = 0x0?
11284        bne.w           fadd_normal             # no; no underflow occurred
11285
11286        btst            &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
11287        beq.w           fadd_normal             # no; no underflow occurred
11288
11289#
11290# ok, so now the result has a exponent equal to the smallest normalized
11291# exponent for the selected precision. also, the mantissa is equal to
11292# 0x8000000000000000 and this mantissa is the result of rounding non-zero
11293# g,r,s.
11294# now, we must determine whether the pre-rounded result was an underflow
11295# rounded "up" or a normalized number rounded "down".
11296# so, we do this be re-executing the add using RZ as the rounding mode and
11297# seeing if the new result is smaller or equal to the current result.
11298#
11299        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op into fp1
11300
11301        mov.l           L_SCR3(%a6),%d1
11302        andi.b          &0xc0,%d1               # keep rnd prec
11303        ori.b           &rz_mode*0x10,%d1       # insert rnd mode
11304        fmov.l          %d1,%fpcr               # set FPCR
11305        fmov.l          &0x0,%fpsr              # clear FPSR
11306
11307        fadd.x          FP_SCR0(%a6),%fp1       # execute add
11308
11309        fmov.l          &0x0,%fpcr              # clear FPCR
11310
11311        fabs.x          %fp0                    # compare absolute values
11312        fabs.x          %fp1
11313        fcmp.x          %fp0,%fp1               # is first result > second?
11314
11315        fbgt.w          fadd_unfl               # yes; it's an underflow
11316        bra.w           fadd_normal             # no; it's not an underflow
11317
11318##########################################################################
11319
11320#
11321# Add: inputs are not both normalized; what are they?
11322#
11323fadd_not_norm:
11324        mov.w           (tbl_fadd_op.b,%pc,%d1.w*2),%d1
11325        jmp             (tbl_fadd_op.b,%pc,%d1.w*1)
11326
11327        swbeg           &48
11328tbl_fadd_op:
11329        short           fadd_norm       - tbl_fadd_op # NORM + NORM
11330        short           fadd_zero_src   - tbl_fadd_op # NORM + ZERO
11331        short           fadd_inf_src    - tbl_fadd_op # NORM + INF
11332        short           fadd_res_qnan   - tbl_fadd_op # NORM + QNAN
11333        short           fadd_norm       - tbl_fadd_op # NORM + DENORM
11334        short           fadd_res_snan   - tbl_fadd_op # NORM + SNAN
11335        short           tbl_fadd_op     - tbl_fadd_op #
11336        short           tbl_fadd_op     - tbl_fadd_op #
11337
11338        short           fadd_zero_dst   - tbl_fadd_op # ZERO + NORM
11339        short           fadd_zero_2     - tbl_fadd_op # ZERO + ZERO
11340        short           fadd_inf_src    - tbl_fadd_op # ZERO + INF
11341        short           fadd_res_qnan   - tbl_fadd_op # NORM + QNAN
11342        short           fadd_zero_dst   - tbl_fadd_op # ZERO + DENORM
11343        short           fadd_res_snan   - tbl_fadd_op # NORM + SNAN
11344        short           tbl_fadd_op     - tbl_fadd_op #
11345        short           tbl_fadd_op     - tbl_fadd_op #
11346
11347        short           fadd_inf_dst    - tbl_fadd_op # INF + NORM
11348        short           fadd_inf_dst    - tbl_fadd_op # INF + ZERO
11349        short           fadd_inf_2      - tbl_fadd_op # INF + INF
11350        short           fadd_res_qnan   - tbl_fadd_op # NORM + QNAN
11351        short           fadd_inf_dst    - tbl_fadd_op # INF + DENORM
11352        short           fadd_res_snan   - tbl_fadd_op # NORM + SNAN
11353        short           tbl_fadd_op     - tbl_fadd_op #
11354        short           tbl_fadd_op     - tbl_fadd_op #
11355
11356        short           fadd_res_qnan   - tbl_fadd_op # QNAN + NORM
11357        short           fadd_res_qnan   - tbl_fadd_op # QNAN + ZERO
11358        short           fadd_res_qnan   - tbl_fadd_op # QNAN + INF
11359        short           fadd_res_qnan   - tbl_fadd_op # QNAN + QNAN
11360        short           fadd_res_qnan   - tbl_fadd_op # QNAN + DENORM
11361        short           fadd_res_snan   - tbl_fadd_op # QNAN + SNAN
11362        short           tbl_fadd_op     - tbl_fadd_op #
11363        short           tbl_fadd_op     - tbl_fadd_op #
11364
11365        short           fadd_norm       - tbl_fadd_op # DENORM + NORM
11366        short           fadd_zero_src   - tbl_fadd_op # DENORM + ZERO
11367        short           fadd_inf_src    - tbl_fadd_op # DENORM + INF
11368        short           fadd_res_qnan   - tbl_fadd_op # NORM + QNAN
11369        short           fadd_norm       - tbl_fadd_op # DENORM + DENORM
11370        short           fadd_res_snan   - tbl_fadd_op # NORM + SNAN
11371        short           tbl_fadd_op     - tbl_fadd_op #
11372        short           tbl_fadd_op     - tbl_fadd_op #
11373
11374        short           fadd_res_snan   - tbl_fadd_op # SNAN + NORM
11375        short           fadd_res_snan   - tbl_fadd_op # SNAN + ZERO
11376        short           fadd_res_snan   - tbl_fadd_op # SNAN + INF
11377        short           fadd_res_snan   - tbl_fadd_op # SNAN + QNAN
11378        short           fadd_res_snan   - tbl_fadd_op # SNAN + DENORM
11379        short           fadd_res_snan   - tbl_fadd_op # SNAN + SNAN
11380        short           tbl_fadd_op     - tbl_fadd_op #
11381        short           tbl_fadd_op     - tbl_fadd_op #
11382
11383fadd_res_qnan:
11384        bra.l           res_qnan
11385fadd_res_snan:
11386        bra.l           res_snan
11387
11388#
11389# both operands are ZEROes
11390#
11391fadd_zero_2:
11392        mov.b           SRC_EX(%a0),%d0         # are the signs opposite
11393        mov.b           DST_EX(%a1),%d1
11394        eor.b           %d0,%d1
11395        bmi.w           fadd_zero_2_chk_rm      # weed out (-ZERO)+(+ZERO)
11396
11397# the signs are the same. so determine whether they are positive or negative
11398# and return the appropriately signed zero.
11399        tst.b           %d0                     # are ZEROes positive or negative?
11400        bmi.b           fadd_zero_rm            # negative
11401        fmov.s          &0x00000000,%fp0        # return +ZERO
11402        mov.b           &z_bmask,FPSR_CC(%a6)   # set Z
11403        rts
11404
11405#
11406# the ZEROes have opposite signs:
11407# - Therefore, we return +ZERO if the rounding modes are RN,RZ, or RP.
11408# - -ZERO is returned in the case of RM.
11409#
11410fadd_zero_2_chk_rm:
11411        mov.b           3+L_SCR3(%a6),%d1
11412        andi.b          &0x30,%d1               # extract rnd mode
11413        cmpi.b          %d1,&rm_mode*0x10       # is rnd mode == RM?
11414        beq.b           fadd_zero_rm            # yes
11415        fmov.s          &0x00000000,%fp0        # return +ZERO
11416        mov.b           &z_bmask,FPSR_CC(%a6)   # set Z
11417        rts
11418
11419fadd_zero_rm:
11420        fmov.s          &0x80000000,%fp0        # return -ZERO
11421        mov.b           &neg_bmask+z_bmask,FPSR_CC(%a6) # set NEG/Z
11422        rts
11423
11424#
11425# one operand is a ZERO and the other is a DENORM or NORM. scale
11426# the DENORM or NORM and jump to the regular fadd routine.
11427#
11428fadd_zero_dst:
11429        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
11430        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
11431        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
11432        bsr.l           scale_to_zero_src       # scale the operand
11433        clr.w           FP_SCR1_EX(%a6)
11434        clr.l           FP_SCR1_HI(%a6)
11435        clr.l           FP_SCR1_LO(%a6)
11436        bra.w           fadd_zero_entry         # go execute fadd
11437
11438fadd_zero_src:
11439        mov.w           DST_EX(%a1),FP_SCR1_EX(%a6)
11440        mov.l           DST_HI(%a1),FP_SCR1_HI(%a6)
11441        mov.l           DST_LO(%a1),FP_SCR1_LO(%a6)
11442        bsr.l           scale_to_zero_dst       # scale the operand
11443        clr.w           FP_SCR0_EX(%a6)
11444        clr.l           FP_SCR0_HI(%a6)
11445        clr.l           FP_SCR0_LO(%a6)
11446        bra.w           fadd_zero_entry         # go execute fadd
11447
11448#
11449# both operands are INFs. an OPERR will result if the INFs have
11450# different signs. else, an INF of the same sign is returned
11451#
11452fadd_inf_2:
11453        mov.b           SRC_EX(%a0),%d0         # exclusive or the signs
11454        mov.b           DST_EX(%a1),%d1
11455        eor.b           %d1,%d0
11456        bmi.l           res_operr               # weed out (-INF)+(+INF)
11457
11458# ok, so it's not an OPERR. but, we do have to remember to return the
11459# src INF since that's where the 881/882 gets the j-bit from...
11460
11461#
11462# operands are INF and one of {ZERO, INF, DENORM, NORM}
11463#
11464fadd_inf_src:
11465        fmovm.x         SRC(%a0),&0x80          # return src INF
11466        tst.b           SRC_EX(%a0)             # is INF positive?
11467        bpl.b           fadd_inf_done           # yes; we're done
11468        mov.b           &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
11469        rts
11470
11471#
11472# operands are INF and one of {ZERO, INF, DENORM, NORM}
11473#
11474fadd_inf_dst:
11475        fmovm.x         DST(%a1),&0x80          # return dst INF
11476        tst.b           DST_EX(%a1)             # is INF positive?
11477        bpl.b           fadd_inf_done           # yes; we're done
11478        mov.b           &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
11479        rts
11480
11481fadd_inf_done:
11482        mov.b           &inf_bmask,FPSR_CC(%a6) # set INF
11483        rts
11484
11485#########################################################################
11486# XDEF **************************************************************** #
11487#       fsub(): emulates the fsub instruction                           #
11488#       fssub(): emulates the fssub instruction                         #
11489#       fdsub(): emulates the fdsub instruction                         #
11490#                                                                       #
11491# XREF **************************************************************** #
11492#       addsub_scaler2() - scale the operands so they won't take exc    #
11493#       ovf_res() - return default overflow result                      #
11494#       unf_res() - return default underflow result                     #
11495#       res_qnan() - set QNAN result                                    #
11496#       res_snan() - set SNAN result                                    #
11497#       res_operr() - set OPERR result                                  #
11498#       scale_to_zero_src() - set src operand exponent equal to zero    #
11499#       scale_to_zero_dst() - set dst operand exponent equal to zero    #
11500#                                                                       #
11501# INPUT *************************************************************** #
11502#       a0 = pointer to extended precision source operand               #
11503#       a1 = pointer to extended precision destination operand          #
11504#                                                                       #
11505# OUTPUT ************************************************************** #
11506#       fp0 = result                                                    #
11507#       fp1 = EXOP (if exception occurred)                              #
11508#                                                                       #
11509# ALGORITHM *********************************************************** #
11510#       Handle NANs, infinities, and zeroes as special cases. Divide    #
11511# norms into extended, single, and double precision.                    #
11512#       Do subtraction after scaling exponents such that exception won't#
11513# occur. Then, check result exponent to see if exception would have     #
11514# occurred. If so, return default result and maybe EXOP. Else, insert   #
11515# the correct result exponent and return. Set FPSR bits as appropriate. #
11516#                                                                       #
11517#########################################################################
11518
11519        global          fssub
11520fssub:
11521        andi.b          &0x30,%d0               # clear rnd prec
11522        ori.b           &s_mode*0x10,%d0        # insert sgl prec
11523        bra.b           fsub
11524
11525        global          fdsub
11526fdsub:
11527        andi.b          &0x30,%d0               # clear rnd prec
11528        ori.b           &d_mode*0x10,%d0        # insert dbl prec
11529
11530        global          fsub
11531fsub:
11532        mov.l           %d0,L_SCR3(%a6)         # store rnd info
11533
11534        clr.w           %d1
11535        mov.b           DTAG(%a6),%d1
11536        lsl.b           &0x3,%d1
11537        or.b            STAG(%a6),%d1           # combine src tags
11538
11539        bne.w           fsub_not_norm           # optimize on non-norm input
11540
11541#
11542# SUB: norms and denorms
11543#
11544fsub_norm:
11545        bsr.l           addsub_scaler2          # scale exponents
11546
11547fsub_zero_entry:
11548        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
11549
11550        fmov.l          &0x0,%fpsr              # clear FPSR
11551        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
11552
11553        fsub.x          FP_SCR0(%a6),%fp0       # execute subtract
11554
11555        fmov.l          &0x0,%fpcr              # clear FPCR
11556        fmov.l          %fpsr,%d1               # fetch INEX2, N, Z
11557
11558        or.l            %d1,USER_FPSR(%a6)      # save exc and ccode bits
11559
11560        fbeq.w          fsub_zero_exit          # if result zero, end now
11561
11562        mov.l           %d2,-(%sp)              # save d2
11563
11564        fmovm.x         &0x01,-(%sp)            # save result to stack
11565
11566        mov.w           2+L_SCR3(%a6),%d1
11567        lsr.b           &0x6,%d1
11568
11569        mov.w           (%sp),%d2               # fetch new exponent
11570        andi.l          &0x7fff,%d2             # strip sign
11571        sub.l           %d0,%d2                 # add scale factor
11572
11573        cmp.l           %d2,(tbl_fsub_ovfl.b,%pc,%d1.w*4) # is it an overflow?
11574        bge.b           fsub_ovfl               # yes
11575
11576        cmp.l           %d2,(tbl_fsub_unfl.b,%pc,%d1.w*4) # is it an underflow?
11577        blt.w           fsub_unfl               # yes
11578        beq.w           fsub_may_unfl           # maybe; go find out
11579
11580fsub_normal:
11581        mov.w           (%sp),%d1
11582        andi.w          &0x8000,%d1             # keep sign
11583        or.w            %d2,%d1                 # insert new exponent
11584        mov.w           %d1,(%sp)               # insert new exponent
11585
11586        fmovm.x         (%sp)+,&0x80            # return result in fp0
11587
11588        mov.l           (%sp)+,%d2              # restore d2
11589        rts
11590
11591fsub_zero_exit:
11592#       fmov.s          &0x00000000,%fp0        # return zero in fp0
11593        rts
11594
11595tbl_fsub_ovfl:
11596        long            0x7fff                  # ext ovfl
11597        long            0x407f                  # sgl ovfl
11598        long            0x43ff                  # dbl ovfl
11599
11600tbl_fsub_unfl:
11601        long            0x0000                  # ext unfl
11602        long            0x3f81                  # sgl unfl
11603        long            0x3c01                  # dbl unfl
11604
11605fsub_ovfl:
11606        or.l            &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
11607
11608        mov.b           FPCR_ENABLE(%a6),%d1
11609        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
11610        bne.b           fsub_ovfl_ena           # yes
11611
11612        add.l           &0xc,%sp
11613fsub_ovfl_dis:
11614        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
11615        sne             %d1                     # set sign param accordingly
11616        mov.l           L_SCR3(%a6),%d0         # pass prec:rnd
11617        bsr.l           ovf_res                 # calculate default result
11618        or.b            %d0,FPSR_CC(%a6)        # set INF,N if applicable
11619        fmovm.x         (%a0),&0x80             # return default result in fp0
11620        mov.l           (%sp)+,%d2              # restore d2
11621        rts
11622
11623fsub_ovfl_ena:
11624        mov.b           L_SCR3(%a6),%d1
11625        andi.b          &0xc0,%d1               # is precision extended?
11626        bne.b           fsub_ovfl_ena_sd        # no
11627
11628fsub_ovfl_ena_cont:
11629        mov.w           (%sp),%d1               # fetch {sgn,exp}
11630        andi.w          &0x8000,%d1             # keep sign
11631        subi.l          &0x6000,%d2             # subtract new bias
11632        andi.w          &0x7fff,%d2             # clear top bit
11633        or.w            %d2,%d1                 # concat sign,exp
11634        mov.w           %d1,(%sp)               # insert new exponent
11635
11636        fmovm.x         (%sp)+,&0x40            # return EXOP in fp1
11637        bra.b           fsub_ovfl_dis
11638
11639fsub_ovfl_ena_sd:
11640        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
11641
11642        mov.l           L_SCR3(%a6),%d1
11643        andi.b          &0x30,%d1               # clear rnd prec
11644        fmov.l          %d1,%fpcr               # set FPCR
11645
11646        fsub.x          FP_SCR0(%a6),%fp0       # execute subtract
11647
11648        fmov.l          &0x0,%fpcr              # clear FPCR
11649
11650        add.l           &0xc,%sp
11651        fmovm.x         &0x01,-(%sp)
11652        bra.b           fsub_ovfl_ena_cont
11653
11654fsub_unfl:
11655        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
11656
11657        add.l           &0xc,%sp
11658
11659        fmovm.x         FP_SCR1(%a6),&0x80      # load dst op
11660
11661        fmov.l          &rz_mode*0x10,%fpcr     # set FPCR
11662        fmov.l          &0x0,%fpsr              # clear FPSR
11663
11664        fsub.x          FP_SCR0(%a6),%fp0       # execute subtract
11665
11666        fmov.l          &0x0,%fpcr              # clear FPCR
11667        fmov.l          %fpsr,%d1               # save status
11668
11669        or.l            %d1,USER_FPSR(%a6)
11670
11671        mov.b           FPCR_ENABLE(%a6),%d1
11672        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
11673        bne.b           fsub_unfl_ena           # yes
11674
11675fsub_unfl_dis:
11676        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
11677
11678        lea             FP_SCR0(%a6),%a0        # pass: result addr
11679        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
11680        bsr.l           unf_res                 # calculate default result
11681        or.b            %d0,FPSR_CC(%a6)        # 'Z' may have been set
11682        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
11683        mov.l           (%sp)+,%d2              # restore d2
11684        rts
11685
11686fsub_unfl_ena:
11687        fmovm.x         FP_SCR1(%a6),&0x40
11688
11689        mov.l           L_SCR3(%a6),%d1
11690        andi.b          &0xc0,%d1               # is precision extended?
11691        bne.b           fsub_unfl_ena_sd        # no
11692
11693        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
11694
11695fsub_unfl_ena_cont:
11696        fmov.l          &0x0,%fpsr              # clear FPSR
11697
11698        fsub.x          FP_SCR0(%a6),%fp1       # execute subtract
11699
11700        fmov.l          &0x0,%fpcr              # clear FPCR
11701
11702        fmovm.x         &0x40,FP_SCR0(%a6)      # store result to stack
11703        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
11704        mov.l           %d1,%d2                 # make a copy
11705        andi.l          &0x7fff,%d1             # strip sign
11706        andi.w          &0x8000,%d2             # keep old sign
11707        sub.l           %d0,%d1                 # add scale factor
11708        addi.l          &0x6000,%d1             # subtract new bias
11709        andi.w          &0x7fff,%d1             # clear top bit
11710        or.w            %d2,%d1                 # concat sgn,exp
11711        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
11712        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
11713        bra.w           fsub_unfl_dis
11714
11715fsub_unfl_ena_sd:
11716        mov.l           L_SCR3(%a6),%d1
11717        andi.b          &0x30,%d1               # clear rnd prec
11718        fmov.l          %d1,%fpcr               # set FPCR
11719
11720        bra.b           fsub_unfl_ena_cont
11721
11722#
11723# result is equal to the smallest normalized number in the selected precision
11724# if the precision is extended, this result could not have come from an
11725# underflow that rounded up.
11726#
11727fsub_may_unfl:
11728        mov.l           L_SCR3(%a6),%d1
11729        andi.b          &0xc0,%d1               # fetch rnd prec
11730        beq.w           fsub_normal             # yes; no underflow occurred
11731
11732        mov.l           0x4(%sp),%d1
11733        cmpi.l          %d1,&0x80000000         # is hi(man) = 0x80000000?
11734        bne.w           fsub_normal             # no; no underflow occurred
11735
11736        tst.l           0x8(%sp)                # is lo(man) = 0x0?
11737        bne.w           fsub_normal             # no; no underflow occurred
11738
11739        btst            &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
11740        beq.w           fsub_normal             # no; no underflow occurred
11741
11742#
11743# ok, so now the result has a exponent equal to the smallest normalized
11744# exponent for the selected precision. also, the mantissa is equal to
11745# 0x8000000000000000 and this mantissa is the result of rounding non-zero
11746# g,r,s.
11747# now, we must determine whether the pre-rounded result was an underflow
11748# rounded "up" or a normalized number rounded "down".
11749# so, we do this be re-executing the add using RZ as the rounding mode and
11750# seeing if the new result is smaller or equal to the current result.
11751#
11752        fmovm.x         FP_SCR1(%a6),&0x40      # load dst op into fp1
11753
11754        mov.l           L_SCR3(%a6),%d1
11755        andi.b          &0xc0,%d1               # keep rnd prec
11756        ori.b           &rz_mode*0x10,%d1       # insert rnd mode
11757        fmov.l          %d1,%fpcr               # set FPCR
11758        fmov.l          &0x0,%fpsr              # clear FPSR
11759
11760        fsub.x          FP_SCR0(%a6),%fp1       # execute subtract
11761
11762        fmov.l          &0x0,%fpcr              # clear FPCR
11763
11764        fabs.x          %fp0                    # compare absolute values
11765        fabs.x          %fp1
11766        fcmp.x          %fp0,%fp1               # is first result > second?
11767
11768        fbgt.w          fsub_unfl               # yes; it's an underflow
11769        bra.w           fsub_normal             # no; it's not an underflow
11770
11771##########################################################################
11772
11773#
11774# Sub: inputs are not both normalized; what are they?
11775#
11776fsub_not_norm:
11777        mov.w           (tbl_fsub_op.b,%pc,%d1.w*2),%d1
11778        jmp             (tbl_fsub_op.b,%pc,%d1.w*1)
11779
11780        swbeg           &48
11781tbl_fsub_op:
11782        short           fsub_norm       - tbl_fsub_op # NORM - NORM
11783        short           fsub_zero_src   - tbl_fsub_op # NORM - ZERO
11784        short           fsub_inf_src    - tbl_fsub_op # NORM - INF
11785        short           fsub_res_qnan   - tbl_fsub_op # NORM - QNAN
11786        short           fsub_norm       - tbl_fsub_op # NORM - DENORM
11787        short           fsub_res_snan   - tbl_fsub_op # NORM - SNAN
11788        short           tbl_fsub_op     - tbl_fsub_op #
11789        short           tbl_fsub_op     - tbl_fsub_op #
11790
11791        short           fsub_zero_dst   - tbl_fsub_op # ZERO - NORM
11792        short           fsub_zero_2     - tbl_fsub_op # ZERO - ZERO
11793        short           fsub_inf_src    - tbl_fsub_op # ZERO - INF
11794        short           fsub_res_qnan   - tbl_fsub_op # NORM - QNAN
11795        short           fsub_zero_dst   - tbl_fsub_op # ZERO - DENORM
11796        short           fsub_res_snan   - tbl_fsub_op # NORM - SNAN
11797        short           tbl_fsub_op     - tbl_fsub_op #
11798        short           tbl_fsub_op     - tbl_fsub_op #
11799
11800        short           fsub_inf_dst    - tbl_fsub_op # INF - NORM
11801        short           fsub_inf_dst    - tbl_fsub_op # INF - ZERO
11802        short           fsub_inf_2      - tbl_fsub_op # INF - INF
11803        short           fsub_res_qnan   - tbl_fsub_op # NORM - QNAN
11804        short           fsub_inf_dst    - tbl_fsub_op # INF - DENORM
11805        short           fsub_res_snan   - tbl_fsub_op # NORM - SNAN
11806        short           tbl_fsub_op     - tbl_fsub_op #
11807        short           tbl_fsub_op     - tbl_fsub_op #
11808
11809        short           fsub_res_qnan   - tbl_fsub_op # QNAN - NORM
11810        short           fsub_res_qnan   - tbl_fsub_op # QNAN - ZERO
11811        short           fsub_res_qnan   - tbl_fsub_op # QNAN - INF
11812        short           fsub_res_qnan   - tbl_fsub_op # QNAN - QNAN
11813        short           fsub_res_qnan   - tbl_fsub_op # QNAN - DENORM
11814        short           fsub_res_snan   - tbl_fsub_op # QNAN - SNAN
11815        short           tbl_fsub_op     - tbl_fsub_op #
11816        short           tbl_fsub_op     - tbl_fsub_op #
11817
11818        short           fsub_norm       - tbl_fsub_op # DENORM - NORM
11819        short           fsub_zero_src   - tbl_fsub_op # DENORM - ZERO
11820        short           fsub_inf_src    - tbl_fsub_op # DENORM - INF
11821        short           fsub_res_qnan   - tbl_fsub_op # NORM - QNAN
11822        short           fsub_norm       - tbl_fsub_op # DENORM - DENORM
11823        short           fsub_res_snan   - tbl_fsub_op # NORM - SNAN
11824        short           tbl_fsub_op     - tbl_fsub_op #
11825        short           tbl_fsub_op     - tbl_fsub_op #
11826
11827        short           fsub_res_snan   - tbl_fsub_op # SNAN - NORM
11828        short           fsub_res_snan   - tbl_fsub_op # SNAN - ZERO
11829        short           fsub_res_snan   - tbl_fsub_op # SNAN - INF
11830        short           fsub_res_snan   - tbl_fsub_op # SNAN - QNAN
11831        short           fsub_res_snan   - tbl_fsub_op # SNAN - DENORM
11832        short           fsub_res_snan   - tbl_fsub_op # SNAN - SNAN
11833        short           tbl_fsub_op     - tbl_fsub_op #
11834        short           tbl_fsub_op     - tbl_fsub_op #
11835
11836fsub_res_qnan:
11837        bra.l           res_qnan
11838fsub_res_snan:
11839        bra.l           res_snan
11840
11841#
11842# both operands are ZEROes
11843#
11844fsub_zero_2:
11845        mov.b           SRC_EX(%a0),%d0
11846        mov.b           DST_EX(%a1),%d1
11847        eor.b           %d1,%d0
11848        bpl.b           fsub_zero_2_chk_rm
11849
11850# the signs are opposite, so, return a ZERO w/ the sign of the dst ZERO
11851        tst.b           %d0                     # is dst negative?
11852        bmi.b           fsub_zero_2_rm          # yes
11853        fmov.s          &0x00000000,%fp0        # no; return +ZERO
11854        mov.b           &z_bmask,FPSR_CC(%a6)   # set Z
11855        rts
11856
11857#
11858# the ZEROes have the same signs:
11859# - Therefore, we return +ZERO if the rounding mode is RN,RZ, or RP
11860# - -ZERO is returned in the case of RM.
11861#
11862fsub_zero_2_chk_rm:
11863        mov.b           3+L_SCR3(%a6),%d1
11864        andi.b          &0x30,%d1               # extract rnd mode
11865        cmpi.b          %d1,&rm_mode*0x10       # is rnd mode = RM?
11866        beq.b           fsub_zero_2_rm          # yes
11867        fmov.s          &0x00000000,%fp0        # no; return +ZERO
11868        mov.b           &z_bmask,FPSR_CC(%a6)   # set Z
11869        rts
11870
11871fsub_zero_2_rm:
11872        fmov.s          &0x80000000,%fp0        # return -ZERO
11873        mov.b           &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/NEG
11874        rts
11875
11876#
11877# one operand is a ZERO and the other is a DENORM or a NORM.
11878# scale the DENORM or NORM and jump to the regular fsub routine.
11879#
11880fsub_zero_dst:
11881        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
11882        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
11883        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
11884        bsr.l           scale_to_zero_src       # scale the operand
11885        clr.w           FP_SCR1_EX(%a6)
11886        clr.l           FP_SCR1_HI(%a6)
11887        clr.l           FP_SCR1_LO(%a6)
11888        bra.w           fsub_zero_entry         # go execute fsub
11889
11890fsub_zero_src:
11891        mov.w           DST_EX(%a1),FP_SCR1_EX(%a6)
11892        mov.l           DST_HI(%a1),FP_SCR1_HI(%a6)
11893        mov.l           DST_LO(%a1),FP_SCR1_LO(%a6)
11894        bsr.l           scale_to_zero_dst       # scale the operand
11895        clr.w           FP_SCR0_EX(%a6)
11896        clr.l           FP_SCR0_HI(%a6)
11897        clr.l           FP_SCR0_LO(%a6)
11898        bra.w           fsub_zero_entry         # go execute fsub
11899
11900#
11901# both operands are INFs. an OPERR will result if the INFs have the
11902# same signs. else,
11903#
11904fsub_inf_2:
11905        mov.b           SRC_EX(%a0),%d0         # exclusive or the signs
11906        mov.b           DST_EX(%a1),%d1
11907        eor.b           %d1,%d0
11908        bpl.l           res_operr               # weed out (-INF)+(+INF)
11909
11910# ok, so it's not an OPERR. but we do have to remember to return
11911# the src INF since that's where the 881/882 gets the j-bit.
11912
11913fsub_inf_src:
11914        fmovm.x         SRC(%a0),&0x80          # return src INF
11915        fneg.x          %fp0                    # invert sign
11916        fbge.w          fsub_inf_done           # sign is now positive
11917        mov.b           &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
11918        rts
11919
11920fsub_inf_dst:
11921        fmovm.x         DST(%a1),&0x80          # return dst INF
11922        tst.b           DST_EX(%a1)             # is INF negative?
11923        bpl.b           fsub_inf_done           # no
11924        mov.b           &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
11925        rts
11926
11927fsub_inf_done:
11928        mov.b           &inf_bmask,FPSR_CC(%a6) # set INF
11929        rts
11930
11931#########################################################################
11932# XDEF **************************************************************** #
11933#       fsqrt(): emulates the fsqrt instruction                         #
11934#       fssqrt(): emulates the fssqrt instruction                       #
11935#       fdsqrt(): emulates the fdsqrt instruction                       #
11936#                                                                       #
11937# XREF **************************************************************** #
11938#       scale_sqrt() - scale the source operand                         #
11939#       unf_res() - return default underflow result                     #
11940#       ovf_res() - return default overflow result                      #
11941#       res_qnan_1op() - return QNAN result                             #
11942#       res_snan_1op() - return SNAN result                             #
11943#                                                                       #
11944# INPUT *************************************************************** #
11945#       a0 = pointer to extended precision source operand               #
11946#       d0  rnd prec,mode                                               #
11947#                                                                       #
11948# OUTPUT ************************************************************** #
11949#       fp0 = result                                                    #
11950#       fp1 = EXOP (if exception occurred)                              #
11951#                                                                       #
11952# ALGORITHM *********************************************************** #
11953#       Handle NANs, infinities, and zeroes as special cases. Divide    #
11954# norms/denorms into ext/sgl/dbl precision.                             #
11955#       For norms/denorms, scale the exponents such that a sqrt         #
11956# instruction won't cause an exception. Use the regular fsqrt to        #
11957# compute a result. Check if the regular operands would have taken      #
11958# an exception. If so, return the default overflow/underflow result     #
11959# and return the EXOP if exceptions are enabled. Else, scale the        #
11960# result operand to the proper exponent.                                #
11961#                                                                       #
11962#########################################################################
11963
11964        global          fssqrt
11965fssqrt:
11966        andi.b          &0x30,%d0               # clear rnd prec
11967        ori.b           &s_mode*0x10,%d0        # insert sgl precision
11968        bra.b           fsqrt
11969
11970        global          fdsqrt
11971fdsqrt:
11972        andi.b          &0x30,%d0               # clear rnd prec
11973        ori.b           &d_mode*0x10,%d0        # insert dbl precision
11974
11975        global          fsqrt
11976fsqrt:
11977        mov.l           %d0,L_SCR3(%a6)         # store rnd info
11978        clr.w           %d1
11979        mov.b           STAG(%a6),%d1
11980        bne.w           fsqrt_not_norm          # optimize on non-norm input
11981
11982#
11983# SQUARE ROOT: norms and denorms ONLY!
11984#
11985fsqrt_norm:
11986        tst.b           SRC_EX(%a0)             # is operand negative?
11987        bmi.l           res_operr               # yes
11988
11989        andi.b          &0xc0,%d0               # is precision extended?
11990        bne.b           fsqrt_not_ext           # no; go handle sgl or dbl
11991
11992        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
11993        fmov.l          &0x0,%fpsr              # clear FPSR
11994
11995        fsqrt.x         (%a0),%fp0              # execute square root
11996
11997        fmov.l          %fpsr,%d1
11998        or.l            %d1,USER_FPSR(%a6)      # set N,INEX
11999
12000        rts
12001
12002fsqrt_denorm:
12003        tst.b           SRC_EX(%a0)             # is operand negative?
12004        bmi.l           res_operr               # yes
12005
12006        andi.b          &0xc0,%d0               # is precision extended?
12007        bne.b           fsqrt_not_ext           # no; go handle sgl or dbl
12008
12009        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
12010        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
12011        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
12012
12013        bsr.l           scale_sqrt              # calculate scale factor
12014
12015        bra.w           fsqrt_sd_normal
12016
12017#
12018# operand is either single or double
12019#
12020fsqrt_not_ext:
12021        cmpi.b          %d0,&s_mode*0x10        # separate sgl/dbl prec
12022        bne.w           fsqrt_dbl
12023
12024#
12025# operand is to be rounded to single precision
12026#
12027fsqrt_sgl:
12028        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
12029        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
12030        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
12031
12032        bsr.l           scale_sqrt              # calculate scale factor
12033
12034        cmpi.l          %d0,&0x3fff-0x3f81      # will move in underflow?
12035        beq.w           fsqrt_sd_may_unfl
12036        bgt.w           fsqrt_sd_unfl           # yes; go handle underflow
12037        cmpi.l          %d0,&0x3fff-0x407f      # will move in overflow?
12038        beq.w           fsqrt_sd_may_ovfl       # maybe; go check
12039        blt.w           fsqrt_sd_ovfl           # yes; go handle overflow
12040
12041#
12042# operand will NOT overflow or underflow when moved in to the fp reg file
12043#
12044fsqrt_sd_normal:
12045        fmov.l          &0x0,%fpsr              # clear FPSR
12046        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
12047
12048        fsqrt.x         FP_SCR0(%a6),%fp0       # perform absolute
12049
12050        fmov.l          %fpsr,%d1               # save FPSR
12051        fmov.l          &0x0,%fpcr              # clear FPCR
12052
12053        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
12054
12055fsqrt_sd_normal_exit:
12056        mov.l           %d2,-(%sp)              # save d2
12057        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
12058        mov.w           FP_SCR0_EX(%a6),%d1     # load sgn,exp
12059        mov.l           %d1,%d2                 # make a copy
12060        andi.l          &0x7fff,%d1             # strip sign
12061        sub.l           %d0,%d1                 # add scale factor
12062        andi.w          &0x8000,%d2             # keep old sign
12063        or.w            %d1,%d2                 # concat old sign,new exp
12064        mov.w           %d2,FP_SCR0_EX(%a6)     # insert new exponent
12065        mov.l           (%sp)+,%d2              # restore d2
12066        fmovm.x         FP_SCR0(%a6),&0x80      # return result in fp0
12067        rts
12068
12069#
12070# operand is to be rounded to double precision
12071#
12072fsqrt_dbl:
12073        mov.w           SRC_EX(%a0),FP_SCR0_EX(%a6)
12074        mov.l           SRC_HI(%a0),FP_SCR0_HI(%a6)
12075        mov.l           SRC_LO(%a0),FP_SCR0_LO(%a6)
12076
12077        bsr.l           scale_sqrt              # calculate scale factor
12078
12079        cmpi.l          %d0,&0x3fff-0x3c01      # will move in underflow?
12080        beq.w           fsqrt_sd_may_unfl
12081        bgt.b           fsqrt_sd_unfl           # yes; go handle underflow
12082        cmpi.l          %d0,&0x3fff-0x43ff      # will move in overflow?
12083        beq.w           fsqrt_sd_may_ovfl       # maybe; go check
12084        blt.w           fsqrt_sd_ovfl           # yes; go handle overflow
12085        bra.w           fsqrt_sd_normal         # no; ho handle normalized op
12086
12087# we're on the line here and the distinguising characteristic is whether
12088# the exponent is 3fff or 3ffe. if it's 3ffe, then it's a safe number
12089# elsewise fall through to underflow.
12090fsqrt_sd_may_unfl:
12091        btst            &0x0,1+FP_SCR0_EX(%a6)  # is exponent 0x3fff?
12092        bne.w           fsqrt_sd_normal         # yes, so no underflow
12093
12094#
12095# operand WILL underflow when moved in to the fp register file
12096#
12097fsqrt_sd_unfl:
12098        bset            &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
12099
12100        fmov.l          &rz_mode*0x10,%fpcr     # set FPCR
12101        fmov.l          &0x0,%fpsr              # clear FPSR
12102
12103        fsqrt.x         FP_SCR0(%a6),%fp0       # execute square root
12104
12105        fmov.l          %fpsr,%d1               # save status
12106        fmov.l          &0x0,%fpcr              # clear FPCR
12107
12108        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
12109
12110# if underflow or inexact is enabled, go calculate EXOP first.
12111        mov.b           FPCR_ENABLE(%a6),%d1
12112        andi.b          &0x0b,%d1               # is UNFL or INEX enabled?
12113        bne.b           fsqrt_sd_unfl_ena       # yes
12114
12115fsqrt_sd_unfl_dis:
12116        fmovm.x         &0x80,FP_SCR0(%a6)      # store out result
12117
12118        lea             FP_SCR0(%a6),%a0        # pass: result addr
12119        mov.l           L_SCR3(%a6),%d1         # pass: rnd prec,mode
12120        bsr.l           unf_res                 # calculate default result
12121        or.b            %d0,FPSR_CC(%a6)        # set possible 'Z' ccode
12122        fmovm.x         FP_SCR0(%a6),&0x80      # return default result in fp0
12123        rts
12124
12125#
12126# operand will underflow AND underflow is enabled.
12127# Therefore, we must return the result rounded to extended precision.
12128#
12129fsqrt_sd_unfl_ena:
12130        mov.l           FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
12131        mov.l           FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
12132        mov.w           FP_SCR0_EX(%a6),%d1     # load current exponent
12133
12134        mov.l           %d2,-(%sp)              # save d2
12135        mov.l           %d1,%d2                 # make a copy
12136        andi.l          &0x7fff,%d1             # strip sign
12137        andi.w          &0x8000,%d2             # keep old sign
12138        sub.l           %d0,%d1                 # subtract scale factor
12139        addi.l          &0x6000,%d1             # add new bias
12140        andi.w          &0x7fff,%d1
12141        or.w            %d2,%d1                 # concat new sign,new exp
12142        mov.w           %d1,FP_SCR1_EX(%a6)     # insert new exp
12143        fmovm.x         FP_SCR1(%a6),&0x40      # return EXOP in fp1
12144        mov.l           (%sp)+,%d2              # restore d2
12145        bra.b           fsqrt_sd_unfl_dis
12146
12147#
12148# operand WILL overflow.
12149#
12150fsqrt_sd_ovfl:
12151        fmov.l          &0x0,%fpsr              # clear FPSR
12152        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
12153
12154        fsqrt.x         FP_SCR0(%a6),%fp0       # perform square root
12155
12156        fmov.l          &0x0,%fpcr              # clear FPCR
12157        fmov.l          %fpsr,%d1               # save FPSR
12158
12159        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
12160
12161fsqrt_sd_ovfl_tst:
12162        or.l            &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
12163
12164        mov.b           FPCR_ENABLE(%a6),%d1
12165        andi.b          &0x13,%d1               # is OVFL or INEX enabled?
12166        bne.b           fsqrt_sd_ovfl_ena       # yes
12167
12168#
12169# OVFL is not enabled; therefore, we must create the default result by
12170# calling ovf_res().
12171#
12172fsqrt_sd_ovfl_dis:
12173        btst            &neg_bit,FPSR_CC(%a6)   # is result negative?
12174        sne             %d1                     # set sign param accordingly
12175        mov.l           L_SCR3(%a6),%d0         # pass: prec,mode
12176        bsr.l           ovf_res                 # calculate default result
12177        or.b            %d0,FPSR_CC(%a6)        # set INF,N if applicable
12178        fmovm.x         (%a0),&0x80             # return default result in fp0
12179        rts
12180
12181#
12182# OVFL is enabled.
12183# the INEX2 bit has already been updated by the round to the correct precision.
12184# now, round to extended(and don't alter the FPSR).
12185#
12186fsqrt_sd_ovfl_ena:
12187        mov.l           %d2,-(%sp)              # save d2
12188        mov.w           FP_SCR0_EX(%a6),%d1     # fetch {sgn,exp}
12189        mov.l           %d1,%d2                 # make a copy
12190        andi.l          &0x7fff,%d1             # strip sign
12191        andi.w          &0x8000,%d2             # keep old sign
12192        sub.l           %d0,%d1                 # add scale factor
12193        subi.l          &0x6000,%d1             # subtract bias
12194        andi.w          &0x7fff,%d1
12195        or.w            %d2,%d1                 # concat sign,exp
12196        mov.w           %d1,FP_SCR0_EX(%a6)     # insert new exponent
12197        fmovm.x         FP_SCR0(%a6),&0x40      # return EXOP in fp1
12198        mov.l           (%sp)+,%d2              # restore d2
12199        bra.b           fsqrt_sd_ovfl_dis
12200
12201#
12202# the move in MAY underflow. so...
12203#
12204fsqrt_sd_may_ovfl:
12205        btst            &0x0,1+FP_SCR0_EX(%a6)  # is exponent 0x3fff?
12206        bne.w           fsqrt_sd_ovfl           # yes, so overflow
12207
12208        fmov.l          &0x0,%fpsr              # clear FPSR
12209        fmov.l          L_SCR3(%a6),%fpcr       # set FPCR
12210
12211        fsqrt.x         FP_SCR0(%a6),%fp0       # perform absolute
12212
12213        fmov.l          %fpsr,%d1               # save status
12214        fmov.l          &0x0,%fpcr              # clear FPCR
12215
12216        or.l            %d1,USER_FPSR(%a6)      # save INEX2,N
12217
12218        fmov.x          %fp0,%fp1               # make a copy of result
12219        fcmp.b          %fp1,&0x1               # is |result| >= 1.b?
12220        fbge.w          fsqrt_sd_ovfl_tst       # yes; overflow has occurred
12221
12222# no, it didn't overflow; we have correct result
12223        bra.w           fsqrt_sd_normal_exit
12224
12225##########################################################################
12226
12227#
12228# input is not normalized; what is it?
12229#
12230fsqrt_not_norm:
12231        cmpi.b          %d1,&DENORM             # weed out DENORM
12232        beq.w           fsqrt_denorm
12233        cmpi.b          %d1,&ZERO               # weed out ZERO
12234        beq.b           fsqrt_zero
12235        cmpi.b          %d1,&INF                # weed out INF
12236        beq.b           fsqrt_inf
12237        cmpi.b          %d1,&SNAN               # weed out SNAN
12238        beq.l           res_snan_1op
12239        bra.l           res_qnan_1op
12240
12241#
12242#       fsqrt(+0) = +0
12243#       fsqrt(-0) = -0
12244#       fsqrt(+INF) = +INF
12245#       fsqrt(-INF) = OPERR
12246#
12247fsqrt_zero:
12248        tst.b           SRC_EX(%a0)             # is ZERO positive or negative?
12249        bmi.b           fsqrt_zero_m            # negative
12250fsqrt_zero_p:
12251        fmov.s          &0x00000000,%fp0        # return +ZERO
12252        mov.b           &z_bmask,FPSR_CC(%a6)   # set 'Z' ccode bit
12253        rts
12254fsqrt_zero_m:
12255        fmov.s          &0x80000000,%fp0        # return -ZERO
12256        mov.b           &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
12257        rts
12258
12259fsqrt_inf:
12260        tst.b           SRC_EX(%a0)             # is INF positive or negative?
12261        bmi.l           res_operr               # negative
12262fsqrt_inf_p:
12263        fmovm.x         SRC(%a0),&0x80          # return +INF in fp0
12264        mov.b           &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
12265        rts
12266
12267#########################################################################
12268# XDEF **************************************************************** #
12269#       fetch_dreg(): fetch register according to index in d1           #
12270#                                                                       #
12271# XREF **************************************************************** #
12272#       None                                                            #
12273#                                                                       #
12274# INPUT *************************************************************** #
12275#       d1 = index of register to fetch from                            #
12276#                                                                       #
12277# OUTPUT ************************************************************** #
12278#       d0 = value of register fetched                                  #
12279#                                                                       #
12280# ALGORITHM *********************************************************** #
12281#       According to the index value in d1 which can range from zero    #
12282# to fifteen, load the corresponding register file value (where         #
12283# address register indexes start at 8). D0/D1/A0/A1/A6/A7 are on the    #
12284# stack. The rest should still be in their original places.             #
12285#                                                                       #
12286#########################################################################
12287
12288# this routine leaves d1 intact for subsequent store_dreg calls.
12289        global          fetch_dreg
12290fetch_dreg:
12291        mov.w           (tbl_fdreg.b,%pc,%d1.w*2),%d0
12292        jmp             (tbl_fdreg.b,%pc,%d0.w*1)
12293
12294tbl_fdreg:
12295        short           fdreg0 - tbl_fdreg
12296        short           fdreg1 - tbl_fdreg
12297        short           fdreg2 - tbl_fdreg
12298        short           fdreg3 - tbl_fdreg
12299        short           fdreg4 - tbl_fdreg
12300        short           fdreg5 - tbl_fdreg
12301        short           fdreg6 - tbl_fdreg
12302        short           fdreg7 - tbl_fdreg
12303        short           fdreg8 - tbl_fdreg
12304        short           fdreg9 - tbl_fdreg
12305        short           fdrega - tbl_fdreg
12306        short           fdregb - tbl_fdreg
12307        short           fdregc - tbl_fdreg
12308        short           fdregd - tbl_fdreg
12309        short           fdrege - tbl_fdreg
12310        short           fdregf - tbl_fdreg
12311
12312fdreg0:
12313        mov.l           EXC_DREGS+0x0(%a6),%d0
12314        rts
12315fdreg1:
12316        mov.l           EXC_DREGS+0x4(%a6),%d0
12317        rts
12318fdreg2:
12319        mov.l           %d2,%d0
12320        rts
12321fdreg3:
12322        mov.l           %d3,%d0
12323        rts
12324fdreg4:
12325        mov.l           %d4,%d0
12326        rts
12327fdreg5:
12328        mov.l           %d5,%d0
12329        rts
12330fdreg6:
12331        mov.l           %d6,%d0
12332        rts
12333fdreg7:
12334        mov.l           %d7,%d0
12335        rts
12336fdreg8:
12337        mov.l           EXC_DREGS+0x8(%a6),%d0
12338        rts
12339fdreg9:
12340        mov.l           EXC_DREGS+0xc(%a6),%d0
12341        rts
12342fdrega:
12343        mov.l           %a2,%d0
12344        rts
12345fdregb:
12346        mov.l           %a3,%d0
12347        rts
12348fdregc:
12349        mov.l           %a4,%d0
12350        rts
12351fdregd:
12352        mov.l           %a5,%d0
12353        rts
12354fdrege:
12355        mov.l           (%a6),%d0
12356        rts
12357fdregf:
12358        mov.l           EXC_A7(%a6),%d0
12359        rts
12360
12361#########################################################################
12362# XDEF **************************************************************** #
12363#       store_dreg_l(): store longword to data register specified by d1 #
12364#                                                                       #
12365# XREF **************************************************************** #
12366#       None                                                            #
12367#                                                                       #
12368# INPUT *************************************************************** #
12369#       d0 = longowrd value to store                                    #
12370#       d1 = index of register to fetch from                            #
12371#                                                                       #
12372# OUTPUT ************************************************************** #
12373#       (data register is updated)                                      #
12374#                                                                       #
12375# ALGORITHM *********************************************************** #
12376#       According to the index value in d1, store the longword value    #
12377# in d0 to the corresponding data register. D0/D1 are on the stack      #
12378# while the rest are in their initial places.                           #
12379#                                                                       #
12380#########################################################################
12381
12382        global          store_dreg_l
12383store_dreg_l:
12384        mov.w           (tbl_sdregl.b,%pc,%d1.w*2),%d1
12385        jmp             (tbl_sdregl.b,%pc,%d1.w*1)
12386
12387tbl_sdregl:
12388        short           sdregl0 - tbl_sdregl
12389        short           sdregl1 - tbl_sdregl
12390        short           sdregl2 - tbl_sdregl
12391        short           sdregl3 - tbl_sdregl
12392        short           sdregl4 - tbl_sdregl
12393        short           sdregl5 - tbl_sdregl
12394        short           sdregl6 - tbl_sdregl
12395        short           sdregl7 - tbl_sdregl
12396
12397sdregl0:
12398        mov.l           %d0,EXC_DREGS+0x0(%a6)
12399        rts
12400sdregl1:
12401        mov.l           %d0,EXC_DREGS+0x4(%a6)
12402        rts
12403sdregl2:
12404        mov.l           %d0,%d2
12405        rts
12406sdregl3:
12407        mov.l           %d0,%d3
12408        rts
12409sdregl4:
12410        mov.l           %d0,%d4
12411        rts
12412sdregl5:
12413        mov.l           %d0,%d5
12414        rts
12415sdregl6:
12416        mov.l           %d0,%d6
12417        rts
12418sdregl7:
12419        mov.l           %d0,%d7
12420        rts
12421
12422#########################################################################
12423# XDEF **************************************************************** #
12424#       store_dreg_w(): store word to data register specified by d1     #
12425#                                                                       #
12426# XREF **************************************************************** #
12427#       None                                                            #
12428#                                                                       #
12429# INPUT *************************************************************** #
12430#       d0 = word value to store                                        #
12431#       d1 = index of register to fetch from                            #
12432#                                                                       #
12433# OUTPUT ************************************************************** #
12434#       (data register is updated)                                      #
12435#                                                                       #
12436# ALGORITHM *********************************************************** #
12437#       According to the index value in d1, store the word value        #
12438# in d0 to the corresponding data register. D0/D1 are on the stack      #
12439# while the rest are in their initial places.                           #
12440#                                                                       #
12441#########################################################################
12442
12443        global          store_dreg_w
12444store_dreg_w:
12445        mov.w           (tbl_sdregw.b,%pc,%d1.w*2),%d1
12446        jmp             (tbl_sdregw.b,%pc,%d1.w*1)
12447
12448tbl_sdregw:
12449        short           sdregw0 - tbl_sdregw
12450        short           sdregw1 - tbl_sdregw
12451        short           sdregw2 - tbl_sdregw
12452        short           sdregw3 - tbl_sdregw
12453        short           sdregw4 - tbl_sdregw
12454        short           sdregw5 - tbl_sdregw
12455        short           sdregw6 - tbl_sdregw
12456        short           sdregw7 - tbl_sdregw
12457
12458sdregw0:
12459        mov.w           %d0,2+EXC_DREGS+0x0(%a6)
12460        rts
12461sdregw1:
12462        mov.w           %d0,2+EXC_DREGS+0x4(%a6)
12463        rts
12464sdregw2:
12465        mov.w           %d0,%d2
12466        rts
12467sdregw3:
12468        mov.w           %d0,%d3
12469        rts
12470sdregw4:
12471        mov.w           %d0,%d4
12472        rts
12473sdregw5:
12474        mov.w           %d0,%d5
12475        rts
12476sdregw6:
12477        mov.w           %d0,%d6
12478        rts
12479sdregw7:
12480        mov.w           %d0,%d7
12481        rts
12482
12483#########################################################################
12484# XDEF **************************************************************** #
12485#       store_dreg_b(): store byte to data register specified by d1     #
12486#                                                                       #
12487# XREF **************************************************************** #
12488#       None                                                            #
12489#                                                                       #
12490# INPUT *************************************************************** #
12491#       d0 = byte value to store                                        #
12492#       d1 = index of register to fetch from                            #
12493#                                                                       #
12494# OUTPUT ************************************************************** #
12495#       (data register is updated)                                      #
12496#                                                                       #
12497# ALGORITHM *********************************************************** #
12498#       According to the index value in d1, store the byte value        #
12499# in d0 to the corresponding data register. D0/D1 are on the stack      #
12500# while the rest are in their initial places.                           #
12501#                                                                       #
12502#########################################################################
12503
12504        global          store_dreg_b
12505store_dreg_b:
12506        mov.w           (tbl_sdregb.b,%pc,%d1.w*2),%d1
12507        jmp             (tbl_sdregb.b,%pc,%d1.w*1)
12508
12509tbl_sdregb:
12510        short           sdregb0 - tbl_sdregb
12511        short           sdregb1 - tbl_sdregb
12512        short           sdregb2 - tbl_sdregb
12513        short           sdregb3 - tbl_sdregb
12514        short           sdregb4 - tbl_sdregb
12515        short           sdregb5 - tbl_sdregb
12516        short           sdregb6 - tbl_sdregb
12517        short           sdregb7 - tbl_sdregb
12518
12519sdregb0:
12520        mov.b           %d0,3+EXC_DREGS+0x0(%a6)
12521        rts
12522sdregb1:
12523        mov.b           %d0,3+EXC_DREGS+0x4(%a6)
12524        rts
12525sdregb2:
12526        mov.b           %d0,%d2
12527        rts
12528sdregb3:
12529        mov.b           %d0,%d3
12530        rts
12531sdregb4:
12532        mov.b           %d0,%d4
12533        rts
12534sdregb5:
12535        mov.b           %d0,%d5
12536        rts
12537sdregb6:
12538        mov.b           %d0,%d6
12539        rts
12540sdregb7:
12541        mov.b           %d0,%d7
12542        rts
12543
12544#########################################################################
12545# XDEF **************************************************************** #
12546#       inc_areg(): increment an address register by the value in d0    #
12547#                                                                       #
12548# XREF **************************************************************** #
12549#       None                                                            #
12550#                                                                       #
12551# INPUT *************************************************************** #
12552#       d0 = amount to increment by                                     #
12553#       d1 = index of address register to increment                     #
12554#                                                                       #
12555# OUTPUT ************************************************************** #
12556#       (address register is updated)                                   #
12557#                                                                       #
12558# ALGORITHM *********************************************************** #
12559#       Typically used for an instruction w/ a post-increment <ea>,     #
12560# this routine adds the increment value in d0 to the address register   #
12561# specified by d1. A0/A1/A6/A7 reside on the stack. The rest reside     #
12562# in their original places.                                             #
12563#       For a7, if the increment amount is one, then we have to         #
12564# increment by two. For any a7 update, set the mia7_flag so that if     #
12565# an access error exception occurs later in emulation, this address     #
12566# register update can be undone.                                        #
12567#                                                                       #
12568#########################################################################
12569
12570        global          inc_areg
12571inc_areg:
12572        mov.w           (tbl_iareg.b,%pc,%d1.w*2),%d1
12573        jmp             (tbl_iareg.b,%pc,%d1.w*1)
12574
12575tbl_iareg:
12576        short           iareg0 - tbl_iareg
12577        short           iareg1 - tbl_iareg
12578        short           iareg2 - tbl_iareg
12579        short           iareg3 - tbl_iareg
12580        short           iareg4 - tbl_iareg
12581        short           iareg5 - tbl_iareg
12582        short           iareg6 - tbl_iareg
12583        short           iareg7 - tbl_iareg
12584
12585iareg0: add.l           %d0,EXC_DREGS+0x8(%a6)
12586        rts
12587iareg1: add.l           %d0,EXC_DREGS+0xc(%a6)
12588        rts
12589iareg2: add.l           %d0,%a2
12590        rts
12591iareg3: add.l           %d0,%a3
12592        rts
12593iareg4: add.l           %d0,%a4
12594        rts
12595iareg5: add.l           %d0,%a5
12596        rts
12597iareg6: add.l           %d0,(%a6)
12598        rts
12599iareg7: mov.b           &mia7_flg,SPCOND_FLG(%a6)
12600        cmpi.b          %d0,&0x1
12601        beq.b           iareg7b
12602        add.l           %d0,EXC_A7(%a6)
12603        rts
12604iareg7b:
12605        addq.l          &0x2,EXC_A7(%a6)
12606        rts
12607
12608#########################################################################
12609# XDEF **************************************************************** #
12610#       dec_areg(): decrement an address register by the value in d0    #
12611#                                                                       #
12612# XREF **************************************************************** #
12613#       None                                                            #
12614#                                                                       #
12615# INPUT *************************************************************** #
12616#       d0 = amount to decrement by                                     #
12617#       d1 = index of address register to decrement                     #
12618#                                                                       #
12619# OUTPUT ************************************************************** #
12620#       (address register is updated)                                   #
12621#                                                                       #
12622# ALGORITHM *********************************************************** #
12623#       Typically used for an instruction w/ a pre-decrement <ea>,      #
12624# this routine adds the decrement value in d0 to the address register   #
12625# specified by d1. A0/A1/A6/A7 reside on the stack. The rest reside     #
12626# in their original places.                                             #
12627#       For a7, if the decrement amount is one, then we have to         #
12628# decrement by two. For any a7 update, set the mda7_flag so that if     #
12629# an access error exception occurs later in emulation, this address     #
12630# register update can be undone.                                        #
12631#                                                                       #
12632#########################################################################
12633
12634        global          dec_areg
12635dec_areg:
12636        mov.w           (tbl_dareg.b,%pc,%d1.w*2),%d1
12637        jmp             (tbl_dareg.b,%pc,%d1.w*1)
12638
12639tbl_dareg:
12640        short           dareg0 - tbl_dareg
12641        short           dareg1 - tbl_dareg
12642        short           dareg2 - tbl_dareg
12643        short           dareg3 - tbl_dareg
12644        short           dareg4 - tbl_dareg
12645        short           dareg5 - tbl_dareg
12646        short           dareg6 - tbl_dareg
12647        short           dareg7 - tbl_dareg
12648
12649dareg0: sub.l           %d0,EXC_DREGS+0x8(%a6)
12650        rts
12651dareg1: sub.l           %d0,EXC_DREGS+0xc(%a6)
12652        rts
12653dareg2: sub.l           %d0,%a2
12654        rts
12655dareg3: sub.l           %d0,%a3
12656        rts
12657dareg4: sub.l           %d0,%a4
12658        rts
12659dareg5: sub.l           %d0,%a5
12660        rts
12661dareg6: sub.l           %d0,(%a6)
12662        rts
12663dareg7: mov.b           &mda7_flg,SPCOND_FLG(%a6)
12664        cmpi.b          %d0,&0x1
12665        beq.b           dareg7b
12666        sub.l           %d0,EXC_A7(%a6)
12667        rts
12668dareg7b:
12669        subq.l          &0x2,EXC_A7(%a6)
12670        rts
12671
12672##############################################################################
12673
12674#########################################################################
12675# XDEF **************************************************************** #
12676#       load_fpn1(): load FP register value into FP_SRC(a6).            #
12677#                                                                       #
12678# XREF **************************************************************** #
12679#       None                                                            #
12680#                                                                       #
12681# INPUT *************************************************************** #
12682#       d0 = index of FP register to load                               #
12683#                                                                       #
12684# OUTPUT ************************************************************** #
12685#       FP_SRC(a6) = value loaded from FP register file                 #
12686#                                                                       #
12687# ALGORITHM *********************************************************** #
12688#       Using the index in d0, load FP_SRC(a6) with a number from the   #
12689# FP register file.                                                     #
12690#                                                                       #
12691#########################################################################
12692
12693        global          load_fpn1
12694load_fpn1:
12695        mov.w           (tbl_load_fpn1.b,%pc,%d0.w*2), %d0
12696        jmp             (tbl_load_fpn1.b,%pc,%d0.w*1)
12697
12698tbl_load_fpn1:
12699        short           load_fpn1_0 - tbl_load_fpn1
12700        short           load_fpn1_1 - tbl_load_fpn1
12701        short           load_fpn1_2 - tbl_load_fpn1
12702        short           load_fpn1_3 - tbl_load_fpn1
12703        short           load_fpn1_4 - tbl_load_fpn1
12704        short           load_fpn1_5 - tbl_load_fpn1
12705        short           load_fpn1_6 - tbl_load_fpn1
12706        short           load_fpn1_7 - tbl_load_fpn1
12707
12708load_fpn1_0:
12709        mov.l           0+EXC_FP0(%a6), 0+FP_SRC(%a6)
12710        mov.l           4+EXC_FP0(%a6), 4+FP_SRC(%a6)
12711        mov.l           8+EXC_FP0(%a6), 8+FP_SRC(%a6)
12712        lea             FP_SRC(%a6), %a0
12713        rts
12714load_fpn1_1:
12715        mov.l           0+EXC_FP1(%a6), 0+FP_SRC(%a6)
12716        mov.l           4+EXC_FP1(%a6), 4+FP_SRC(%a6)
12717        mov.l           8+EXC_FP1(%a6), 8+FP_SRC(%a6)
12718        lea             FP_SRC(%a6), %a0
12719        rts
12720load_fpn1_2:
12721        fmovm.x         &0x20, FP_SRC(%a6)
12722        lea             FP_SRC(%a6), %a0
12723        rts
12724load_fpn1_3:
12725        fmovm.x         &0x10, FP_SRC(%a6)
12726        lea             FP_SRC(%a6), %a0
12727        rts
12728load_fpn1_4:
12729        fmovm.x         &0x08, FP_SRC(%a6)
12730        lea             FP_SRC(%a6), %a0
12731        rts
12732load_fpn1_5:
12733        fmovm.x         &0x04, FP_SRC(%a6)
12734        lea             FP_SRC(%a6), %a0
12735        rts
12736load_fpn1_6:
12737        fmovm.x         &0x02, FP_SRC(%a6)
12738        lea             FP_SRC(%a6), %a0
12739        rts
12740load_fpn1_7:
12741        fmovm.x         &0x01, FP_SRC(%a6)
12742        lea             FP_SRC(%a6), %a0
12743        rts
12744
12745#############################################################################
12746
12747#########################################################################
12748# XDEF **************************************************************** #
12749#       load_fpn2(): load FP register value into FP_DST(a6).            #
12750#                                                                       #
12751# XREF **************************************************************** #
12752#       None                                                            #
12753#                                                                       #
12754# INPUT *************************************************************** #
12755#       d0 = index of FP register to load                               #
12756#                                                                       #
12757# OUTPUT ************************************************************** #
12758#       FP_DST(a6) = value loaded from FP register file                 #
12759#                                                                       #
12760# ALGORITHM *********************************************************** #
12761#       Using the index in d0, load FP_DST(a6) with a number from the   #
12762# FP register file.                                                     #
12763#                                                                       #
12764#########################################################################
12765
12766        global          load_fpn2
12767load_fpn2:
12768        mov.w           (tbl_load_fpn2.b,%pc,%d0.w*2), %d0
12769        jmp             (tbl_load_fpn2.b,%pc,%d0.w*1)
12770
12771tbl_load_fpn2:
12772        short           load_fpn2_0 - tbl_load_fpn2
12773        short           load_fpn2_1 - tbl_load_fpn2
12774        short           load_fpn2_2 - tbl_load_fpn2
12775        short           load_fpn2_3 - tbl_load_fpn2
12776        short           load_fpn2_4 - tbl_load_fpn2
12777        short           load_fpn2_5 - tbl_load_fpn2
12778        short           load_fpn2_6 - tbl_load_fpn2
12779        short           load_fpn2_7 - tbl_load_fpn2
12780
12781load_fpn2_0:
12782        mov.l           0+EXC_FP0(%a6), 0+FP_DST(%a6)
12783        mov.l           4+EXC_FP0(%a6), 4+FP_DST(%a6)
12784        mov.l           8+EXC_FP0(%a6), 8+FP_DST(%a6)
12785        lea             FP_DST(%a6), %a0
12786        rts
12787load_fpn2_1:
12788        mov.l           0+EXC_FP1(%a6), 0+FP_DST(%a6)
12789        mov.l           4+EXC_FP1(%a6), 4+FP_DST(%a6)
12790        mov.l           8+EXC_FP1(%a6), 8+FP_DST(%a6)
12791        lea             FP_DST(%a6), %a0
12792        rts
12793load_fpn2_2:
12794        fmovm.x         &0x20, FP_DST(%a6)
12795        lea             FP_DST(%a6), %a0
12796        rts
12797load_fpn2_3:
12798        fmovm.x         &0x10, FP_DST(%a6)
12799        lea             FP_DST(%a6), %a0
12800        rts
12801load_fpn2_4:
12802        fmovm.x         &0x08, FP_DST(%a6)
12803        lea             FP_DST(%a6), %a0
12804        rts
12805load_fpn2_5:
12806        fmovm.x         &0x04, FP_DST(%a6)
12807        lea             FP_DST(%a6), %a0
12808        rts
12809load_fpn2_6:
12810        fmovm.x         &0x02, FP_DST(%a6)
12811        lea             FP_DST(%a6), %a0
12812        rts
12813load_fpn2_7:
12814        fmovm.x         &0x01, FP_DST(%a6)
12815        lea             FP_DST(%a6), %a0
12816        rts
12817
12818#############################################################################
12819
12820#########################################################################
12821# XDEF **************************************************************** #
12822#       store_fpreg(): store an fp value to the fpreg designated d0.    #
12823#                                                                       #
12824# XREF **************************************************************** #
12825#       None                                                            #
12826#                                                                       #
12827# INPUT *************************************************************** #
12828#       fp0 = extended precision value to store                         #
12829#       d0  = index of floating-point register                          #
12830#                                                                       #
12831# OUTPUT ************************************************************** #
12832#       None                                                            #
12833#                                                                       #
12834# ALGORITHM *********************************************************** #
12835#       Store the value in fp0 to the FP register designated by the     #
12836# value in d0. The FP number can be DENORM or SNAN so we have to be     #
12837# careful that we don't take an exception here.                         #
12838#                                                                       #
12839#########################################################################
12840
12841        global          store_fpreg
12842store_fpreg:
12843        mov.w           (tbl_store_fpreg.b,%pc,%d0.w*2), %d0
12844        jmp             (tbl_store_fpreg.b,%pc,%d0.w*1)
12845
12846tbl_store_fpreg:
12847        short           store_fpreg_0 - tbl_store_fpreg
12848        short           store_fpreg_1 - tbl_store_fpreg
12849        short           store_fpreg_2 - tbl_store_fpreg
12850        short           store_fpreg_3 - tbl_store_fpreg
12851        short           store_fpreg_4 - tbl_store_fpreg
12852        short           store_fpreg_5 - tbl_store_fpreg
12853        short           store_fpreg_6 - tbl_store_fpreg
12854        short           store_fpreg_7 - tbl_store_fpreg
12855
12856store_fpreg_0:
12857        fmovm.x         &0x80, EXC_FP0(%a6)
12858        rts
12859store_fpreg_1:
12860        fmovm.x         &0x80, EXC_FP1(%a6)
12861        rts
12862store_fpreg_2:
12863        fmovm.x         &0x01, -(%sp)
12864        fmovm.x         (%sp)+, &0x20
12865        rts
12866store_fpreg_3:
12867        fmovm.x         &0x01, -(%sp)
12868        fmovm.x         (%sp)+, &0x10
12869        rts
12870store_fpreg_4:
12871        fmovm.x         &0x01, -(%sp)
12872        fmovm.x         (%sp)+, &0x08
12873        rts
12874store_fpreg_5:
12875        fmovm.x         &0x01, -(%sp)
12876        fmovm.x         (%sp)+, &0x04
12877        rts
12878store_fpreg_6:
12879        fmovm.x         &0x01, -(%sp)
12880        fmovm.x         (%sp)+, &0x02
12881        rts
12882store_fpreg_7:
12883        fmovm.x         &0x01, -(%sp)
12884        fmovm.x         (%sp)+, &0x01
12885        rts
12886
12887#########################################################################
12888# XDEF **************************************************************** #
12889#       get_packed(): fetch a packed operand from memory and then       #
12890#                     convert it to a floating-point binary number.     #
12891#                                                                       #
12892# XREF **************************************************************** #
12893#       _dcalc_ea() - calculate the correct <ea>                        #
12894#       _mem_read() - fetch the packed operand from memory              #
12895#       facc_in_x() - the fetch failed so jump to special exit code     #
12896#       decbin()    - convert packed to binary extended precision       #
12897#                                                                       #
12898# INPUT *************************************************************** #
12899#       None                                                            #
12900#                                                                       #
12901# OUTPUT ************************************************************** #
12902#       If no failure on _mem_read():                                   #
12903#       FP_SRC(a6) = packed operand now as a binary FP number           #
12904#                                                                       #
12905# ALGORITHM *********************************************************** #
12906#       Get the correct <ea> which is the value on the exception stack  #
12907# frame w/ maybe a correction factor if the <ea> is -(an) or (an)+.     #
12908# Then, fetch the operand from memory. If the fetch fails, exit         #
12909# through facc_in_x().                                                  #
12910#       If the packed operand is a ZERO,NAN, or INF, convert it to      #
12911# its binary representation here. Else, call decbin() which will        #
12912# convert the packed value to an extended precision binary value.       #
12913#                                                                       #
12914#########################################################################
12915
12916# the stacked <ea> for packed is correct except for -(An).
12917# the base reg must be updated for both -(An) and (An)+.
12918        global          get_packed
12919get_packed:
12920        mov.l           &0xc,%d0                # packed is 12 bytes
12921        bsr.l           _dcalc_ea               # fetch <ea>; correct An
12922
12923        lea             FP_SRC(%a6),%a1         # pass: ptr to super dst
12924        mov.l           &0xc,%d0                # pass: 12 bytes
12925        bsr.l           _dmem_read              # read packed operand
12926
12927        tst.l           %d1                     # did dfetch fail?
12928        bne.l           facc_in_x               # yes
12929
12930# The packed operand is an INF or a NAN if the exponent field is all ones.
12931        bfextu          FP_SRC(%a6){&1:&15},%d0 # get exp
12932        cmpi.w          %d0,&0x7fff             # INF or NAN?
12933        bne.b           gp_try_zero             # no
12934        rts                                     # operand is an INF or NAN
12935
12936# The packed operand is a zero if the mantissa is all zero, else it's
12937# a normal packed op.
12938gp_try_zero:
12939        mov.b           3+FP_SRC(%a6),%d0       # get byte 4
12940        andi.b          &0x0f,%d0               # clear all but last nybble
12941        bne.b           gp_not_spec             # not a zero
12942        tst.l           FP_SRC_HI(%a6)          # is lw 2 zero?
12943        bne.b           gp_not_spec             # not a zero
12944        tst.l           FP_SRC_LO(%a6)          # is lw 3 zero?
12945        bne.b           gp_not_spec             # not a zero
12946        rts                                     # operand is a ZERO
12947gp_not_spec:
12948        lea             FP_SRC(%a6),%a0         # pass: ptr to packed op
12949        bsr.l           decbin                  # convert to extended
12950        fmovm.x         &0x80,FP_SRC(%a6)       # make this the srcop
12951        rts
12952
12953#########################################################################
12954# decbin(): Converts normalized packed bcd value pointed to by register #
12955#           a0 to extended-precision value in fp0.                      #
12956#                                                                       #
12957# INPUT *************************************************************** #
12958#       a0 = pointer to normalized packed bcd value                     #
12959#                                                                       #
12960# OUTPUT ************************************************************** #
12961#       fp0 = exact fp representation of the packed bcd value.          #
12962#                                                                       #
12963# ALGORITHM *********************************************************** #
12964#       Expected is a normal bcd (i.e. non-exceptional; all inf, zero,  #
12965#       and NaN operands are dispatched without entering this routine)  #
12966#       value in 68881/882 format at location (a0).                     #
12967#                                                                       #
12968#       A1. Convert the bcd exponent to binary by successive adds and   #
12969#       muls. Set the sign according to SE. Subtract 16 to compensate   #
12970#       for the mantissa which is to be interpreted as 17 integer       #
12971#       digits, rather than 1 integer and 16 fraction digits.           #
12972#       Note: this operation can never overflow.                        #
12973#                                                                       #
12974#       A2. Convert the bcd mantissa to binary by successive            #
12975#       adds and muls in FP0. Set the sign according to SM.             #
12976#       The mantissa digits will be converted with the decimal point    #
12977#       assumed following the least-significant digit.                  #
12978#       Note: this operation can never overflow.                        #
12979#                                                                       #
12980#       A3. Count the number of leading/trailing zeros in the           #
12981#       bcd string.  If SE is positive, count the leading zeros;        #
12982#       if negative, count the trailing zeros.  Set the adjusted        #
12983#       exponent equal to the exponent from A1 and the zero count       #
12984#       added if SM = 1 and subtracted if SM = 0.  Scale the            #
12985#       mantissa the equivalent of forcing in the bcd value:            #
12986#                                                                       #
12987#       SM = 0  a non-zero digit in the integer position                #
12988#       SM = 1  a non-zero digit in Mant0, lsd of the fraction          #
12989#                                                                       #
12990#       this will insure that any value, regardless of its              #
12991#       representation (ex. 0.1E2, 1E1, 10E0, 100E-1), is converted     #
12992#       consistently.                                                   #
12993#                                                                       #
12994#       A4. Calculate the factor 10^exp in FP1 using a table of         #
12995#       10^(2^n) values.  To reduce the error in forming factors        #
12996#       greater than 10^27, a directed rounding scheme is used with     #
12997#       tables rounded to RN, RM, and RP, according to the table        #
12998#       in the comments of the pwrten section.                          #
12999#                                                                       #
13000#       A5. Form the final binary number by scaling the mantissa by     #
13001#       the exponent factor.  This is done by multiplying the           #
13002#       mantissa in FP0 by the factor in FP1 if the adjusted            #
13003#       exponent sign is positive, and dividing FP0 by FP1 if           #
13004#       it is negative.                                                 #
13005#                                                                       #
13006#       Clean up and return. Check if the final mul or div was inexact. #
13007#       If so, set INEX1 in USER_FPSR.                                  #
13008#                                                                       #
13009#########################################################################
13010
13011#
13012#       PTENRN, PTENRM, and PTENRP are arrays of powers of 10 rounded
13013#       to nearest, minus, and plus, respectively.  The tables include
13014#       10**{1,2,4,8,16,32,64,128,256,512,1024,2048,4096}.  No rounding
13015#       is required until the power is greater than 27, however, all
13016#       tables include the first 5 for ease of indexing.
13017#
13018RTABLE:
13019        byte            0,0,0,0
13020        byte            2,3,2,3
13021        byte            2,3,3,2
13022        byte            3,2,2,3
13023
13024        set             FNIBS,7
13025        set             FSTRT,0
13026
13027        set             ESTRT,4
13028        set             EDIGITS,2
13029
13030        global          decbin
13031decbin:
13032        mov.l           0x0(%a0),FP_SCR0_EX(%a6) # make a copy of input
13033        mov.l           0x4(%a0),FP_SCR0_HI(%a6) # so we don't alter it
13034        mov.l           0x8(%a0),FP_SCR0_LO(%a6)
13035
13036        lea             FP_SCR0(%a6),%a0
13037
13038        movm.l          &0x3c00,-(%sp)          # save d2-d5
13039        fmovm.x         &0x1,-(%sp)             # save fp1
13040#
13041# Calculate exponent:
13042#  1. Copy bcd value in memory for use as a working copy.
13043#  2. Calculate absolute value of exponent in d1 by mul and add.
13044#  3. Correct for exponent sign.
13045#  4. Subtract 16 to compensate for interpreting the mant as all integer digits.
13046#     (i.e., all digits assumed left of the decimal point.)
13047#
13048# Register usage:
13049#
13050#  calc_e:
13051#       (*)  d0: temp digit storage
13052#       (*)  d1: accumulator for binary exponent
13053#       (*)  d2: digit count
13054#       (*)  d3: offset pointer
13055#       ( )  d4: first word of bcd
13056#       ( )  a0: pointer to working bcd value
13057#       ( )  a6: pointer to original bcd value
13058#       (*)  FP_SCR1: working copy of original bcd value
13059#       (*)  L_SCR1: copy of original exponent word
13060#
13061calc_e:
13062        mov.l           &EDIGITS,%d2            # # of nibbles (digits) in fraction part
13063        mov.l           &ESTRT,%d3              # counter to pick up digits
13064        mov.l           (%a0),%d4               # get first word of bcd
13065        clr.l           %d1                     # zero d1 for accumulator
13066e_gd:
13067        mulu.l          &0xa,%d1                # mul partial product by one digit place
13068        bfextu          %d4{%d3:&4},%d0         # get the digit and zero extend into d0
13069        add.l           %d0,%d1                 # d1 = d1 + d0
13070        addq.b          &4,%d3                  # advance d3 to the next digit
13071        dbf.w           %d2,e_gd                # if we have used all 3 digits, exit loop
13072        btst            &30,%d4                 # get SE
13073        beq.b           e_pos                   # don't negate if pos
13074        neg.l           %d1                     # negate before subtracting
13075e_pos:
13076        sub.l           &16,%d1                 # sub to compensate for shift of mant
13077        bge.b           e_save                  # if still pos, do not neg
13078        neg.l           %d1                     # now negative, make pos and set SE
13079        or.l            &0x40000000,%d4         # set SE in d4,
13080        or.l            &0x40000000,(%a0)       # and in working bcd
13081e_save:
13082        mov.l           %d1,-(%sp)              # save exp on stack
13083#
13084#
13085# Calculate mantissa:
13086#  1. Calculate absolute value of mantissa in fp0 by mul and add.
13087#  2. Correct for mantissa sign.
13088#     (i.e., all digits assumed left of the decimal point.)
13089#
13090# Register usage:
13091#
13092#  calc_m:
13093#       (*)  d0: temp digit storage
13094#       (*)  d1: lword counter
13095#       (*)  d2: digit count
13096#       (*)  d3: offset pointer
13097#       ( )  d4: words 2 and 3 of bcd
13098#       ( )  a0: pointer to working bcd value
13099#       ( )  a6: pointer to original bcd value
13100#       (*) fp0: mantissa accumulator
13101#       ( )  FP_SCR1: working copy of original bcd value
13102#       ( )  L_SCR1: copy of original exponent word
13103#
13104calc_m:
13105        mov.l           &1,%d1                  # word counter, init to 1
13106        fmov.s          &0x00000000,%fp0        # accumulator
13107#
13108#
13109#  Since the packed number has a long word between the first & second parts,
13110#  get the integer digit then skip down & get the rest of the
13111#  mantissa.  We will unroll the loop once.
13112#
13113        bfextu          (%a0){&28:&4},%d0       # integer part is ls digit in long word
13114        fadd.b          %d0,%fp0                # add digit to sum in fp0
13115#
13116#
13117#  Get the rest of the mantissa.
13118#
13119loadlw:
13120        mov.l           (%a0,%d1.L*4),%d4       # load mantissa lonqword into d4
13121        mov.l           &FSTRT,%d3              # counter to pick up digits
13122        mov.l           &FNIBS,%d2              # reset number of digits per a0 ptr
13123md2b:
13124        fmul.s          &0x41200000,%fp0        # fp0 = fp0 * 10
13125        bfextu          %d4{%d3:&4},%d0         # get the digit and zero extend
13126        fadd.b          %d0,%fp0                # fp0 = fp0 + digit
13127#
13128#
13129#  If all the digits (8) in that long word have been converted (d2=0),
13130#  then inc d1 (=2) to point to the next long word and reset d3 to 0
13131#  to initialize the digit offset, and set d2 to 7 for the digit count;
13132#  else continue with this long word.
13133#
13134        addq.b          &4,%d3                  # advance d3 to the next digit
13135        dbf.w           %d2,md2b                # check for last digit in this lw
13136nextlw:
13137        addq.l          &1,%d1                  # inc lw pointer in mantissa
13138        cmp.l           %d1,&2                  # test for last lw
13139        ble.b           loadlw                  # if not, get last one
13140#
13141#  Check the sign of the mant and make the value in fp0 the same sign.
13142#
13143m_sign:
13144        btst            &31,(%a0)               # test sign of the mantissa
13145        beq.b           ap_st_z                 # if clear, go to append/strip zeros
13146        fneg.x          %fp0                    # if set, negate fp0
13147#
13148# Append/strip zeros:
13149#
13150#  For adjusted exponents which have an absolute value greater than 27*,
13151#  this routine calculates the amount needed to normalize the mantissa
13152#  for the adjusted exponent.  That number is subtracted from the exp
13153#  if the exp was positive, and added if it was negative.  The purpose
13154#  of this is to reduce the value of the exponent and the possibility
13155#  of error in calculation of pwrten.
13156#
13157#  1. Branch on the sign of the adjusted exponent.
13158#  2p.(positive exp)
13159#   2. Check M16 and the digits in lwords 2 and 3 in descending order.
13160#   3. Add one for each zero encountered until a non-zero digit.
13161#   4. Subtract the count from the exp.
13162#   5. Check if the exp has crossed zero in #3 above; make the exp abs
13163#          and set SE.
13164#       6. Multiply the mantissa by 10**count.
13165#  2n.(negative exp)
13166#   2. Check the digits in lwords 3 and 2 in descending order.
13167#   3. Add one for each zero encountered until a non-zero digit.
13168#   4. Add the count to the exp.
13169#   5. Check if the exp has crossed zero in #3 above; clear SE.
13170#   6. Divide the mantissa by 10**count.
13171#
13172#  *Why 27?  If the adjusted exponent is within -28 < expA < 28, than
13173#   any adjustment due to append/strip zeros will drive the resultane
13174#   exponent towards zero.  Since all pwrten constants with a power
13175#   of 27 or less are exact, there is no need to use this routine to
13176#   attempt to lessen the resultant exponent.
13177#
13178# Register usage:
13179#
13180#  ap_st_z:
13181#       (*)  d0: temp digit storage
13182#       (*)  d1: zero count
13183#       (*)  d2: digit count
13184#       (*)  d3: offset pointer
13185#       ( )  d4: first word of bcd
13186#       (*)  d5: lword counter
13187#       ( )  a0: pointer to working bcd value
13188#       ( )  FP_SCR1: working copy of original bcd value
13189#       ( )  L_SCR1: copy of original exponent word
13190#
13191#
13192# First check the absolute value of the exponent to see if this
13193# routine is necessary.  If so, then check the sign of the exponent
13194# and do append (+) or strip (-) zeros accordingly.
13195# This section handles a positive adjusted exponent.
13196#
13197ap_st_z:
13198        mov.l           (%sp),%d1               # load expA for range test
13199        cmp.l           %d1,&27                 # test is with 27
13200        ble.w           pwrten                  # if abs(expA) <28, skip ap/st zeros
13201        btst            &30,(%a0)               # check sign of exp
13202        bne.b           ap_st_n                 # if neg, go to neg side
13203        clr.l           %d1                     # zero count reg
13204        mov.l           (%a0),%d4               # load lword 1 to d4
13205        bfextu          %d4{&28:&4},%d0         # get M16 in d0
13206        bne.b           ap_p_fx                 # if M16 is non-zero, go fix exp
13207        addq.l          &1,%d1                  # inc zero count
13208        mov.l           &1,%d5                  # init lword counter
13209        mov.l           (%a0,%d5.L*4),%d4       # get lword 2 to d4
13210        bne.b           ap_p_cl                 # if lw 2 is zero, skip it
13211        addq.l          &8,%d1                  # and inc count by 8
13212        addq.l          &1,%d5                  # inc lword counter
13213        mov.l           (%a0,%d5.L*4),%d4       # get lword 3 to d4
13214ap_p_cl:
13215        clr.l           %d3                     # init offset reg
13216        mov.l           &7,%d2                  # init digit counter
13217ap_p_gd:
13218        bfextu          %d4{%d3:&4},%d0         # get digit
13219        bne.b           ap_p_fx                 # if non-zero, go to fix exp
13220        addq.l          &4,%d3                  # point to next digit
13221        addq.l          &1,%d1                  # inc digit counter
13222        dbf.w           %d2,ap_p_gd             # get next digit
13223ap_p_fx:
13224        mov.l           %d1,%d0                 # copy counter to d2
13225        mov.l           (%sp),%d1               # get adjusted exp from memory
13226        sub.l           %d0,%d1                 # subtract count from exp
13227        bge.b           ap_p_fm                 # if still pos, go to pwrten
13228        neg.l           %d1                     # now its neg; get abs
13229        mov.l           (%a0),%d4               # load lword 1 to d4
13230        or.l            &0x40000000,%d4         # and set SE in d4
13231        or.l            &0x40000000,(%a0)       # and in memory
13232#
13233# Calculate the mantissa multiplier to compensate for the striping of
13234# zeros from the mantissa.
13235#
13236ap_p_fm:
13237        lea.l           PTENRN(%pc),%a1         # get address of power-of-ten table
13238        clr.l           %d3                     # init table index
13239        fmov.s          &0x3f800000,%fp1        # init fp1 to 1
13240        mov.l           &3,%d2                  # init d2 to count bits in counter
13241ap_p_el:
13242        asr.l           &1,%d0                  # shift lsb into carry
13243        bcc.b           ap_p_en                 # if 1, mul fp1 by pwrten factor
13244        fmul.x          (%a1,%d3),%fp1          # mul by 10**(d3_bit_no)
13245ap_p_en:
13246        add.l           &12,%d3                 # inc d3 to next rtable entry
13247        tst.l           %d0                     # check if d0 is zero
13248        bne.b           ap_p_el                 # if not, get next bit
13249        fmul.x          %fp1,%fp0               # mul mantissa by 10**(no_bits_shifted)
13250        bra.b           pwrten                  # go calc pwrten
13251#
13252# This section handles a negative adjusted exponent.
13253#
13254ap_st_n:
13255        clr.l           %d1                     # clr counter
13256        mov.l           &2,%d5                  # set up d5 to point to lword 3
13257        mov.l           (%a0,%d5.L*4),%d4       # get lword 3
13258        bne.b           ap_n_cl                 # if not zero, check digits
13259        sub.l           &1,%d5                  # dec d5 to point to lword 2
13260        addq.l          &8,%d1                  # inc counter by 8
13261        mov.l           (%a0,%d5.L*4),%d4       # get lword 2
13262ap_n_cl:
13263        mov.l           &28,%d3                 # point to last digit
13264        mov.l           &7,%d2                  # init digit counter
13265ap_n_gd:
13266        bfextu          %d4{%d3:&4},%d0         # get digit
13267        bne.b           ap_n_fx                 # if non-zero, go to exp fix
13268        subq.l          &4,%d3                  # point to previous digit
13269        addq.l          &1,%d1                  # inc digit counter
13270        dbf.w           %d2,ap_n_gd             # get next digit
13271ap_n_fx:
13272        mov.l           %d1,%d0                 # copy counter to d0
13273        mov.l           (%sp),%d1               # get adjusted exp from memory
13274        sub.l           %d0,%d1                 # subtract count from exp
13275        bgt.b           ap_n_fm                 # if still pos, go fix mantissa
13276        neg.l           %d1                     # take abs of exp and clr SE
13277        mov.l           (%a0),%d4               # load lword 1 to d4
13278        and.l           &0xbfffffff,%d4         # and clr SE in d4
13279        and.l           &0xbfffffff,(%a0)       # and in memory
13280#
13281# Calculate the mantissa multiplier to compensate for the appending of
13282# zeros to the mantissa.
13283#
13284ap_n_fm:
13285        lea.l           PTENRN(%pc),%a1         # get address of power-of-ten table
13286        clr.l           %d3                     # init table index
13287        fmov.s          &0x3f800000,%fp1        # init fp1 to 1
13288        mov.l           &3,%d2                  # init d2 to count bits in counter
13289ap_n_el:
13290        asr.l           &1,%d0                  # shift lsb into carry
13291        bcc.b           ap_n_en                 # if 1, mul fp1 by pwrten factor
13292        fmul.x          (%a1,%d3),%fp1          # mul by 10**(d3_bit_no)
13293ap_n_en:
13294        add.l           &12,%d3                 # inc d3 to next rtable entry
13295        tst.l           %d0                     # check if d0 is zero
13296        bne.b           ap_n_el                 # if not, get next bit
13297        fdiv.x          %fp1,%fp0               # div mantissa by 10**(no_bits_shifted)
13298#
13299#
13300# Calculate power-of-ten factor from adjusted and shifted exponent.
13301#
13302# Register usage:
13303#
13304#  pwrten:
13305#       (*)  d0: temp
13306#       ( )  d1: exponent
13307#       (*)  d2: {FPCR[6:5],SM,SE} as index in RTABLE; temp
13308#       (*)  d3: FPCR work copy
13309#       ( )  d4: first word of bcd
13310#       (*)  a1: RTABLE pointer
13311#  calc_p:
13312#       (*)  d0: temp
13313#       ( )  d1: exponent
13314#       (*)  d3: PWRTxx table index
13315#       ( )  a0: pointer to working copy of bcd
13316#       (*)  a1: PWRTxx pointer
13317#       (*) fp1: power-of-ten accumulator
13318#
13319# Pwrten calculates the exponent factor in the selected rounding mode
13320# according to the following table:
13321#
13322#       Sign of Mant  Sign of Exp  Rounding Mode  PWRTEN Rounding Mode
13323#
13324#       ANY       ANY   RN      RN
13325#
13326#        +         +    RP      RP
13327#        -         +    RP      RM
13328#        +         -    RP      RM
13329#        -         -    RP      RP
13330#
13331#        +         +    RM      RM
13332#        -         +    RM      RP
13333#        +         -    RM      RP
13334#        -         -    RM      RM
13335#
13336#        +         +    RZ      RM
13337#        -         +    RZ      RM
13338#        +         -    RZ      RP
13339#        -         -    RZ      RP
13340#
13341#
13342pwrten:
13343        mov.l           USER_FPCR(%a6),%d3      # get user's FPCR
13344        bfextu          %d3{&26:&2},%d2         # isolate rounding mode bits
13345        mov.l           (%a0),%d4               # reload 1st bcd word to d4
13346        asl.l           &2,%d2                  # format d2 to be
13347        bfextu          %d4{&0:&2},%d0          # {FPCR[6],FPCR[5],SM,SE}
13348        add.l           %d0,%d2                 # in d2 as index into RTABLE
13349        lea.l           RTABLE(%pc),%a1         # load rtable base
13350        mov.b           (%a1,%d2),%d0           # load new rounding bits from table
13351        clr.l           %d3                     # clear d3 to force no exc and extended
13352        bfins           %d0,%d3{&26:&2}         # stuff new rounding bits in FPCR
13353        fmov.l          %d3,%fpcr               # write new FPCR
13354        asr.l           &1,%d0                  # write correct PTENxx table
13355        bcc.b           not_rp                  # to a1
13356        lea.l           PTENRP(%pc),%a1         # it is RP
13357        bra.b           calc_p                  # go to init section
13358not_rp:
13359        asr.l           &1,%d0                  # keep checking
13360        bcc.b           not_rm
13361        lea.l           PTENRM(%pc),%a1         # it is RM
13362        bra.b           calc_p                  # go to init section
13363not_rm:
13364        lea.l           PTENRN(%pc),%a1         # it is RN
13365calc_p:
13366        mov.l           %d1,%d0                 # copy exp to d0;use d0
13367        bpl.b           no_neg                  # if exp is negative,
13368        neg.l           %d0                     # invert it
13369        or.l            &0x40000000,(%a0)       # and set SE bit
13370no_neg:
13371        clr.l           %d3                     # table index
13372        fmov.s          &0x3f800000,%fp1        # init fp1 to 1
13373e_loop:
13374        asr.l           &1,%d0                  # shift next bit into carry
13375        bcc.b           e_next                  # if zero, skip the mul
13376        fmul.x          (%a1,%d3),%fp1          # mul by 10**(d3_bit_no)
13377e_next:
13378        add.l           &12,%d3                 # inc d3 to next rtable entry
13379        tst.l           %d0                     # check if d0 is zero
13380        bne.b           e_loop                  # not zero, continue shifting
13381#
13382#
13383#  Check the sign of the adjusted exp and make the value in fp0 the
13384#  same sign. If the exp was pos then multiply fp1*fp0;
13385#  else divide fp0/fp1.
13386#
13387# Register Usage:
13388#  norm:
13389#       ( )  a0: pointer to working bcd value
13390#       (*) fp0: mantissa accumulator
13391#       ( ) fp1: scaling factor - 10**(abs(exp))
13392#
13393pnorm:
13394        btst            &30,(%a0)               # test the sign of the exponent
13395        beq.b           mul                     # if clear, go to multiply
13396div:
13397        fdiv.x          %fp1,%fp0               # exp is negative, so divide mant by exp
13398        bra.b           end_dec
13399mul:
13400        fmul.x          %fp1,%fp0               # exp is positive, so multiply by exp
13401#
13402#
13403# Clean up and return with result in fp0.
13404#
13405# If the final mul/div in decbin incurred an inex exception,
13406# it will be inex2, but will be reported as inex1 by get_op.
13407#
13408end_dec:
13409        fmov.l          %fpsr,%d0               # get status register
13410        bclr            &inex2_bit+8,%d0        # test for inex2 and clear it
13411        beq.b           no_exc                  # skip this if no exc
13412        ori.w           &inx1a_mask,2+USER_FPSR(%a6) # set INEX1/AINEX
13413no_exc:
13414        add.l           &0x4,%sp                # clear 1 lw param
13415        fmovm.x         (%sp)+,&0x40            # restore fp1
13416        movm.l          (%sp)+,&0x3c            # restore d2-d5
13417        fmov.l          &0x0,%fpcr
13418        fmov.l          &0x0,%fpsr
13419        rts
13420
13421#########################################################################
13422# bindec(): Converts an input in extended precision format to bcd format#
13423#                                                                       #
13424# INPUT *************************************************************** #
13425#       a0 = pointer to the input extended precision value in memory.   #
13426#            the input may be either normalized, unnormalized, or       #
13427#            denormalized.                                              #
13428#       d0 = contains the k-factor sign-extended to 32-bits.            #
13429#                                                                       #
13430# OUTPUT ************************************************************** #
13431#       FP_SCR0(a6) = bcd format result on the stack.                   #
13432#                                                                       #
13433# ALGORITHM *********************************************************** #
13434#                                                                       #
13435#       A1.     Set RM and size ext;  Set SIGMA = sign of input.        #
13436#               The k-factor is saved for use in d7. Clear the          #
13437#               BINDEC_FLG for separating normalized/denormalized       #
13438#               input.  If input is unnormalized or denormalized,       #
13439#               normalize it.                                           #
13440#                                                                       #
13441#       A2.     Set X = abs(input).                                     #
13442#                                                                       #
13443#       A3.     Compute ILOG.                                           #
13444#               ILOG is the log base 10 of the input value.  It is      #
13445#               approximated by adding e + 0.f when the original        #
13446#               value is viewed as 2^^e * 1.f in extended precision.    #
13447#               This value is stored in d6.                             #
13448#                                                                       #
13449#       A4.     Clr INEX bit.                                           #
13450#               The operation in A3 above may have set INEX2.           #
13451#                                                                       #
13452#       A5.     Set ICTR = 0;                                           #
13453#               ICTR is a flag used in A13.  It must be set before the  #
13454#               loop entry A6.                                          #
13455#                                                                       #
13456#       A6.     Calculate LEN.                                          #
13457#               LEN is the number of digits to be displayed.  The       #
13458#               k-factor can dictate either the total number of digits, #
13459#               if it is a positive number, or the number of digits     #
13460#               after the decimal point which are to be included as     #
13461#               significant.  See the 68882 manual for examples.        #
13462#               If LEN is computed to be greater than 17, set OPERR in  #
13463#               USER_FPSR.  LEN is stored in d4.                        #
13464#                                                                       #
13465#       A7.     Calculate SCALE.                                        #
13466#               SCALE is equal to 10^ISCALE, where ISCALE is the number #
13467#               of decimal places needed to insure LEN integer digits   #
13468#               in the output before conversion to bcd. LAMBDA is the   #
13469#               sign of ISCALE, used in A9. Fp1 contains                #
13470#               10^^(abs(ISCALE)) using a rounding mode which is a      #
13471#               function of the original rounding mode and the signs    #
13472#               of ISCALE and X.  A table is given in the code.         #
13473#                                                                       #
13474#       A8.     Clr INEX; Force RZ.                                     #
13475#               The operation in A3 above may have set INEX2.           #
13476#               RZ mode is forced for the scaling operation to insure   #
13477#               only one rounding error.  The grs bits are collected in #
13478#               the INEX flag for use in A10.                           #
13479#                                                                       #
13480#       A9.     Scale X -> Y.                                           #
13481#               The mantissa is scaled to the desired number of         #
13482#               significant digits.  The excess digits are collected    #
13483#               in INEX2.                                               #
13484#                                                                       #
13485#       A10.    Or in INEX.                                             #
13486#               If INEX is set, round error occurred.  This is          #
13487#               compensated for by 'or-ing' in the INEX2 flag to        #
13488#               the lsb of Y.                                           #
13489#                                                                       #
13490#       A11.    Restore original FPCR; set size ext.                    #
13491#               Perform FINT operation in the user's rounding mode.     #
13492#               Keep the size to extended.                              #
13493#                                                                       #
13494#       A12.    Calculate YINT = FINT(Y) according to user's rounding   #
13495#               mode.  The FPSP routine sintd0 is used.  The output     #
13496#               is in fp0.                                              #
13497#                                                                       #
13498#       A13.    Check for LEN digits.                                   #
13499#               If the int operation results in more than LEN digits,   #
13500#               or less than LEN -1 digits, adjust ILOG and repeat from #
13501#               A6.  This test occurs only on the first pass.  If the   #
13502#               result is exactly 10^LEN, decrement ILOG and divide     #
13503#               the mantissa by 10.                                     #
13504#                                                                       #
13505#       A14.    Convert the mantissa to bcd.                            #
13506#               The binstr routine is used to convert the LEN digit     #
13507#               mantissa to bcd in memory.  The input to binstr is      #
13508#               to be a fraction; i.e. (mantissa)/10^LEN and adjusted   #
13509#               such that the decimal point is to the left of bit 63.   #
13510#               The bcd digits are stored in the correct position in    #
13511#               the final string area in memory.                        #
13512#                                                                       #
13513#       A15.    Convert the exponent to bcd.                            #
13514#               As in A14 above, the exp is converted to bcd and the    #
13515#               digits are stored in the final string.                  #
13516#               Test the length of the final exponent string.  If the   #
13517#               length is 4, set operr.                                 #
13518#                                                                       #
13519#       A16.    Write sign bits to final string.                        #
13520#                                                                       #
13521#########################################################################
13522
13523set     BINDEC_FLG,     EXC_TEMP        # DENORM flag
13524
13525# Constants in extended precision
13526PLOG2:
13527        long            0x3FFD0000,0x9A209A84,0xFBCFF798,0x00000000
13528PLOG2UP1:
13529        long            0x3FFD0000,0x9A209A84,0xFBCFF799,0x00000000
13530
13531# Constants in single precision
13532FONE:
13533        long            0x3F800000,0x00000000,0x00000000,0x00000000
13534FTWO:
13535        long            0x40000000,0x00000000,0x00000000,0x00000000
13536FTEN:
13537        long            0x41200000,0x00000000,0x00000000,0x00000000
13538F4933:
13539        long            0x459A2800,0x00000000,0x00000000,0x00000000
13540
13541RBDTBL:
13542        byte            0,0,0,0
13543        byte            3,3,2,2
13544        byte            3,2,2,3
13545        byte            2,3,3,2
13546
13547#       Implementation Notes:
13548#
13549#       The registers are used as follows:
13550#
13551#               d0: scratch; LEN input to binstr
13552#               d1: scratch
13553#               d2: upper 32-bits of mantissa for binstr
13554#               d3: scratch;lower 32-bits of mantissa for binstr
13555#               d4: LEN
13556#               d5: LAMBDA/ICTR
13557#               d6: ILOG
13558#               d7: k-factor
13559#               a0: ptr for original operand/final result
13560#               a1: scratch pointer
13561#               a2: pointer to FP_X; abs(original value) in ext
13562#               fp0: scratch
13563#               fp1: scratch
13564#               fp2: scratch
13565#               F_SCR1:
13566#               F_SCR2:
13567#               L_SCR1:
13568#               L_SCR2:
13569
13570        global          bindec
13571bindec:
13572        movm.l          &0x3f20,-(%sp)  #  {%d2-%d7/%a2}
13573        fmovm.x         &0x7,-(%sp)     #  {%fp0-%fp2}
13574
13575# A1. Set RM and size ext. Set SIGMA = sign input;
13576#     The k-factor is saved for use in d7.  Clear BINDEC_FLG for
13577#     separating  normalized/denormalized input.  If the input
13578#     is a denormalized number, set the BINDEC_FLG memory word
13579#     to signal denorm.  If the input is unnormalized, normalize
13580#     the input and test for denormalized result.
13581#
13582        fmov.l          &rm_mode*0x10,%fpcr     # set RM and ext
13583        mov.l           (%a0),L_SCR2(%a6)       # save exponent for sign check
13584        mov.l           %d0,%d7         # move k-factor to d7
13585
13586        clr.b           BINDEC_FLG(%a6) # clr norm/denorm flag
13587        cmpi.b          STAG(%a6),&DENORM # is input a DENORM?
13588        bne.w           A2_str          # no; input is a NORM
13589
13590#
13591# Normalize the denorm
13592#
13593un_de_norm:
13594        mov.w           (%a0),%d0
13595        and.w           &0x7fff,%d0     # strip sign of normalized exp
13596        mov.l           4(%a0),%d1
13597        mov.l           8(%a0),%d2
13598norm_loop:
13599        sub.w           &1,%d0
13600        lsl.l           &1,%d2
13601        roxl.l          &1,%d1
13602        tst.l           %d1
13603        bge.b           norm_loop
13604#
13605# Test if the normalized input is denormalized
13606#
13607        tst.w           %d0
13608        bgt.b           pos_exp         # if greater than zero, it is a norm
13609        st              BINDEC_FLG(%a6) # set flag for denorm
13610pos_exp:
13611        and.w           &0x7fff,%d0     # strip sign of normalized exp
13612        mov.w           %d0,(%a0)
13613        mov.l           %d1,4(%a0)
13614        mov.l           %d2,8(%a0)
13615
13616# A2. Set X = abs(input).
13617#
13618A2_str:
13619        mov.l           (%a0),FP_SCR1(%a6)      # move input to work space
13620        mov.l           4(%a0),FP_SCR1+4(%a6)   # move input to work space
13621        mov.l           8(%a0),FP_SCR1+8(%a6)   # move input to work space
13622        and.l           &0x7fffffff,FP_SCR1(%a6)        # create abs(X)
13623
13624# A3. Compute ILOG.
13625#     ILOG is the log base 10 of the input value.  It is approx-
13626#     imated by adding e + 0.f when the original value is viewed
13627#     as 2^^e * 1.f in extended precision.  This value is stored
13628#     in d6.
13629#
13630# Register usage:
13631#       Input/Output
13632#       d0: k-factor/exponent
13633#       d2: x/x
13634#       d3: x/x
13635#       d4: x/x
13636#       d5: x/x
13637#       d6: x/ILOG
13638#       d7: k-factor/Unchanged
13639#       a0: ptr for original operand/final result
13640#       a1: x/x
13641#       a2: x/x
13642#       fp0: x/float(ILOG)
13643#       fp1: x/x
13644#       fp2: x/x
13645#       F_SCR1:x/x
13646#       F_SCR2:Abs(X)/Abs(X) with $3fff exponent
13647#       L_SCR1:x/x
13648#       L_SCR2:first word of X packed/Unchanged
13649
13650        tst.b           BINDEC_FLG(%a6) # check for denorm
13651        beq.b           A3_cont         # if clr, continue with norm
13652        mov.l           &-4933,%d6      # force ILOG = -4933
13653        bra.b           A4_str
13654A3_cont:
13655        mov.w           FP_SCR1(%a6),%d0        # move exp to d0
13656        mov.w           &0x3fff,FP_SCR1(%a6)    # replace exponent with 0x3fff
13657        fmov.x          FP_SCR1(%a6),%fp0       # now fp0 has 1.f
13658        sub.w           &0x3fff,%d0     # strip off bias
13659        fadd.w          %d0,%fp0        # add in exp
13660        fsub.s          FONE(%pc),%fp0  # subtract off 1.0
13661        fbge.w          pos_res         # if pos, branch
13662        fmul.x          PLOG2UP1(%pc),%fp0      # if neg, mul by LOG2UP1
13663        fmov.l          %fp0,%d6        # put ILOG in d6 as a lword
13664        bra.b           A4_str          # go move out ILOG
13665pos_res:
13666        fmul.x          PLOG2(%pc),%fp0 # if pos, mul by LOG2
13667        fmov.l          %fp0,%d6        # put ILOG in d6 as a lword
13668
13669
13670# A4. Clr INEX bit.
13671#     The operation in A3 above may have set INEX2.
13672
13673A4_str:
13674        fmov.l          &0,%fpsr        # zero all of fpsr - nothing needed
13675
13676
13677# A5. Set ICTR = 0;
13678#     ICTR is a flag used in A13.  It must be set before the
13679#     loop entry A6. The lower word of d5 is used for ICTR.
13680
13681        clr.w           %d5             # clear ICTR
13682
13683# A6. Calculate LEN.
13684#     LEN is the number of digits to be displayed.  The k-factor
13685#     can dictate either the total number of digits, if it is
13686#     a positive number, or the number of digits after the
13687#     original decimal point which are to be included as
13688#     significant.  See the 68882 manual for examples.
13689#     If LEN is computed to be greater than 17, set OPERR in
13690#     USER_FPSR.  LEN is stored in d4.
13691#
13692# Register usage:
13693#       Input/Output
13694#       d0: exponent/Unchanged
13695#       d2: x/x/scratch
13696#       d3: x/x
13697#       d4: exc picture/LEN
13698#       d5: ICTR/Unchanged
13699#       d6: ILOG/Unchanged
13700#       d7: k-factor/Unchanged
13701#       a0: ptr for original operand/final result
13702#       a1: x/x
13703#       a2: x/x
13704#       fp0: float(ILOG)/Unchanged
13705#       fp1: x/x
13706#       fp2: x/x
13707#       F_SCR1:x/x
13708#       F_SCR2:Abs(X) with $3fff exponent/Unchanged
13709#       L_SCR1:x/x
13710#       L_SCR2:first word of X packed/Unchanged
13711
13712A6_str:
13713        tst.l           %d7             # branch on sign of k
13714        ble.b           k_neg           # if k <= 0, LEN = ILOG + 1 - k
13715        mov.l           %d7,%d4         # if k > 0, LEN = k
13716        bra.b           len_ck          # skip to LEN check
13717k_neg:
13718        mov.l           %d6,%d4         # first load ILOG to d4
13719        sub.l           %d7,%d4         # subtract off k
13720        addq.l          &1,%d4          # add in the 1
13721len_ck:
13722        tst.l           %d4             # LEN check: branch on sign of LEN
13723        ble.b           LEN_ng          # if neg, set LEN = 1
13724        cmp.l           %d4,&17         # test if LEN > 17
13725        ble.b           A7_str          # if not, forget it
13726        mov.l           &17,%d4         # set max LEN = 17
13727        tst.l           %d7             # if negative, never set OPERR
13728        ble.b           A7_str          # if positive, continue
13729        or.l            &opaop_mask,USER_FPSR(%a6)      # set OPERR & AIOP in USER_FPSR
13730        bra.b           A7_str          # finished here
13731LEN_ng:
13732        mov.l           &1,%d4          # min LEN is 1
13733
13734
13735# A7. Calculate SCALE.
13736#     SCALE is equal to 10^ISCALE, where ISCALE is the number
13737#     of decimal places needed to insure LEN integer digits
13738#     in the output before conversion to bcd. LAMBDA is the sign
13739#     of ISCALE, used in A9.  Fp1 contains 10^^(abs(ISCALE)) using
13740#     the rounding mode as given in the following table (see
13741#     Coonen, p. 7.23 as ref.; however, the SCALE variable is
13742#     of opposite sign in bindec.sa from Coonen).
13743#
13744#       Initial                                 USE
13745#       FPCR[6:5]       LAMBDA  SIGN(X)         FPCR[6:5]
13746#       ----------------------------------------------
13747#        RN     00         0       0            00/0    RN
13748#        RN     00         0       1            00/0    RN
13749#        RN     00         1       0            00/0    RN
13750#        RN     00         1       1            00/0    RN
13751#        RZ     01         0       0            11/3    RP
13752#        RZ     01         0       1            11/3    RP
13753#        RZ     01         1       0            10/2    RM
13754#        RZ     01         1       1            10/2    RM
13755#        RM     10         0       0            11/3    RP
13756#        RM     10         0       1            10/2    RM
13757#        RM     10         1       0            10/2    RM
13758#        RM     10         1       1            11/3    RP
13759#        RP     11         0       0            10/2    RM
13760#        RP     11         0       1            11/3    RP
13761#        RP     11         1       0            11/3    RP
13762#        RP     11         1       1            10/2    RM
13763#
13764# Register usage:
13765#       Input/Output
13766#       d0: exponent/scratch - final is 0
13767#       d2: x/0 or 24 for A9
13768#       d3: x/scratch - offset ptr into PTENRM array
13769#       d4: LEN/Unchanged
13770#       d5: 0/ICTR:LAMBDA
13771#       d6: ILOG/ILOG or k if ((k<=0)&(ILOG<k))
13772#       d7: k-factor/Unchanged
13773#       a0: ptr for original operand/final result
13774#       a1: x/ptr to PTENRM array
13775#       a2: x/x
13776#       fp0: float(ILOG)/Unchanged
13777#       fp1: x/10^ISCALE
13778#       fp2: x/x
13779#       F_SCR1:x/x
13780#       F_SCR2:Abs(X) with $3fff exponent/Unchanged
13781#       L_SCR1:x/x
13782#       L_SCR2:first word of X packed/Unchanged
13783
13784A7_str:
13785        tst.l           %d7             # test sign of k
13786        bgt.b           k_pos           # if pos and > 0, skip this
13787        cmp.l           %d7,%d6         # test k - ILOG
13788        blt.b           k_pos           # if ILOG >= k, skip this
13789        mov.l           %d7,%d6         # if ((k<0) & (ILOG < k)) ILOG = k
13790k_pos:
13791        mov.l           %d6,%d0         # calc ILOG + 1 - LEN in d0
13792        addq.l          &1,%d0          # add the 1
13793        sub.l           %d4,%d0         # sub off LEN
13794        swap            %d5             # use upper word of d5 for LAMBDA
13795        clr.w           %d5             # set it zero initially
13796        clr.w           %d2             # set up d2 for very small case
13797        tst.l           %d0             # test sign of ISCALE
13798        bge.b           iscale          # if pos, skip next inst
13799        addq.w          &1,%d5          # if neg, set LAMBDA true
13800        cmp.l           %d0,&0xffffecd4 # test iscale <= -4908
13801        bgt.b           no_inf          # if false, skip rest
13802        add.l           &24,%d0         # add in 24 to iscale
13803        mov.l           &24,%d2         # put 24 in d2 for A9
13804no_inf:
13805        neg.l           %d0             # and take abs of ISCALE
13806iscale:
13807        fmov.s          FONE(%pc),%fp1  # init fp1 to 1
13808        bfextu          USER_FPCR(%a6){&26:&2},%d1      # get initial rmode bits
13809        lsl.w           &1,%d1          # put them in bits 2:1
13810        add.w           %d5,%d1         # add in LAMBDA
13811        lsl.w           &1,%d1          # put them in bits 3:1
13812        tst.l           L_SCR2(%a6)     # test sign of original x
13813        bge.b           x_pos           # if pos, don't set bit 0
13814        addq.l          &1,%d1          # if neg, set bit 0
13815x_pos:
13816        lea.l           RBDTBL(%pc),%a2 # load rbdtbl base
13817        mov.b           (%a2,%d1),%d3   # load d3 with new rmode
13818        lsl.l           &4,%d3          # put bits in proper position
13819        fmov.l          %d3,%fpcr       # load bits into fpu
13820        lsr.l           &4,%d3          # put bits in proper position
13821        tst.b           %d3             # decode new rmode for pten table
13822        bne.b           not_rn          # if zero, it is RN
13823        lea.l           PTENRN(%pc),%a1 # load a1 with RN table base
13824        bra.b           rmode           # exit decode
13825not_rn:
13826        lsr.b           &1,%d3          # get lsb in carry
13827        bcc.b           not_rp2         # if carry clear, it is RM
13828        lea.l           PTENRP(%pc),%a1 # load a1 with RP table base
13829        bra.b           rmode           # exit decode
13830not_rp2:
13831        lea.l           PTENRM(%pc),%a1 # load a1 with RM table base
13832rmode:
13833        clr.l           %d3             # clr table index
13834e_loop2:
13835        lsr.l           &1,%d0          # shift next bit into carry
13836        bcc.b           e_next2         # if zero, skip the mul
13837        fmul.x          (%a1,%d3),%fp1  # mul by 10**(d3_bit_no)
13838e_next2:
13839        add.l           &12,%d3         # inc d3 to next pwrten table entry
13840        tst.l           %d0             # test if ISCALE is zero
13841        bne.b           e_loop2         # if not, loop
13842
13843# A8. Clr INEX; Force RZ.
13844#     The operation in A3 above may have set INEX2.
13845#     RZ mode is forced for the scaling operation to insure
13846#     only one rounding error.  The grs bits are collected in
13847#     the INEX flag for use in A10.
13848#
13849# Register usage:
13850#       Input/Output
13851
13852        fmov.l          &0,%fpsr        # clr INEX
13853        fmov.l          &rz_mode*0x10,%fpcr     # set RZ rounding mode
13854
13855# A9. Scale X -> Y.
13856#     The mantissa is scaled to the desired number of significant
13857#     digits.  The excess digits are collected in INEX2. If mul,
13858#     Check d2 for excess 10 exponential value.  If not zero,
13859#     the iscale value would have caused the pwrten calculation
13860#     to overflow.  Only a negative iscale can cause this, so
13861#     multiply by 10^(d2), which is now only allowed to be 24,
13862#     with a multiply by 10^8 and 10^16, which is exact since
13863#     10^24 is exact.  If the input was denormalized, we must
13864#     create a busy stack frame with the mul command and the
13865#     two operands, and allow the fpu to complete the multiply.
13866#
13867# Register usage:
13868#       Input/Output
13869#       d0: FPCR with RZ mode/Unchanged
13870#       d2: 0 or 24/unchanged
13871#       d3: x/x
13872#       d4: LEN/Unchanged
13873#       d5: ICTR:LAMBDA
13874#       d6: ILOG/Unchanged
13875#       d7: k-factor/Unchanged
13876#       a0: ptr for original operand/final result
13877#       a1: ptr to PTENRM array/Unchanged
13878#       a2: x/x
13879#       fp0: float(ILOG)/X adjusted for SCALE (Y)
13880#       fp1: 10^ISCALE/Unchanged
13881#       fp2: x/x
13882#       F_SCR1:x/x
13883#       F_SCR2:Abs(X) with $3fff exponent/Unchanged
13884#       L_SCR1:x/x
13885#       L_SCR2:first word of X packed/Unchanged
13886
13887A9_str:
13888        fmov.x          (%a0),%fp0      # load X from memory
13889        fabs.x          %fp0            # use abs(X)
13890        tst.w           %d5             # LAMBDA is in lower word of d5
13891        bne.b           sc_mul          # if neg (LAMBDA = 1), scale by mul
13892        fdiv.x          %fp1,%fp0       # calculate X / SCALE -> Y to fp0
13893        bra.w           A10_st          # branch to A10
13894
13895sc_mul:
13896        tst.b           BINDEC_FLG(%a6) # check for denorm
13897        beq.w           A9_norm         # if norm, continue with mul
13898
13899# for DENORM, we must calculate:
13900#       fp0 = input_op * 10^ISCALE * 10^24
13901# since the input operand is a DENORM, we can't multiply it directly.
13902# so, we do the multiplication of the exponents and mantissas separately.
13903# in this way, we avoid underflow on intermediate stages of the
13904# multiplication and guarantee a result without exception.
13905        fmovm.x         &0x2,-(%sp)     # save 10^ISCALE to stack
13906
13907        mov.w           (%sp),%d3       # grab exponent
13908        andi.w          &0x7fff,%d3     # clear sign
13909        ori.w           &0x8000,(%a0)   # make DENORM exp negative
13910        add.w           (%a0),%d3       # add DENORM exp to 10^ISCALE exp
13911        subi.w          &0x3fff,%d3     # subtract BIAS
13912        add.w           36(%a1),%d3
13913        subi.w          &0x3fff,%d3     # subtract BIAS
13914        add.w           48(%a1),%d3
13915        subi.w          &0x3fff,%d3     # subtract BIAS
13916
13917        bmi.w           sc_mul_err      # is result is DENORM, punt!!!
13918
13919        andi.w          &0x8000,(%sp)   # keep sign
13920        or.w            %d3,(%sp)       # insert new exponent
13921        andi.w          &0x7fff,(%a0)   # clear sign bit on DENORM again
13922        mov.l           0x8(%a0),-(%sp) # put input op mantissa on stk
13923        mov.l           0x4(%a0),-(%sp)
13924        mov.l           &0x3fff0000,-(%sp) # force exp to zero
13925        fmovm.x         (%sp)+,&0x80    # load normalized DENORM into fp0
13926        fmul.x          (%sp)+,%fp0
13927
13928#       fmul.x  36(%a1),%fp0    # multiply fp0 by 10^8
13929#       fmul.x  48(%a1),%fp0    # multiply fp0 by 10^16
13930        mov.l           36+8(%a1),-(%sp) # get 10^8 mantissa
13931        mov.l           36+4(%a1),-(%sp)
13932        mov.l           &0x3fff0000,-(%sp) # force exp to zero
13933        mov.l           48+8(%a1),-(%sp) # get 10^16 mantissa
13934        mov.l           48+4(%a1),-(%sp)
13935        mov.l           &0x3fff0000,-(%sp)# force exp to zero
13936        fmul.x          (%sp)+,%fp0     # multiply fp0 by 10^8
13937        fmul.x          (%sp)+,%fp0     # multiply fp0 by 10^16
13938        bra.b           A10_st
13939
13940sc_mul_err:
13941        bra.b           sc_mul_err
13942
13943A9_norm:
13944        tst.w           %d2             # test for small exp case
13945        beq.b           A9_con          # if zero, continue as normal
13946        fmul.x          36(%a1),%fp0    # multiply fp0 by 10^8
13947        fmul.x          48(%a1),%fp0    # multiply fp0 by 10^16
13948A9_con:
13949        fmul.x          %fp1,%fp0       # calculate X * SCALE -> Y to fp0
13950
13951# A10. Or in INEX.
13952#      If INEX is set, round error occurred.  This is compensated
13953#      for by 'or-ing' in the INEX2 flag to the lsb of Y.
13954#
13955# Register usage:
13956#       Input/Output
13957#       d0: FPCR with RZ mode/FPSR with INEX2 isolated
13958#       d2: x/x
13959#       d3: x/x
13960#       d4: LEN/Unchanged
13961#       d5: ICTR:LAMBDA
13962#       d6: ILOG/Unchanged
13963#       d7: k-factor/Unchanged
13964#       a0: ptr for original operand/final result
13965#       a1: ptr to PTENxx array/Unchanged
13966#       a2: x/ptr to FP_SCR1(a6)
13967#       fp0: Y/Y with lsb adjusted
13968#       fp1: 10^ISCALE/Unchanged
13969#       fp2: x/x
13970
13971A10_st:
13972        fmov.l          %fpsr,%d0       # get FPSR
13973        fmov.x          %fp0,FP_SCR1(%a6)       # move Y to memory
13974        lea.l           FP_SCR1(%a6),%a2        # load a2 with ptr to FP_SCR1
13975        btst            &9,%d0          # check if INEX2 set
13976        beq.b           A11_st          # if clear, skip rest
13977        or.l            &1,8(%a2)       # or in 1 to lsb of mantissa
13978        fmov.x          FP_SCR1(%a6),%fp0       # write adjusted Y back to fpu
13979
13980
13981# A11. Restore original FPCR; set size ext.
13982#      Perform FINT operation in the user's rounding mode.  Keep
13983#      the size to extended.  The sintdo entry point in the sint
13984#      routine expects the FPCR value to be in USER_FPCR for
13985#      mode and precision.  The original FPCR is saved in L_SCR1.
13986
13987A11_st:
13988        mov.l           USER_FPCR(%a6),L_SCR1(%a6)      # save it for later
13989        and.l           &0x00000030,USER_FPCR(%a6)      # set size to ext,
13990#                                       ;block exceptions
13991
13992
13993# A12. Calculate YINT = FINT(Y) according to user's rounding mode.
13994#      The FPSP routine sintd0 is used.  The output is in fp0.
13995#
13996# Register usage:
13997#       Input/Output
13998#       d0: FPSR with AINEX cleared/FPCR with size set to ext
13999#       d2: x/x/scratch
14000#       d3: x/x
14001#       d4: LEN/Unchanged
14002#       d5: ICTR:LAMBDA/Unchanged
14003#       d6: ILOG/Unchanged
14004#       d7: k-factor/Unchanged
14005#       a0: ptr for original operand/src ptr for sintdo
14006#       a1: ptr to PTENxx array/Unchanged
14007#       a2: ptr to FP_SCR1(a6)/Unchanged
14008#       a6: temp pointer to FP_SCR1(a6) - orig value saved and restored
14009#       fp0: Y/YINT
14010#       fp1: 10^ISCALE/Unchanged
14011#       fp2: x/x
14012#       F_SCR1:x/x
14013#       F_SCR2:Y adjusted for inex/Y with original exponent
14014#       L_SCR1:x/original USER_FPCR
14015#       L_SCR2:first word of X packed/Unchanged
14016
14017A12_st:
14018        movm.l  &0xc0c0,-(%sp)  # save regs used by sintd0       {%d0-%d1/%a0-%a1}
14019        mov.l   L_SCR1(%a6),-(%sp)
14020        mov.l   L_SCR2(%a6),-(%sp)
14021
14022        lea.l           FP_SCR1(%a6),%a0        # a0 is ptr to FP_SCR1(a6)
14023        fmov.x          %fp0,(%a0)      # move Y to memory at FP_SCR1(a6)
14024        tst.l           L_SCR2(%a6)     # test sign of original operand
14025        bge.b           do_fint12               # if pos, use Y
14026        or.l            &0x80000000,(%a0)       # if neg, use -Y
14027do_fint12:
14028        mov.l   USER_FPSR(%a6),-(%sp)
14029#       bsr     sintdo          # sint routine returns int in fp0
14030
14031        fmov.l  USER_FPCR(%a6),%fpcr
14032        fmov.l  &0x0,%fpsr                      # clear the AEXC bits!!!
14033##      mov.l           USER_FPCR(%a6),%d0      # ext prec/keep rnd mode
14034##      andi.l          &0x00000030,%d0
14035##      fmov.l          %d0,%fpcr
14036        fint.x          FP_SCR1(%a6),%fp0       # do fint()
14037        fmov.l  %fpsr,%d0
14038        or.w    %d0,FPSR_EXCEPT(%a6)
14039##      fmov.l          &0x0,%fpcr
14040##      fmov.l          %fpsr,%d0               # don't keep ccodes
14041##      or.w            %d0,FPSR_EXCEPT(%a6)
14042
14043        mov.b   (%sp),USER_FPSR(%a6)
14044        add.l   &4,%sp
14045
14046        mov.l   (%sp)+,L_SCR2(%a6)
14047        mov.l   (%sp)+,L_SCR1(%a6)
14048        movm.l  (%sp)+,&0x303   # restore regs used by sint      {%d0-%d1/%a0-%a1}
14049
14050        mov.l   L_SCR2(%a6),FP_SCR1(%a6)        # restore original exponent
14051        mov.l   L_SCR1(%a6),USER_FPCR(%a6)      # restore user's FPCR
14052
14053# A13. Check for LEN digits.
14054#      If the int operation results in more than LEN digits,
14055#      or less than LEN -1 digits, adjust ILOG and repeat from
14056#      A6.  This test occurs only on the first pass.  If the
14057#      result is exactly 10^LEN, decrement ILOG and divide
14058#      the mantissa by 10.  The calculation of 10^LEN cannot
14059#      be inexact, since all powers of ten up to 10^27 are exact
14060#      in extended precision, so the use of a previous power-of-ten
14061#      table will introduce no error.
14062#
14063#
14064# Register usage:
14065#       Input/Output
14066#       d0: FPCR with size set to ext/scratch final = 0
14067#       d2: x/x
14068#       d3: x/scratch final = x
14069#       d4: LEN/LEN adjusted
14070#       d5: ICTR:LAMBDA/LAMBDA:ICTR
14071#       d6: ILOG/ILOG adjusted
14072#       d7: k-factor/Unchanged
14073#       a0: pointer into memory for packed bcd string formation
14074#       a1: ptr to PTENxx array/Unchanged
14075#       a2: ptr to FP_SCR1(a6)/Unchanged
14076#       fp0: int portion of Y/abs(YINT) adjusted
14077#       fp1: 10^ISCALE/Unchanged
14078#       fp2: x/10^LEN
14079#       F_SCR1:x/x
14080#       F_SCR2:Y with original exponent/Unchanged
14081#       L_SCR1:original USER_FPCR/Unchanged
14082#       L_SCR2:first word of X packed/Unchanged
14083
14084A13_st:
14085        swap            %d5             # put ICTR in lower word of d5
14086        tst.w           %d5             # check if ICTR = 0
14087        bne             not_zr          # if non-zero, go to second test
14088#
14089# Compute 10^(LEN-1)
14090#
14091        fmov.s          FONE(%pc),%fp2  # init fp2 to 1.0
14092        mov.l           %d4,%d0         # put LEN in d0
14093        subq.l          &1,%d0          # d0 = LEN -1
14094        clr.l           %d3             # clr table index
14095l_loop:
14096        lsr.l           &1,%d0          # shift next bit into carry
14097        bcc.b           l_next          # if zero, skip the mul
14098        fmul.x          (%a1,%d3),%fp2  # mul by 10**(d3_bit_no)
14099l_next:
14100        add.l           &12,%d3         # inc d3 to next pwrten table entry
14101        tst.l           %d0             # test if LEN is zero
14102        bne.b           l_loop          # if not, loop
14103#
14104# 10^LEN-1 is computed for this test and A14.  If the input was
14105# denormalized, check only the case in which YINT > 10^LEN.
14106#
14107        tst.b           BINDEC_FLG(%a6) # check if input was norm
14108        beq.b           A13_con         # if norm, continue with checking
14109        fabs.x          %fp0            # take abs of YINT
14110        bra             test_2
14111#
14112# Compare abs(YINT) to 10^(LEN-1) and 10^LEN
14113#
14114A13_con:
14115        fabs.x          %fp0            # take abs of YINT
14116        fcmp.x          %fp0,%fp2       # compare abs(YINT) with 10^(LEN-1)
14117        fbge.w          test_2          # if greater, do next test
14118        subq.l          &1,%d6          # subtract 1 from ILOG
14119        mov.w           &1,%d5          # set ICTR
14120        fmov.l          &rm_mode*0x10,%fpcr     # set rmode to RM
14121        fmul.s          FTEN(%pc),%fp2  # compute 10^LEN
14122        bra.w           A6_str          # return to A6 and recompute YINT
14123test_2:
14124        fmul.s          FTEN(%pc),%fp2  # compute 10^LEN
14125        fcmp.x          %fp0,%fp2       # compare abs(YINT) with 10^LEN
14126        fblt.w          A14_st          # if less, all is ok, go to A14
14127        fbgt.w          fix_ex          # if greater, fix and redo
14128        fdiv.s          FTEN(%pc),%fp0  # if equal, divide by 10
14129        addq.l          &1,%d6          # and inc ILOG
14130        bra.b           A14_st          # and continue elsewhere
14131fix_ex:
14132        addq.l          &1,%d6          # increment ILOG by 1
14133        mov.w           &1,%d5          # set ICTR
14134        fmov.l          &rm_mode*0x10,%fpcr     # set rmode to RM
14135        bra.w           A6_str          # return to A6 and recompute YINT
14136#
14137# Since ICTR <> 0, we have already been through one adjustment,
14138# and shouldn't have another; this is to check if abs(YINT) = 10^LEN
14139# 10^LEN is again computed using whatever table is in a1 since the
14140# value calculated cannot be inexact.
14141#
14142not_zr:
14143        fmov.s          FONE(%pc),%fp2  # init fp2 to 1.0
14144        mov.l           %d4,%d0         # put LEN in d0
14145        clr.l           %d3             # clr table index
14146z_loop:
14147        lsr.l           &1,%d0          # shift next bit into carry
14148        bcc.b           z_next          # if zero, skip the mul
14149        fmul.x          (%a1,%d3),%fp2  # mul by 10**(d3_bit_no)
14150z_next:
14151        add.l           &12,%d3         # inc d3 to next pwrten table entry
14152        tst.l           %d0             # test if LEN is zero
14153        bne.b           z_loop          # if not, loop
14154        fabs.x          %fp0            # get abs(YINT)
14155        fcmp.x          %fp0,%fp2       # check if abs(YINT) = 10^LEN
14156        fbneq.w         A14_st          # if not, skip this
14157        fdiv.s          FTEN(%pc),%fp0  # divide abs(YINT) by 10
14158        addq.l          &1,%d6          # and inc ILOG by 1
14159        addq.l          &1,%d4          # and inc LEN
14160        fmul.s          FTEN(%pc),%fp2  # if LEN++, the get 10^^LEN
14161
14162# A14. Convert the mantissa to bcd.
14163#      The binstr routine is used to convert the LEN digit
14164#      mantissa to bcd in memory.  The input to binstr is
14165#      to be a fraction; i.e. (mantissa)/10^LEN and adjusted
14166#      such that the decimal point is to the left of bit 63.
14167#      The bcd digits are stored in the correct position in
14168#      the final string area in memory.
14169#
14170#
14171# Register usage:
14172#       Input/Output
14173#       d0: x/LEN call to binstr - final is 0
14174#       d1: x/0
14175#       d2: x/ms 32-bits of mant of abs(YINT)
14176#       d3: x/ls 32-bits of mant of abs(YINT)
14177#       d4: LEN/Unchanged
14178#       d5: ICTR:LAMBDA/LAMBDA:ICTR
14179#       d6: ILOG
14180#       d7: k-factor/Unchanged
14181#       a0: pointer into memory for packed bcd string formation
14182#           /ptr to first mantissa byte in result string
14183#       a1: ptr to PTENxx array/Unchanged
14184#       a2: ptr to FP_SCR1(a6)/Unchanged
14185#       fp0: int portion of Y/abs(YINT) adjusted
14186#       fp1: 10^ISCALE/Unchanged
14187#       fp2: 10^LEN/Unchanged
14188#       F_SCR1:x/Work area for final result
14189#       F_SCR2:Y with original exponent/Unchanged
14190#       L_SCR1:original USER_FPCR/Unchanged
14191#       L_SCR2:first word of X packed/Unchanged
14192
14193A14_st:
14194        fmov.l          &rz_mode*0x10,%fpcr     # force rz for conversion
14195        fdiv.x          %fp2,%fp0       # divide abs(YINT) by 10^LEN
14196        lea.l           FP_SCR0(%a6),%a0
14197        fmov.x          %fp0,(%a0)      # move abs(YINT)/10^LEN to memory
14198        mov.l           4(%a0),%d2      # move 2nd word of FP_RES to d2
14199        mov.l           8(%a0),%d3      # move 3rd word of FP_RES to d3
14200        clr.l           4(%a0)          # zero word 2 of FP_RES
14201        clr.l           8(%a0)          # zero word 3 of FP_RES
14202        mov.l           (%a0),%d0       # move exponent to d0
14203        swap            %d0             # put exponent in lower word
14204        beq.b           no_sft          # if zero, don't shift
14205        sub.l           &0x3ffd,%d0     # sub bias less 2 to make fract
14206        tst.l           %d0             # check if > 1
14207        bgt.b           no_sft          # if so, don't shift
14208        neg.l           %d0             # make exp positive
14209m_loop:
14210        lsr.l           &1,%d2          # shift d2:d3 right, add 0s
14211        roxr.l          &1,%d3          # the number of places
14212        dbf.w           %d0,m_loop      # given in d0
14213no_sft:
14214        tst.l           %d2             # check for mantissa of zero
14215        bne.b           no_zr           # if not, go on
14216        tst.l           %d3             # continue zero check
14217        beq.b           zer_m           # if zero, go directly to binstr
14218no_zr:
14219        clr.l           %d1             # put zero in d1 for addx
14220        add.l           &0x00000080,%d3 # inc at bit 7
14221        addx.l          %d1,%d2         # continue inc
14222        and.l           &0xffffff80,%d3 # strip off lsb not used by 882
14223zer_m:
14224        mov.l           %d4,%d0         # put LEN in d0 for binstr call
14225        addq.l          &3,%a0          # a0 points to M16 byte in result
14226        bsr             binstr          # call binstr to convert mant
14227
14228
14229# A15. Convert the exponent to bcd.
14230#      As in A14 above, the exp is converted to bcd and the
14231#      digits are stored in the final string.
14232#
14233#      Digits are stored in L_SCR1(a6) on return from BINDEC as:
14234#
14235#        32               16 15                0
14236#       -----------------------------------------
14237#       |  0 | e3 | e2 | e1 | e4 |  X |  X |  X |
14238#       -----------------------------------------
14239#
14240# And are moved into their proper places in FP_SCR0.  If digit e4
14241# is non-zero, OPERR is signaled.  In all cases, all 4 digits are
14242# written as specified in the 881/882 manual for packed decimal.
14243#
14244# Register usage:
14245#       Input/Output
14246#       d0: x/LEN call to binstr - final is 0
14247#       d1: x/scratch (0);shift count for final exponent packing
14248#       d2: x/ms 32-bits of exp fraction/scratch
14249#       d3: x/ls 32-bits of exp fraction
14250#       d4: LEN/Unchanged
14251#       d5: ICTR:LAMBDA/LAMBDA:ICTR
14252#       d6: ILOG
14253#       d7: k-factor/Unchanged
14254#       a0: ptr to result string/ptr to L_SCR1(a6)
14255#       a1: ptr to PTENxx array/Unchanged
14256#       a2: ptr to FP_SCR1(a6)/Unchanged
14257#       fp0: abs(YINT) adjusted/float(ILOG)
14258#       fp1: 10^ISCALE/Unchanged
14259#       fp2: 10^LEN/Unchanged
14260#       F_SCR1:Work area for final result/BCD result
14261#       F_SCR2:Y with original exponent/ILOG/10^4
14262#       L_SCR1:original USER_FPCR/Exponent digits on return from binstr
14263#       L_SCR2:first word of X packed/Unchanged
14264
14265A15_st:
14266        tst.b           BINDEC_FLG(%a6) # check for denorm
14267        beq.b           not_denorm
14268        ftest.x         %fp0            # test for zero
14269        fbeq.w          den_zero        # if zero, use k-factor or 4933
14270        fmov.l          %d6,%fp0        # float ILOG
14271        fabs.x          %fp0            # get abs of ILOG
14272        bra.b           convrt
14273den_zero:
14274        tst.l           %d7             # check sign of the k-factor
14275        blt.b           use_ilog        # if negative, use ILOG
14276        fmov.s          F4933(%pc),%fp0 # force exponent to 4933
14277        bra.b           convrt          # do it
14278use_ilog:
14279        fmov.l          %d6,%fp0        # float ILOG
14280        fabs.x          %fp0            # get abs of ILOG
14281        bra.b           convrt
14282not_denorm:
14283        ftest.x         %fp0            # test for zero
14284        fbneq.w         not_zero        # if zero, force exponent
14285        fmov.s          FONE(%pc),%fp0  # force exponent to 1
14286        bra.b           convrt          # do it
14287not_zero:
14288        fmov.l          %d6,%fp0        # float ILOG
14289        fabs.x          %fp0            # get abs of ILOG
14290convrt:
14291        fdiv.x          24(%a1),%fp0    # compute ILOG/10^4
14292        fmov.x          %fp0,FP_SCR1(%a6)       # store fp0 in memory
14293        mov.l           4(%a2),%d2      # move word 2 to d2
14294        mov.l           8(%a2),%d3      # move word 3 to d3
14295        mov.w           (%a2),%d0       # move exp to d0
14296        beq.b           x_loop_fin      # if zero, skip the shift
14297        sub.w           &0x3ffd,%d0     # subtract off bias
14298        neg.w           %d0             # make exp positive
14299x_loop:
14300        lsr.l           &1,%d2          # shift d2:d3 right
14301        roxr.l          &1,%d3          # the number of places
14302        dbf.w           %d0,x_loop      # given in d0
14303x_loop_fin:
14304        clr.l           %d1             # put zero in d1 for addx
14305        add.l           &0x00000080,%d3 # inc at bit 6
14306        addx.l          %d1,%d2         # continue inc
14307        and.l           &0xffffff80,%d3 # strip off lsb not used by 882
14308        mov.l           &4,%d0          # put 4 in d0 for binstr call
14309        lea.l           L_SCR1(%a6),%a0 # a0 is ptr to L_SCR1 for exp digits
14310        bsr             binstr          # call binstr to convert exp
14311        mov.l           L_SCR1(%a6),%d0 # load L_SCR1 lword to d0
14312        mov.l           &12,%d1         # use d1 for shift count
14313        lsr.l           %d1,%d0         # shift d0 right by 12
14314        bfins           %d0,FP_SCR0(%a6){&4:&12}        # put e3:e2:e1 in FP_SCR0
14315        lsr.l           %d1,%d0         # shift d0 right by 12
14316        bfins           %d0,FP_SCR0(%a6){&16:&4}        # put e4 in FP_SCR0
14317        tst.b           %d0             # check if e4 is zero
14318        beq.b           A16_st          # if zero, skip rest
14319        or.l            &opaop_mask,USER_FPSR(%a6)      # set OPERR & AIOP in USER_FPSR
14320
14321
14322# A16. Write sign bits to final string.
14323#          Sigma is bit 31 of initial value; RHO is bit 31 of d6 (ILOG).
14324#
14325# Register usage:
14326#       Input/Output
14327#       d0: x/scratch - final is x
14328#       d2: x/x
14329#       d3: x/x
14330#       d4: LEN/Unchanged
14331#       d5: ICTR:LAMBDA/LAMBDA:ICTR
14332#       d6: ILOG/ILOG adjusted
14333#       d7: k-factor/Unchanged
14334#       a0: ptr to L_SCR1(a6)/Unchanged
14335#       a1: ptr to PTENxx array/Unchanged
14336#       a2: ptr to FP_SCR1(a6)/Unchanged
14337#       fp0: float(ILOG)/Unchanged
14338#       fp1: 10^ISCALE/Unchanged
14339#       fp2: 10^LEN/Unchanged
14340#       F_SCR1:BCD result with correct signs
14341#       F_SCR2:ILOG/10^4
14342#       L_SCR1:Exponent digits on return from binstr
14343#       L_SCR2:first word of X packed/Unchanged
14344
14345A16_st:
14346        clr.l           %d0             # clr d0 for collection of signs
14347        and.b           &0x0f,FP_SCR0(%a6)      # clear first nibble of FP_SCR0
14348        tst.l           L_SCR2(%a6)     # check sign of original mantissa
14349        bge.b           mant_p          # if pos, don't set SM
14350        mov.l           &2,%d0          # move 2 in to d0 for SM
14351mant_p:
14352        tst.l           %d6             # check sign of ILOG
14353        bge.b           wr_sgn          # if pos, don't set SE
14354        addq.l          &1,%d0          # set bit 0 in d0 for SE
14355wr_sgn:
14356        bfins           %d0,FP_SCR0(%a6){&0:&2} # insert SM and SE into FP_SCR0
14357
14358# Clean up and restore all registers used.
14359
14360        fmov.l          &0,%fpsr        # clear possible inex2/ainex bits
14361        fmovm.x         (%sp)+,&0xe0    #  {%fp0-%fp2}
14362        movm.l          (%sp)+,&0x4fc   #  {%d2-%d7/%a2}
14363        rts
14364
14365        global          PTENRN
14366PTENRN:
14367        long            0x40020000,0xA0000000,0x00000000        # 10 ^ 1
14368        long            0x40050000,0xC8000000,0x00000000        # 10 ^ 2
14369        long            0x400C0000,0x9C400000,0x00000000        # 10 ^ 4
14370        long            0x40190000,0xBEBC2000,0x00000000        # 10 ^ 8
14371        long            0x40340000,0x8E1BC9BF,0x04000000        # 10 ^ 16
14372        long            0x40690000,0x9DC5ADA8,0x2B70B59E        # 10 ^ 32
14373        long            0x40D30000,0xC2781F49,0xFFCFA6D5        # 10 ^ 64
14374        long            0x41A80000,0x93BA47C9,0x80E98CE0        # 10 ^ 128
14375        long            0x43510000,0xAA7EEBFB,0x9DF9DE8E        # 10 ^ 256
14376        long            0x46A30000,0xE319A0AE,0xA60E91C7        # 10 ^ 512
14377        long            0x4D480000,0xC9767586,0x81750C17        # 10 ^ 1024
14378        long            0x5A920000,0x9E8B3B5D,0xC53D5DE5        # 10 ^ 2048
14379        long            0x75250000,0xC4605202,0x8A20979B        # 10 ^ 4096
14380
14381        global          PTENRP
14382PTENRP:
14383        long            0x40020000,0xA0000000,0x00000000        # 10 ^ 1
14384        long            0x40050000,0xC8000000,0x00000000        # 10 ^ 2
14385        long            0x400C0000,0x9C400000,0x00000000        # 10 ^ 4
14386        long            0x40190000,0xBEBC2000,0x00000000        # 10 ^ 8
14387        long            0x40340000,0x8E1BC9BF,0x04000000        # 10 ^ 16
14388        long            0x40690000,0x9DC5ADA8,0x2B70B59E        # 10 ^ 32
14389        long            0x40D30000,0xC2781F49,0xFFCFA6D6        # 10 ^ 64
14390        long            0x41A80000,0x93BA47C9,0x80E98CE0        # 10 ^ 128
14391        long            0x43510000,0xAA7EEBFB,0x9DF9DE8E        # 10 ^ 256
14392        long            0x46A30000,0xE319A0AE,0xA60E91C7        # 10 ^ 512
14393        long            0x4D480000,0xC9767586,0x81750C18        # 10 ^ 1024
14394        long            0x5A920000,0x9E8B3B5D,0xC53D5DE5        # 10 ^ 2048
14395        long            0x75250000,0xC4605202,0x8A20979B        # 10 ^ 4096
14396
14397        global          PTENRM
14398PTENRM:
14399        long            0x40020000,0xA0000000,0x00000000        # 10 ^ 1
14400        long            0x40050000,0xC8000000,0x00000000        # 10 ^ 2
14401        long            0x400C0000,0x9C400000,0x00000000        # 10 ^ 4
14402        long            0x40190000,0xBEBC2000,0x00000000        # 10 ^ 8
14403        long            0x40340000,0x8E1BC9BF,0x04000000        # 10 ^ 16
14404        long            0x40690000,0x9DC5ADA8,0x2B70B59D        # 10 ^ 32
14405        long            0x40D30000,0xC2781F49,0xFFCFA6D5        # 10 ^ 64
14406        long            0x41A80000,0x93BA47C9,0x80E98CDF        # 10 ^ 128
14407        long            0x43510000,0xAA7EEBFB,0x9DF9DE8D        # 10 ^ 256
14408        long            0x46A30000,0xE319A0AE,0xA60E91C6        # 10 ^ 512
14409        long            0x4D480000,0xC9767586,0x81750C17        # 10 ^ 1024
14410        long            0x5A920000,0x9E8B3B5D,0xC53D5DE4        # 10 ^ 2048
14411        long            0x75250000,0xC4605202,0x8A20979A        # 10 ^ 4096
14412
14413#########################################################################
14414# binstr(): Converts a 64-bit binary integer to bcd.                    #
14415#                                                                       #
14416# INPUT *************************************************************** #
14417#       d2:d3 = 64-bit binary integer                                   #
14418#       d0    = desired length (LEN)                                    #
14419#       a0    = pointer to start in memory for bcd characters           #
14420#               (This pointer must point to byte 4 of the first         #
14421#                lword of the packed decimal memory string.)            #
14422#                                                                       #
14423# OUTPUT ************************************************************** #
14424#       a0 = pointer to LEN bcd digits representing the 64-bit integer. #
14425#                                                                       #
14426# ALGORITHM *********************************************************** #
14427#       The 64-bit binary is assumed to have a decimal point before     #
14428#       bit 63.  The fraction is multiplied by 10 using a mul by 2      #
14429#       shift and a mul by 8 shift.  The bits shifted out of the        #
14430#       msb form a decimal digit.  This process is iterated until       #
14431#       LEN digits are formed.                                          #
14432#                                                                       #
14433# A1. Init d7 to 1.  D7 is the byte digit counter, and if 1, the        #
14434#     digit formed will be assumed the least significant.  This is      #
14435#     to force the first byte formed to have a 0 in the upper 4 bits.   #
14436#                                                                       #
14437# A2. Beginning of the loop:                                            #
14438#     Copy the fraction in d2:d3 to d4:d5.                              #
14439#                                                                       #
14440# A3. Multiply the fraction in d2:d3 by 8 using bit-field               #
14441#     extracts and shifts.  The three msbs from d2 will go into d1.     #
14442#                                                                       #
14443# A4. Multiply the fraction in d4:d5 by 2 using shifts.  The msb        #
14444#     will be collected by the carry.                                   #
14445#                                                                       #
14446# A5. Add using the carry the 64-bit quantities in d2:d3 and d4:d5      #
14447#     into d2:d3.  D1 will contain the bcd digit formed.                #
14448#                                                                       #
14449# A6. Test d7.  If zero, the digit formed is the ms digit.  If non-     #
14450#     zero, it is the ls digit.  Put the digit in its place in the      #
14451#     upper word of d0.  If it is the ls digit, write the word          #
14452#     from d0 to memory.                                                #
14453#                                                                       #
14454# A7. Decrement d6 (LEN counter) and repeat the loop until zero.        #
14455#                                                                       #
14456#########################################################################
14457
14458#       Implementation Notes:
14459#
14460#       The registers are used as follows:
14461#
14462#               d0: LEN counter
14463#               d1: temp used to form the digit
14464#               d2: upper 32-bits of fraction for mul by 8
14465#               d3: lower 32-bits of fraction for mul by 8
14466#               d4: upper 32-bits of fraction for mul by 2
14467#               d5: lower 32-bits of fraction for mul by 2
14468#               d6: temp for bit-field extracts
14469#               d7: byte digit formation word;digit count {0,1}
14470#               a0: pointer into memory for packed bcd string formation
14471#
14472
14473        global          binstr
14474binstr:
14475        movm.l          &0xff00,-(%sp)  #  {%d0-%d7}
14476
14477#
14478# A1: Init d7
14479#
14480        mov.l           &1,%d7          # init d7 for second digit
14481        subq.l          &1,%d0          # for dbf d0 would have LEN+1 passes
14482#
14483# A2. Copy d2:d3 to d4:d5.  Start loop.
14484#
14485loop:
14486        mov.l           %d2,%d4         # copy the fraction before muls
14487        mov.l           %d3,%d5         # to d4:d5
14488#
14489# A3. Multiply d2:d3 by 8; extract msbs into d1.
14490#
14491        bfextu          %d2{&0:&3},%d1  # copy 3 msbs of d2 into d1
14492        asl.l           &3,%d2          # shift d2 left by 3 places
14493        bfextu          %d3{&0:&3},%d6  # copy 3 msbs of d3 into d6
14494        asl.l           &3,%d3          # shift d3 left by 3 places
14495        or.l            %d6,%d2         # or in msbs from d3 into d2
14496#
14497# A4. Multiply d4:d5 by 2; add carry out to d1.
14498#
14499        asl.l           &1,%d5          # mul d5 by 2
14500        roxl.l          &1,%d4          # mul d4 by 2
14501        swap            %d6             # put 0 in d6 lower word
14502        addx.w          %d6,%d1         # add in extend from mul by 2
14503#
14504# A5. Add mul by 8 to mul by 2.  D1 contains the digit formed.
14505#
14506        add.l           %d5,%d3         # add lower 32 bits
14507        nop                             # ERRATA FIX #13 (Rev. 1.2 6/6/90)
14508        addx.l          %d4,%d2         # add with extend upper 32 bits
14509        nop                             # ERRATA FIX #13 (Rev. 1.2 6/6/90)
14510        addx.w          %d6,%d1         # add in extend from add to d1
14511        swap            %d6             # with d6 = 0; put 0 in upper word
14512#
14513# A6. Test d7 and branch.
14514#
14515        tst.w           %d7             # if zero, store digit & to loop
14516        beq.b           first_d         # if non-zero, form byte & write
14517sec_d:
14518        swap            %d7             # bring first digit to word d7b
14519        asl.w           &4,%d7          # first digit in upper 4 bits d7b
14520        add.w           %d1,%d7         # add in ls digit to d7b
14521        mov.b           %d7,(%a0)+      # store d7b byte in memory
14522        swap            %d7             # put LEN counter in word d7a
14523        clr.w           %d7             # set d7a to signal no digits done
14524        dbf.w           %d0,loop        # do loop some more!
14525        bra.b           end_bstr        # finished, so exit
14526first_d:
14527        swap            %d7             # put digit word in d7b
14528        mov.w           %d1,%d7         # put new digit in d7b
14529        swap            %d7             # put LEN counter in word d7a
14530        addq.w          &1,%d7          # set d7a to signal first digit done
14531        dbf.w           %d0,loop        # do loop some more!
14532        swap            %d7             # put last digit in string
14533        lsl.w           &4,%d7          # move it to upper 4 bits
14534        mov.b           %d7,(%a0)+      # store it in memory string
14535#
14536# Clean up and return with result in fp0.
14537#
14538end_bstr:
14539        movm.l          (%sp)+,&0xff    #  {%d0-%d7}
14540        rts
14541
14542#########################################################################
14543# XDEF **************************************************************** #
14544#       facc_in_b(): dmem_read_byte failed                              #
14545#       facc_in_w(): dmem_read_word failed                              #
14546#       facc_in_l(): dmem_read_long failed                              #
14547#       facc_in_d(): dmem_read of dbl prec failed                       #
14548#       facc_in_x(): dmem_read of ext prec failed                       #
14549#                                                                       #
14550#       facc_out_b(): dmem_write_byte failed                            #
14551#       facc_out_w(): dmem_write_word failed                            #
14552#       facc_out_l(): dmem_write_long failed                            #
14553#       facc_out_d(): dmem_write of dbl prec failed                     #
14554#       facc_out_x(): dmem_write of ext prec failed                     #
14555#                                                                       #
14556# XREF **************************************************************** #
14557#       _real_access() - exit through access error handler              #
14558#                                                                       #
14559# INPUT *************************************************************** #
14560#       None                                                            #
14561#                                                                       #
14562# OUTPUT ************************************************************** #
14563#       None                                                            #
14564#                                                                       #
14565# ALGORITHM *********************************************************** #
14566#       Flow jumps here when an FP data fetch call gets an error        #
14567# result. This means the operating system wants an access error frame   #
14568# made out of the current exception stack frame.                        #
14569#       So, we first call restore() which makes sure that any updated   #
14570# -(an)+ register gets returned to its pre-exception value and then     #
14571# we change the stack to an access error stack frame.                   #
14572#                                                                       #
14573#########################################################################
14574
14575facc_in_b:
14576        movq.l          &0x1,%d0                        # one byte
14577        bsr.w           restore                         # fix An
14578
14579        mov.w           &0x0121,EXC_VOFF(%a6)           # set FSLW
14580        bra.w           facc_finish
14581
14582facc_in_w:
14583        movq.l          &0x2,%d0                        # two bytes
14584        bsr.w           restore                         # fix An
14585
14586        mov.w           &0x0141,EXC_VOFF(%a6)           # set FSLW
14587        bra.b           facc_finish
14588
14589facc_in_l:
14590        movq.l          &0x4,%d0                        # four bytes
14591        bsr.w           restore                         # fix An
14592
14593        mov.w           &0x0101,EXC_VOFF(%a6)           # set FSLW
14594        bra.b           facc_finish
14595
14596facc_in_d:
14597        movq.l          &0x8,%d0                        # eight bytes
14598        bsr.w           restore                         # fix An
14599
14600        mov.w           &0x0161,EXC_VOFF(%a6)           # set FSLW
14601        bra.b           facc_finish
14602
14603facc_in_x:
14604        movq.l          &0xc,%d0                        # twelve bytes
14605        bsr.w           restore                         # fix An
14606
14607        mov.w           &0x0161,EXC_VOFF(%a6)           # set FSLW
14608        bra.b           facc_finish
14609
14610################################################################
14611
14612facc_out_b:
14613        movq.l          &0x1,%d0                        # one byte
14614        bsr.w           restore                         # restore An
14615
14616        mov.w           &0x00a1,EXC_VOFF(%a6)           # set FSLW
14617        bra.b           facc_finish
14618
14619facc_out_w:
14620        movq.l          &0x2,%d0                        # two bytes
14621        bsr.w           restore                         # restore An
14622
14623        mov.w           &0x00c1,EXC_VOFF(%a6)           # set FSLW
14624        bra.b           facc_finish
14625
14626facc_out_l:
14627        movq.l          &0x4,%d0                        # four bytes
14628        bsr.w           restore                         # restore An
14629
14630        mov.w           &0x0081,EXC_VOFF(%a6)           # set FSLW
14631        bra.b           facc_finish
14632
14633facc_out_d:
14634        movq.l          &0x8,%d0                        # eight bytes
14635        bsr.w           restore                         # restore An
14636
14637        mov.w           &0x00e1,EXC_VOFF(%a6)           # set FSLW
14638        bra.b           facc_finish
14639
14640facc_out_x:
14641        mov.l           &0xc,%d0                        # twelve bytes
14642        bsr.w           restore                         # restore An
14643
14644        mov.w           &0x00e1,EXC_VOFF(%a6)           # set FSLW
14645
14646# here's where we actually create the access error frame from the
14647# current exception stack frame.
14648facc_finish:
14649        mov.l           USER_FPIAR(%a6),EXC_PC(%a6) # store current PC
14650
14651        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
14652        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
14653        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
14654
14655        unlk            %a6
14656
14657        mov.l           (%sp),-(%sp)            # store SR, hi(PC)
14658        mov.l           0x8(%sp),0x4(%sp)       # store lo(PC)
14659        mov.l           0xc(%sp),0x8(%sp)       # store EA
14660        mov.l           &0x00000001,0xc(%sp)    # store FSLW
14661        mov.w           0x6(%sp),0xc(%sp)       # fix FSLW (size)
14662        mov.w           &0x4008,0x6(%sp)        # store voff
14663
14664        btst            &0x5,(%sp)              # supervisor or user mode?
14665        beq.b           facc_out2               # user
14666        bset            &0x2,0xd(%sp)           # set supervisor TM bit
14667
14668facc_out2:
14669        bra.l           _real_access
14670
14671##################################################################
14672
14673# if the effective addressing mode was predecrement or postincrement,
14674# the emulation has already changed its value to the correct post-
14675# instruction value. but since we're exiting to the access error
14676# handler, then AN must be returned to its pre-instruction value.
14677# we do that here.
14678restore:
14679        mov.b           EXC_OPWORD+0x1(%a6),%d1
14680        andi.b          &0x38,%d1               # extract opmode
14681        cmpi.b          %d1,&0x18               # postinc?
14682        beq.w           rest_inc
14683        cmpi.b          %d1,&0x20               # predec?
14684        beq.w           rest_dec
14685        rts
14686
14687rest_inc:
14688        mov.b           EXC_OPWORD+0x1(%a6),%d1
14689        andi.w          &0x0007,%d1             # fetch An
14690
14691        mov.w           (tbl_rest_inc.b,%pc,%d1.w*2),%d1
14692        jmp             (tbl_rest_inc.b,%pc,%d1.w*1)
14693
14694tbl_rest_inc:
14695        short           ri_a0 - tbl_rest_inc
14696        short           ri_a1 - tbl_rest_inc
14697        short           ri_a2 - tbl_rest_inc
14698        short           ri_a3 - tbl_rest_inc
14699        short           ri_a4 - tbl_rest_inc
14700        short           ri_a5 - tbl_rest_inc
14701        short           ri_a6 - tbl_rest_inc
14702        short           ri_a7 - tbl_rest_inc
14703
14704ri_a0:
14705        sub.l           %d0,EXC_DREGS+0x8(%a6)  # fix stacked a0
14706        rts
14707ri_a1:
14708        sub.l           %d0,EXC_DREGS+0xc(%a6)  # fix stacked a1
14709        rts
14710ri_a2:
14711        sub.l           %d0,%a2                 # fix a2
14712        rts
14713ri_a3:
14714        sub.l           %d0,%a3                 # fix a3
14715        rts
14716ri_a4:
14717        sub.l           %d0,%a4                 # fix a4
14718        rts
14719ri_a5:
14720        sub.l           %d0,%a5                 # fix a5
14721        rts
14722ri_a6:
14723        sub.l           %d0,(%a6)               # fix stacked a6
14724        rts
14725# if it's a fmove out instruction, we don't have to fix a7
14726# because we hadn't changed it yet. if it's an opclass two
14727# instruction (data moved in) and the exception was in supervisor
14728# mode, then also also wasn't updated. if it was user mode, then
14729# restore the correct a7 which is in the USP currently.
14730ri_a7:
14731        cmpi.b          EXC_VOFF(%a6),&0x30     # move in or out?
14732        bne.b           ri_a7_done              # out
14733
14734        btst            &0x5,EXC_SR(%a6)        # user or supervisor?
14735        bne.b           ri_a7_done              # supervisor
14736        movc            %usp,%a0                # restore USP
14737        sub.l           %d0,%a0
14738        movc            %a0,%usp
14739ri_a7_done:
14740        rts
14741
14742# need to invert adjustment value if the <ea> was predec
14743rest_dec:
14744        neg.l           %d0
14745        bra.b           rest_inc
14746