linux/arch/m68k/ifpsp060/src/fpsp.S
<<
>>
Prefs
   1~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   2MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
   3M68000 Hi-Performance Microprocessor Division
   4M68060 Software Package
   5Production Release P1.00 -- October 10, 1994
   6
   7M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.
   8
   9THE SOFTWARE is provided on an "AS IS" basis and without warranty.
  10To the maximum extent permitted by applicable law,
  11MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
  12INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
  13and any warranty against infringement with regard to the SOFTWARE
  14(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
  15
  16To the maximum extent permitted by applicable law,
  17IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
  18(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
  19BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
  20ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
  21Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
  22
  23You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
  24so long as this entire notice is retained without alteration in any modified and/or
  25redistributed versions, and that such modified versions are clearly identified as such.
  26No licenses are granted by implication, estoppel or otherwise under any patents
  27or trademarks of Motorola, Inc.
  28~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  29#
  30# freal.s:
  31#       This file is appended to the top of the 060FPSP package
  32# and contains the entry points into the package. The user, in
  33# effect, branches to one of the branch table entries located
  34# after _060FPSP_TABLE.
  35#       Also, subroutine stubs exist in this file (_fpsp_done for
  36# example) that are referenced by the FPSP package itself in order
  37# to call a given routine. The stub routine actually performs the
  38# callout. The FPSP code does a "bsr" to the stub routine. This
  39# extra layer of hierarchy adds a slight performance penalty but
  40# it makes the FPSP code easier to read and more mainatinable.
  41#
  42
  43set     _off_bsun,      0x00
  44set     _off_snan,      0x04
  45set     _off_operr,     0x08
  46set     _off_ovfl,      0x0c
  47set     _off_unfl,      0x10
  48set     _off_dz,        0x14
  49set     _off_inex,      0x18
  50set     _off_fline,     0x1c
  51set     _off_fpu_dis,   0x20
  52set     _off_trap,      0x24
  53set     _off_trace,     0x28
  54set     _off_access,    0x2c
  55set     _off_done,      0x30
  56
  57set     _off_imr,       0x40
  58set     _off_dmr,       0x44
  59set     _off_dmw,       0x48
  60set     _off_irw,       0x4c
  61set     _off_irl,       0x50
  62set     _off_drb,       0x54
  63set     _off_drw,       0x58
  64set     _off_drl,       0x5c
  65set     _off_dwb,       0x60
  66set     _off_dww,       0x64
  67set     _off_dwl,       0x68
  68
  69_060FPSP_TABLE:
  70
  71###############################################################
  72
  73# Here's the table of ENTRY POINTS for those linking the package.
  74        bra.l           _fpsp_snan
  75        short           0x0000
  76        bra.l           _fpsp_operr
  77        short           0x0000
  78        bra.l           _fpsp_ovfl
  79        short           0x0000
  80        bra.l           _fpsp_unfl
  81        short           0x0000
  82        bra.l           _fpsp_dz
  83        short           0x0000
  84        bra.l           _fpsp_inex
  85        short           0x0000
  86        bra.l           _fpsp_fline
  87        short           0x0000
  88        bra.l           _fpsp_unsupp
  89        short           0x0000
  90        bra.l           _fpsp_effadd
  91        short           0x0000
  92
  93        space           56
  94
  95###############################################################
  96        global          _fpsp_done
  97_fpsp_done:
  98        mov.l           %d0,-(%sp)
  99        mov.l           (_060FPSP_TABLE-0x80+_off_done,%pc),%d0
 100        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 101        mov.l           0x4(%sp),%d0
 102        rtd             &0x4
 103
 104        global          _real_ovfl
 105_real_ovfl:
 106        mov.l           %d0,-(%sp)
 107        mov.l           (_060FPSP_TABLE-0x80+_off_ovfl,%pc),%d0
 108        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 109        mov.l           0x4(%sp),%d0
 110        rtd             &0x4
 111
 112        global          _real_unfl
 113_real_unfl:
 114        mov.l           %d0,-(%sp)
 115        mov.l           (_060FPSP_TABLE-0x80+_off_unfl,%pc),%d0
 116        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 117        mov.l           0x4(%sp),%d0
 118        rtd             &0x4
 119
 120        global          _real_inex
 121_real_inex:
 122        mov.l           %d0,-(%sp)
 123        mov.l           (_060FPSP_TABLE-0x80+_off_inex,%pc),%d0
 124        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 125        mov.l           0x4(%sp),%d0
 126        rtd             &0x4
 127
 128        global          _real_bsun
 129_real_bsun:
 130        mov.l           %d0,-(%sp)
 131        mov.l           (_060FPSP_TABLE-0x80+_off_bsun,%pc),%d0
 132        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 133        mov.l           0x4(%sp),%d0
 134        rtd             &0x4
 135
 136        global          _real_operr
 137_real_operr:
 138        mov.l           %d0,-(%sp)
 139        mov.l           (_060FPSP_TABLE-0x80+_off_operr,%pc),%d0
 140        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 141        mov.l           0x4(%sp),%d0
 142        rtd             &0x4
 143
 144        global          _real_snan
 145_real_snan:
 146        mov.l           %d0,-(%sp)
 147        mov.l           (_060FPSP_TABLE-0x80+_off_snan,%pc),%d0
 148        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 149        mov.l           0x4(%sp),%d0
 150        rtd             &0x4
 151
 152        global          _real_dz
 153_real_dz:
 154        mov.l           %d0,-(%sp)
 155        mov.l           (_060FPSP_TABLE-0x80+_off_dz,%pc),%d0
 156        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 157        mov.l           0x4(%sp),%d0
 158        rtd             &0x4
 159
 160        global          _real_fline
 161_real_fline:
 162        mov.l           %d0,-(%sp)
 163        mov.l           (_060FPSP_TABLE-0x80+_off_fline,%pc),%d0
 164        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 165        mov.l           0x4(%sp),%d0
 166        rtd             &0x4
 167
 168        global          _real_fpu_disabled
 169_real_fpu_disabled:
 170        mov.l           %d0,-(%sp)
 171        mov.l           (_060FPSP_TABLE-0x80+_off_fpu_dis,%pc),%d0
 172        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 173        mov.l           0x4(%sp),%d0
 174        rtd             &0x4
 175
 176        global          _real_trap
 177_real_trap:
 178        mov.l           %d0,-(%sp)
 179        mov.l           (_060FPSP_TABLE-0x80+_off_trap,%pc),%d0
 180        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 181        mov.l           0x4(%sp),%d0
 182        rtd             &0x4
 183
 184        global          _real_trace
 185_real_trace:
 186        mov.l           %d0,-(%sp)
 187        mov.l           (_060FPSP_TABLE-0x80+_off_trace,%pc),%d0
 188        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 189        mov.l           0x4(%sp),%d0
 190        rtd             &0x4
 191
 192        global          _real_access
 193_real_access:
 194        mov.l           %d0,-(%sp)
 195        mov.l           (_060FPSP_TABLE-0x80+_off_access,%pc),%d0
 196        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 197        mov.l           0x4(%sp),%d0
 198        rtd             &0x4
 199
 200#######################################
 201
 202        global          _imem_read
 203_imem_read:
 204        mov.l           %d0,-(%sp)
 205        mov.l           (_060FPSP_TABLE-0x80+_off_imr,%pc),%d0
 206        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 207        mov.l           0x4(%sp),%d0
 208        rtd             &0x4
 209
 210        global          _dmem_read
 211_dmem_read:
 212        mov.l           %d0,-(%sp)
 213        mov.l           (_060FPSP_TABLE-0x80+_off_dmr,%pc),%d0
 214        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 215        mov.l           0x4(%sp),%d0
 216        rtd             &0x4
 217
 218        global          _dmem_write
 219_dmem_write:
 220        mov.l           %d0,-(%sp)
 221        mov.l           (_060FPSP_TABLE-0x80+_off_dmw,%pc),%d0
 222        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 223        mov.l           0x4(%sp),%d0
 224        rtd             &0x4
 225
 226        global          _imem_read_word
 227_imem_read_word:
 228        mov.l           %d0,-(%sp)
 229        mov.l           (_060FPSP_TABLE-0x80+_off_irw,%pc),%d0
 230        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 231        mov.l           0x4(%sp),%d0
 232        rtd             &0x4
 233
 234        global          _imem_read_long
 235_imem_read_long:
 236        mov.l           %d0,-(%sp)
 237        mov.l           (_060FPSP_TABLE-0x80+_off_irl,%pc),%d0
 238        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 239        mov.l           0x4(%sp),%d0
 240        rtd             &0x4
 241
 242        global          _dmem_read_byte
 243_dmem_read_byte:
 244        mov.l           %d0,-(%sp)
 245        mov.l           (_060FPSP_TABLE-0x80+_off_drb,%pc),%d0
 246        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 247        mov.l           0x4(%sp),%d0
 248        rtd             &0x4
 249
 250        global          _dmem_read_word
 251_dmem_read_word:
 252        mov.l           %d0,-(%sp)
 253        mov.l           (_060FPSP_TABLE-0x80+_off_drw,%pc),%d0
 254        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 255        mov.l           0x4(%sp),%d0
 256        rtd             &0x4
 257
 258        global          _dmem_read_long
 259_dmem_read_long:
 260        mov.l           %d0,-(%sp)
 261        mov.l           (_060FPSP_TABLE-0x80+_off_drl,%pc),%d0
 262        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 263        mov.l           0x4(%sp),%d0
 264        rtd             &0x4
 265
 266        global          _dmem_write_byte
 267_dmem_write_byte:
 268        mov.l           %d0,-(%sp)
 269        mov.l           (_060FPSP_TABLE-0x80+_off_dwb,%pc),%d0
 270        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 271        mov.l           0x4(%sp),%d0
 272        rtd             &0x4
 273
 274        global          _dmem_write_word
 275_dmem_write_word:
 276        mov.l           %d0,-(%sp)
 277        mov.l           (_060FPSP_TABLE-0x80+_off_dww,%pc),%d0
 278        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 279        mov.l           0x4(%sp),%d0
 280        rtd             &0x4
 281
 282        global          _dmem_write_long
 283_dmem_write_long:
 284        mov.l           %d0,-(%sp)
 285        mov.l           (_060FPSP_TABLE-0x80+_off_dwl,%pc),%d0
 286        pea.l           (_060FPSP_TABLE-0x80,%pc,%d0)
 287        mov.l           0x4(%sp),%d0
 288        rtd             &0x4
 289
 290#
 291# This file contains a set of define statements for constants
 292# in order to promote readability within the corecode itself.
 293#
 294
 295set LOCAL_SIZE,         192                     # stack frame size(bytes)
 296set LV,                 -LOCAL_SIZE             # stack offset
 297
 298set EXC_SR,             0x4                     # stack status register
 299set EXC_PC,             0x6                     # stack pc
 300set EXC_VOFF,           0xa                     # stacked vector offset
 301set EXC_EA,             0xc                     # stacked <ea>
 302
 303set EXC_FP,             0x0                     # frame pointer
 304
 305set EXC_AREGS,          -68                     # offset of all address regs
 306set EXC_DREGS,          -100                    # offset of all data regs
 307set EXC_FPREGS,         -36                     # offset of all fp regs
 308
 309set EXC_A7,             EXC_AREGS+(7*4)         # offset of saved a7
 310set OLD_A7,             EXC_AREGS+(6*4)         # extra copy of saved a7
 311set EXC_A6,             EXC_AREGS+(6*4)         # offset of saved a6
 312set EXC_A5,             EXC_AREGS+(5*4)
 313set EXC_A4,             EXC_AREGS+(4*4)
 314set EXC_A3,             EXC_AREGS+(3*4)
 315set EXC_A2,             EXC_AREGS+(2*4)
 316set EXC_A1,             EXC_AREGS+(1*4)
 317set EXC_A0,             EXC_AREGS+(0*4)
 318set EXC_D7,             EXC_DREGS+(7*4)
 319set EXC_D6,             EXC_DREGS+(6*4)
 320set EXC_D5,             EXC_DREGS+(5*4)
 321set EXC_D4,             EXC_DREGS+(4*4)
 322set EXC_D3,             EXC_DREGS+(3*4)
 323set EXC_D2,             EXC_DREGS+(2*4)
 324set EXC_D1,             EXC_DREGS+(1*4)
 325set EXC_D0,             EXC_DREGS+(0*4)
 326
 327set EXC_FP0,            EXC_FPREGS+(0*12)       # offset of saved fp0
 328set EXC_FP1,            EXC_FPREGS+(1*12)       # offset of saved fp1
 329set EXC_FP2,            EXC_FPREGS+(2*12)       # offset of saved fp2 (not used)
 330
 331set FP_SCR1,            LV+80                   # fp scratch 1
 332set FP_SCR1_EX,         FP_SCR1+0
 333set FP_SCR1_SGN,        FP_SCR1+2
 334set FP_SCR1_HI,         FP_SCR1+4
 335set FP_SCR1_LO,         FP_SCR1+8
 336
 337set FP_SCR0,            LV+68                   # fp scratch 0
 338set FP_SCR0_EX,         FP_SCR0+0
 339set FP_SCR0_SGN,        FP_SCR0+2
 340set FP_SCR0_HI,         FP_SCR0+4
 341set FP_SCR0_LO,         FP_SCR0+8
 342
 343set FP_DST,             LV+56                   # fp destination operand
 344set FP_DST_EX,          FP_DST+0
 345set FP_DST_SGN,         FP_DST+2
 346set FP_DST_HI,          FP_DST+4
 347set FP_DST_LO,          FP_DST+8
 348
 349set FP_SRC,             LV+44                   # fp source operand
 350set FP_SRC_EX,          FP_SRC+0
 351set FP_SRC_SGN,         FP_SRC+2
 352set FP_SRC_HI,          FP_SRC+4
 353set FP_SRC_LO,          FP_SRC+8
 354
 355set USER_FPIAR,         LV+40                   # FP instr address register
 356
 357set USER_FPSR,          LV+36                   # FP status register
 358set FPSR_CC,            USER_FPSR+0             # FPSR condition codes
 359set FPSR_QBYTE,         USER_FPSR+1             # FPSR qoutient byte
 360set FPSR_EXCEPT,        USER_FPSR+2             # FPSR exception status byte
 361set FPSR_AEXCEPT,       USER_FPSR+3             # FPSR accrued exception byte
 362
 363set USER_FPCR,          LV+32                   # FP control register
 364set FPCR_ENABLE,        USER_FPCR+2             # FPCR exception enable
 365set FPCR_MODE,          USER_FPCR+3             # FPCR rounding mode control
 366
 367set L_SCR3,             LV+28                   # integer scratch 3
 368set L_SCR2,             LV+24                   # integer scratch 2
 369set L_SCR1,             LV+20                   # integer scratch 1
 370
 371set STORE_FLG,          LV+19                   # flag: operand store (ie. not fcmp/ftst)
 372
 373set EXC_TEMP2,          LV+24                   # temporary space
 374set EXC_TEMP,           LV+16                   # temporary space
 375
 376set DTAG,               LV+15                   # destination operand type
 377set STAG,               LV+14                   # source operand type
 378
 379set SPCOND_FLG,         LV+10                   # flag: special case (see below)
 380
 381set EXC_CC,             LV+8                    # saved condition codes
 382set EXC_EXTWPTR,        LV+4                    # saved current PC (active)
 383set EXC_EXTWORD,        LV+2                    # saved extension word
 384set EXC_CMDREG,         LV+2                    # saved extension word
 385set EXC_OPWORD,         LV+0                    # saved operation word
 386
 387################################
 388
 389# Helpful macros
 390
 391set FTEMP,              0                       # offsets within an
 392set FTEMP_EX,           0                       # extended precision
 393set FTEMP_SGN,          2                       # value saved in memory.
 394set FTEMP_HI,           4
 395set FTEMP_LO,           8
 396set FTEMP_GRS,          12
 397
 398set LOCAL,              0                       # offsets within an
 399set LOCAL_EX,           0                       # extended precision
 400set LOCAL_SGN,          2                       # value saved in memory.
 401set LOCAL_HI,           4
 402set LOCAL_LO,           8
 403set LOCAL_GRS,          12
 404
 405set DST,                0                       # offsets within an
 406set DST_EX,             0                       # extended precision
 407set DST_HI,             4                       # value saved in memory.
 408set DST_LO,             8
 409
 410set SRC,                0                       # offsets within an
 411set SRC_EX,             0                       # extended precision
 412set SRC_HI,             4                       # value saved in memory.
 413set SRC_LO,             8
 414
 415set SGL_LO,             0x3f81                  # min sgl prec exponent
 416set SGL_HI,             0x407e                  # max sgl prec exponent
 417set DBL_LO,             0x3c01                  # min dbl prec exponent
 418set DBL_HI,             0x43fe                  # max dbl prec exponent
 419set EXT_LO,             0x0                     # min ext prec exponent
 420set EXT_HI,             0x7ffe                  # max ext prec exponent
 421
 422set EXT_BIAS,           0x3fff                  # extended precision bias
 423set SGL_BIAS,           0x007f                  # single precision bias
 424set DBL_BIAS,           0x03ff                  # double precision bias
 425
 426set NORM,               0x00                    # operand type for STAG/DTAG
 427set ZERO,               0x01                    # operand type for STAG/DTAG
 428set INF,                0x02                    # operand type for STAG/DTAG
 429set QNAN,               0x03                    # operand type for STAG/DTAG
 430set DENORM,             0x04                    # operand type for STAG/DTAG
 431set SNAN,               0x05                    # operand type for STAG/DTAG
 432set UNNORM,             0x06                    # operand type for STAG/DTAG
 433
 434##################
 435# FPSR/FPCR bits #
 436##################
 437set neg_bit,            0x3                     # negative result
 438set z_bit,              0x2                     # zero result
 439set inf_bit,            0x1                     # infinite result
 440set nan_bit,            0x0                     # NAN result
 441
 442set q_sn_bit,           0x7                     # sign bit of quotient byte
 443
 444set bsun_bit,           7                       # branch on unordered
 445set snan_bit,           6                       # signalling NAN
 446set operr_bit,          5                       # operand error
 447set ovfl_bit,           4                       # overflow
 448set unfl_bit,           3                       # underflow
 449set dz_bit,             2                       # divide by zero
 450set inex2_bit,          1                       # inexact result 2
 451set inex1_bit,          0                       # inexact result 1
 452
 453set aiop_bit,           7                       # accrued inexact operation bit
 454set aovfl_bit,          6                       # accrued overflow bit
 455set aunfl_bit,          5                       # accrued underflow bit
 456set adz_bit,            4                       # accrued dz bit
 457set ainex_bit,          3                       # accrued inexact bit
 458
 459#############################
 460# FPSR individual bit masks #
 461#############################
 462set neg_mask,           0x08000000              # negative bit mask (lw)
 463set inf_mask,           0x02000000              # infinity bit mask (lw)
 464set z_mask,             0x04000000              # zero bit mask (lw)
 465set nan_mask,           0x01000000              # nan bit mask (lw)
 466
 467set neg_bmask,          0x08                    # negative bit mask (byte)
 468set inf_bmask,          0x02                    # infinity bit mask (byte)
 469set z_bmask,            0x04                    # zero bit mask (byte)
 470set nan_bmask,          0x01                    # nan bit mask (byte)
 471
 472set bsun_mask,          0x00008000              # bsun exception mask
 473set snan_mask,          0x00004000              # snan exception mask
 474set operr_mask,         0x00002000              # operr exception mask
 475set ovfl_mask,          0x00001000              # overflow exception mask
 476set unfl_mask,          0x00000800              # underflow exception mask
 477set dz_mask,            0x00000400              # dz exception mask
 478set inex2_mask,         0x00000200              # inex2 exception mask
 479set inex1_mask,         0x00000100              # inex1 exception mask
 480
 481set aiop_mask,          0x00000080              # accrued illegal operation
 482set aovfl_mask,         0x00000040              # accrued overflow
 483set aunfl_mask,         0x00000020              # accrued underflow
 484set adz_mask,           0x00000010              # accrued divide by zero
 485set ainex_mask,         0x00000008              # accrued inexact
 486
 487######################################
 488# FPSR combinations used in the FPSP #
 489######################################
 490set dzinf_mask,         inf_mask+dz_mask+adz_mask
 491set opnan_mask,         nan_mask+operr_mask+aiop_mask
 492set nzi_mask,           0x01ffffff              #clears N, Z, and I
 493set unfinx_mask,        unfl_mask+inex2_mask+aunfl_mask+ainex_mask
 494set unf2inx_mask,       unfl_mask+inex2_mask+ainex_mask
 495set ovfinx_mask,        ovfl_mask+inex2_mask+aovfl_mask+ainex_mask
 496set inx1a_mask,         inex1_mask+ainex_mask
 497set inx2a_mask,         inex2_mask+ainex_mask
 498set snaniop_mask,       nan_mask+snan_mask+aiop_mask
 499set snaniop2_mask,      snan_mask+aiop_mask
 500set naniop_mask,        nan_mask+aiop_mask
 501set neginf_mask,        neg_mask+inf_mask
 502set infaiop_mask,       inf_mask+aiop_mask
 503set negz_mask,          neg_mask+z_mask
 504set opaop_mask,         operr_mask+aiop_mask
 505set unfl_inx_mask,      unfl_mask+aunfl_mask+ainex_mask
 506set ovfl_inx_mask,      ovfl_mask+aovfl_mask+ainex_mask
 507
 508#########
 509# misc. #
 510#########
 511set rnd_stky_bit,       29                      # stky bit pos in longword
 512
 513set sign_bit,           0x7                     # sign bit
 514set signan_bit,         0x6                     # signalling nan bit
 515
 516set sgl_thresh,         0x3f81                  # minimum sgl exponent
 517set dbl_thresh,         0x3c01                  # minimum dbl exponent
 518
 519set x_mode,             0x0                     # extended precision
 520set s_mode,             0x4                     # single precision
 521set d_mode,             0x8                     # double precision
 522
 523set rn_mode,            0x0                     # round-to-nearest
 524set rz_mode,            0x1                     # round-to-zero
 525set rm_mode,            0x2                     # round-tp-minus-infinity
 526set rp_mode,            0x3                     # round-to-plus-infinity
 527
 528set mantissalen,        64                      # length of mantissa in bits
 529
 530set BYTE,               1                       # len(byte) == 1 byte
 531set WORD,               2                       # len(word) == 2 bytes
 532set LONG,               4                       # len(longword) == 2 bytes
 533
 534set BSUN_VEC,           0xc0                    # bsun    vector offset
 535set INEX_VEC,           0xc4                    # inexact vector offset
 536set DZ_VEC,             0xc8                    # dz      vector offset
 537set UNFL_VEC,           0xcc                    # unfl    vector offset
 538set OPERR_VEC,          0xd0                    # operr   vector offset
 539set OVFL_VEC,           0xd4                    # ovfl    vector offset
 540set SNAN_VEC,           0xd8                    # snan    vector offset
 541
 542###########################
 543# SPecial CONDition FLaGs #
 544###########################
 545set ftrapcc_flg,        0x01                    # flag bit: ftrapcc exception
 546set fbsun_flg,          0x02                    # flag bit: bsun exception
 547set mia7_flg,           0x04                    # flag bit: (a7)+ <ea>
 548set mda7_flg,           0x08                    # flag bit: -(a7) <ea>
 549set fmovm_flg,          0x40                    # flag bit: fmovm instruction
 550set immed_flg,          0x80                    # flag bit: &<data> <ea>
 551
 552set ftrapcc_bit,        0x0
 553set fbsun_bit,          0x1
 554set mia7_bit,           0x2
 555set mda7_bit,           0x3
 556set immed_bit,          0x7
 557
 558##################################
 559# TRANSCENDENTAL "LAST-OP" FLAGS #
 560##################################
 561set FMUL_OP,            0x0                     # fmul instr performed last
 562set FDIV_OP,            0x1                     # fdiv performed last
 563set FADD_OP,            0x2                     # fadd performed last
 564set FMOV_OP,            0x3                     # fmov performed last
 565
 566#############
 567# CONSTANTS #
 568#############
 569T1:     long            0x40C62D38,0xD3D64634   # 16381 LOG2 LEAD
 570T2:     long            0x3D6F90AE,0xB1E75CC7   # 16381 LOG2 TRAIL
 571
 572PI:     long            0x40000000,0xC90FDAA2,0x2168C235,0x00000000
 573PIBY2:  long            0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000
 574
 575TWOBYPI:
 576        long            0x3FE45F30,0x6DC9C883
 577
 578#########################################################################
 579# XDEF **************************************************************** #
 580#       _fpsp_ovfl(): 060FPSP entry point for FP Overflow exception.    #
 581#                                                                       #
 582#       This handler should be the first code executed upon taking the  #
 583#       FP Overflow exception in an operating system.                   #
 584#                                                                       #
 585# XREF **************************************************************** #
 586#       _imem_read_long() - read instruction longword                   #
 587#       fix_skewed_ops() - adjust src operand in fsave frame            #
 588#       set_tag_x() - determine optype of src/dst operands              #
 589#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
 590#       unnorm_fix() - change UNNORM operands to NORM or ZERO           #
 591#       load_fpn2() - load dst operand from FP regfile                  #
 592#       fout() - emulate an opclass 3 instruction                       #
 593#       tbl_unsupp - add of table of emulation routines for opclass 0,2 #
 594#       _fpsp_done() - "callout" for 060FPSP exit (all work done!)      #
 595#       _real_ovfl() - "callout" for Overflow exception enabled code    #
 596#       _real_inex() - "callout" for Inexact exception enabled code     #
 597#       _real_trace() - "callout" for Trace exception code              #
 598#                                                                       #
 599# INPUT *************************************************************** #
 600#       - The system stack contains the FP Ovfl exception stack frame   #
 601#       - The fsave frame contains the source operand                   #
 602#                                                                       #
 603# OUTPUT ************************************************************** #
 604#       Overflow Exception enabled:                                     #
 605#       - The system stack is unchanged                                 #
 606#       - The fsave frame contains the adjusted src op for opclass 0,2  #
 607#       Overflow Exception disabled:                                    #
 608#       - The system stack is unchanged                                 #
 609#       - The "exception present" flag in the fsave frame is cleared    #
 610#                                                                       #
 611# ALGORITHM *********************************************************** #
 612#       On the 060, if an FP overflow is present as the result of any   #
 613# instruction, the 060 will take an overflow exception whether the      #
 614# exception is enabled or disabled in the FPCR. For the disabled case,  #
 615# This handler emulates the instruction to determine what the correct   #
 616# default result should be for the operation. This default result is    #
 617# then stored in either the FP regfile, data regfile, or memory.        #
 618# Finally, the handler exits through the "callout" _fpsp_done()         #
 619# denoting that no exceptional conditions exist within the machine.     #
 620#       If the exception is enabled, then this handler must create the  #
 621# exceptional operand and plave it in the fsave state frame, and store  #
 622# the default result (only if the instruction is opclass 3). For        #
 623# exceptions enabled, this handler must exit through the "callout"      #
 624# _real_ovfl() so that the operating system enabled overflow handler    #
 625# can handle this case.                                                 #
 626#       Two other conditions exist. First, if overflow was disabled     #
 627# but the inexact exception was enabled, this handler must exit         #
 628# through the "callout" _real_inex() regardless of whether the result   #
 629# was inexact.                                                          #
 630#       Also, in the case of an opclass three instruction where         #
 631# overflow was disabled and the trace exception was enabled, this       #
 632# handler must exit through the "callout" _real_trace().                #
 633#                                                                       #
 634#########################################################################
 635
 636        global          _fpsp_ovfl
 637_fpsp_ovfl:
 638
 639#$#     sub.l           &24,%sp                 # make room for src/dst
 640
 641        link.w          %a6,&-LOCAL_SIZE        # init stack frame
 642
 643        fsave           FP_SRC(%a6)             # grab the "busy" frame
 644
 645        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
 646        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
 647        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
 648
 649# the FPIAR holds the "current PC" of the faulting instruction
 650        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
 651        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
 652        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
 653        bsr.l           _imem_read_long         # fetch the instruction words
 654        mov.l           %d0,EXC_OPWORD(%a6)
 655
 656##############################################################################
 657
 658        btst            &0x5,EXC_CMDREG(%a6)    # is instr an fmove out?
 659        bne.w           fovfl_out
 660
 661
 662        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
 663        bsr.l           fix_skewed_ops          # fix src op
 664
 665# since, I believe, only NORMs and DENORMs can come through here,
 666# maybe we can avoid the subroutine call.
 667        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
 668        bsr.l           set_tag_x               # tag the operand type
 669        mov.b           %d0,STAG(%a6)           # maybe NORM,DENORM
 670
 671# bit five of the fp extension word separates the monadic and dyadic operations
 672# that can pass through fpsp_ovfl(). remember that fcmp, ftst, and fsincos
 673# will never take this exception.
 674        btst            &0x5,1+EXC_CMDREG(%a6)  # is operation monadic or dyadic?
 675        beq.b           fovfl_extract           # monadic
 676
 677        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
 678        bsr.l           load_fpn2               # load dst into FP_DST
 679
 680        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
 681        bsr.l           set_tag_x               # tag the operand type
 682        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
 683        bne.b           fovfl_op2_done          # no
 684        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
 685fovfl_op2_done:
 686        mov.b           %d0,DTAG(%a6)           # save dst optype tag
 687
 688fovfl_extract:
 689
 690#$#     mov.l           FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
 691#$#     mov.l           FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
 692#$#     mov.l           FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
 693#$#     mov.l           FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6)
 694#$#     mov.l           FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6)
 695#$#     mov.l           FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6)
 696
 697        clr.l           %d0
 698        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec/mode
 699
 700        mov.b           1+EXC_CMDREG(%a6),%d1
 701        andi.w          &0x007f,%d1             # extract extension
 702
 703        andi.l          &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field
 704
 705        fmov.l          &0x0,%fpcr              # zero current control regs
 706        fmov.l          &0x0,%fpsr
 707
 708        lea             FP_SRC(%a6),%a0
 709        lea             FP_DST(%a6),%a1
 710
 711# maybe we can make these entry points ONLY the OVFL entry points of each routine.
 712        mov.l           (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
 713        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
 714
 715# the operation has been emulated. the result is in fp0.
 716# the EXOP, if an exception occurred, is in fp1.
 717# we must save the default result regardless of whether
 718# traps are enabled or disabled.
 719        bfextu          EXC_CMDREG(%a6){&6:&3},%d0
 720        bsr.l           store_fpreg
 721
 722# the exceptional possibilities we have left ourselves with are ONLY overflow
 723# and inexact. and, the inexact is such that overflow occurred and was disabled
 724# but inexact was enabled.
 725        btst            &ovfl_bit,FPCR_ENABLE(%a6)
 726        bne.b           fovfl_ovfl_on
 727
 728        btst            &inex2_bit,FPCR_ENABLE(%a6)
 729        bne.b           fovfl_inex_on
 730
 731        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
 732        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 733        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
 734
 735        unlk            %a6
 736#$#     add.l           &24,%sp
 737        bra.l           _fpsp_done
 738
 739# overflow is enabled AND overflow, of course, occurred. so, we have the EXOP
 740# in fp1. now, simply jump to _real_ovfl()!
 741fovfl_ovfl_on:
 742        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP (fp1) to stack
 743
 744        mov.w           &0xe005,2+FP_SRC(%a6)   # save exc status
 745
 746        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
 747        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 748        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
 749
 750        frestore        FP_SRC(%a6)             # do this after fmovm,other f<op>s!
 751
 752        unlk            %a6
 753
 754        bra.l           _real_ovfl
 755
 756# overflow occurred but is disabled. meanwhile, inexact is enabled. Therefore,
 757# we must jump to real_inex().
 758fovfl_inex_on:
 759
 760        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP (fp1) to stack
 761
 762        mov.b           &0xc4,1+EXC_VOFF(%a6)   # vector offset = 0xc4
 763        mov.w           &0xe001,2+FP_SRC(%a6)   # save exc status
 764
 765        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
 766        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 767        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
 768
 769        frestore        FP_SRC(%a6)             # do this after fmovm,other f<op>s!
 770
 771        unlk            %a6
 772
 773        bra.l           _real_inex
 774
 775########################################################################
 776fovfl_out:
 777
 778
 779#$#     mov.l           FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
 780#$#     mov.l           FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
 781#$#     mov.l           FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
 782
 783# the src operand is definitely a NORM(!), so tag it as such
 784        mov.b           &NORM,STAG(%a6)         # set src optype tag
 785
 786        clr.l           %d0
 787        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec/mode
 788
 789        and.l           &0xffff00ff,USER_FPSR(%a6) # zero all but accured field
 790
 791        fmov.l          &0x0,%fpcr              # zero current control regs
 792        fmov.l          &0x0,%fpsr
 793
 794        lea             FP_SRC(%a6),%a0         # pass ptr to src operand
 795
 796        bsr.l           fout
 797
 798        btst            &ovfl_bit,FPCR_ENABLE(%a6)
 799        bne.w           fovfl_ovfl_on
 800
 801        btst            &inex2_bit,FPCR_ENABLE(%a6)
 802        bne.w           fovfl_inex_on
 803
 804        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
 805        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 806        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
 807
 808        unlk            %a6
 809#$#     add.l           &24,%sp
 810
 811        btst            &0x7,(%sp)              # is trace on?
 812        beq.l           _fpsp_done              # no
 813
 814        fmov.l          %fpiar,0x8(%sp)         # "Current PC" is in FPIAR
 815        mov.w           &0x2024,0x6(%sp)        # stk fmt = 0x2; voff = 0x024
 816        bra.l           _real_trace
 817
 818#########################################################################
 819# XDEF **************************************************************** #
 820#       _fpsp_unfl(): 060FPSP entry point for FP Underflow exception.   #
 821#                                                                       #
 822#       This handler should be the first code executed upon taking the  #
 823#       FP Underflow exception in an operating system.                  #
 824#                                                                       #
 825# XREF **************************************************************** #
 826#       _imem_read_long() - read instruction longword                   #
 827#       fix_skewed_ops() - adjust src operand in fsave frame            #
 828#       set_tag_x() - determine optype of src/dst operands              #
 829#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
 830#       unnorm_fix() - change UNNORM operands to NORM or ZERO           #
 831#       load_fpn2() - load dst operand from FP regfile                  #
 832#       fout() - emulate an opclass 3 instruction                       #
 833#       tbl_unsupp - add of table of emulation routines for opclass 0,2 #
 834#       _fpsp_done() - "callout" for 060FPSP exit (all work done!)      #
 835#       _real_ovfl() - "callout" for Overflow exception enabled code    #
 836#       _real_inex() - "callout" for Inexact exception enabled code     #
 837#       _real_trace() - "callout" for Trace exception code              #
 838#                                                                       #
 839# INPUT *************************************************************** #
 840#       - The system stack contains the FP Unfl exception stack frame   #
 841#       - The fsave frame contains the source operand                   #
 842#                                                                       #
 843# OUTPUT ************************************************************** #
 844#       Underflow Exception enabled:                                    #
 845#       - The system stack is unchanged                                 #
 846#       - The fsave frame contains the adjusted src op for opclass 0,2  #
 847#       Underflow Exception disabled:                                   #
 848#       - The system stack is unchanged                                 #
 849#       - The "exception present" flag in the fsave frame is cleared    #
 850#                                                                       #
 851# ALGORITHM *********************************************************** #
 852#       On the 060, if an FP underflow is present as the result of any  #
 853# instruction, the 060 will take an underflow exception whether the     #
 854# exception is enabled or disabled in the FPCR. For the disabled case,  #
 855# This handler emulates the instruction to determine what the correct   #
 856# default result should be for the operation. This default result is    #
 857# then stored in either the FP regfile, data regfile, or memory.        #
 858# Finally, the handler exits through the "callout" _fpsp_done()         #
 859# denoting that no exceptional conditions exist within the machine.     #
 860#       If the exception is enabled, then this handler must create the  #
 861# exceptional operand and plave it in the fsave state frame, and store  #
 862# the default result (only if the instruction is opclass 3). For        #
 863# exceptions enabled, this handler must exit through the "callout"      #
 864# _real_unfl() so that the operating system enabled overflow handler    #
 865# can handle this case.                                                 #
 866#       Two other conditions exist. First, if underflow was disabled    #
 867# but the inexact exception was enabled and the result was inexact,     #
 868# this handler must exit through the "callout" _real_inex().            #
 869# was inexact.                                                          #
 870#       Also, in the case of an opclass three instruction where         #
 871# underflow was disabled and the trace exception was enabled, this      #
 872# handler must exit through the "callout" _real_trace().                #
 873#                                                                       #
 874#########################################################################
 875
 876        global          _fpsp_unfl
 877_fpsp_unfl:
 878
 879#$#     sub.l           &24,%sp                 # make room for src/dst
 880
 881        link.w          %a6,&-LOCAL_SIZE        # init stack frame
 882
 883        fsave           FP_SRC(%a6)             # grab the "busy" frame
 884
 885        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
 886        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
 887        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
 888
 889# the FPIAR holds the "current PC" of the faulting instruction
 890        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
 891        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
 892        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
 893        bsr.l           _imem_read_long         # fetch the instruction words
 894        mov.l           %d0,EXC_OPWORD(%a6)
 895
 896##############################################################################
 897
 898        btst            &0x5,EXC_CMDREG(%a6)    # is instr an fmove out?
 899        bne.w           funfl_out
 900
 901
 902        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
 903        bsr.l           fix_skewed_ops          # fix src op
 904
 905        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
 906        bsr.l           set_tag_x               # tag the operand type
 907        mov.b           %d0,STAG(%a6)           # maybe NORM,DENORM
 908
 909# bit five of the fp ext word separates the monadic and dyadic operations
 910# that can pass through fpsp_unfl(). remember that fcmp, and ftst
 911# will never take this exception.
 912        btst            &0x5,1+EXC_CMDREG(%a6)  # is op monadic or dyadic?
 913        beq.b           funfl_extract           # monadic
 914
 915# now, what's left that's not dyadic is fsincos. we can distinguish it
 916# from all dyadics by the '0110xxx pattern
 917        btst            &0x4,1+EXC_CMDREG(%a6)  # is op an fsincos?
 918        bne.b           funfl_extract           # yes
 919
 920        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
 921        bsr.l           load_fpn2               # load dst into FP_DST
 922
 923        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
 924        bsr.l           set_tag_x               # tag the operand type
 925        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
 926        bne.b           funfl_op2_done          # no
 927        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
 928funfl_op2_done:
 929        mov.b           %d0,DTAG(%a6)           # save dst optype tag
 930
 931funfl_extract:
 932
 933#$#     mov.l           FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
 934#$#     mov.l           FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
 935#$#     mov.l           FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
 936#$#     mov.l           FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6)
 937#$#     mov.l           FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6)
 938#$#     mov.l           FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6)
 939
 940        clr.l           %d0
 941        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec/mode
 942
 943        mov.b           1+EXC_CMDREG(%a6),%d1
 944        andi.w          &0x007f,%d1             # extract extension
 945
 946        andi.l          &0x00ff01ff,USER_FPSR(%a6)
 947
 948        fmov.l          &0x0,%fpcr              # zero current control regs
 949        fmov.l          &0x0,%fpsr
 950
 951        lea             FP_SRC(%a6),%a0
 952        lea             FP_DST(%a6),%a1
 953
 954# maybe we can make these entry points ONLY the OVFL entry points of each routine.
 955        mov.l           (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
 956        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
 957
 958        bfextu          EXC_CMDREG(%a6){&6:&3},%d0
 959        bsr.l           store_fpreg
 960
 961# The `060 FPU multiplier hardware is such that if the result of a
 962# multiply operation is the smallest possible normalized number
 963# (0x00000000_80000000_00000000), then the machine will take an
 964# underflow exception. Since this is incorrect, we need to check
 965# if our emulation, after re-doing the operation, decided that
 966# no underflow was called for. We do these checks only in
 967# funfl_{unfl,inex}_on() because w/ both exceptions disabled, this
 968# special case will simply exit gracefully with the correct result.
 969
 970# the exceptional possibilities we have left ourselves with are ONLY overflow
 971# and inexact. and, the inexact is such that overflow occurred and was disabled
 972# but inexact was enabled.
 973        btst            &unfl_bit,FPCR_ENABLE(%a6)
 974        bne.b           funfl_unfl_on
 975
 976funfl_chkinex:
 977        btst            &inex2_bit,FPCR_ENABLE(%a6)
 978        bne.b           funfl_inex_on
 979
 980funfl_exit:
 981        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
 982        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
 983        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
 984
 985        unlk            %a6
 986#$#     add.l           &24,%sp
 987        bra.l           _fpsp_done
 988
 989# overflow is enabled AND overflow, of course, occurred. so, we have the EXOP
 990# in fp1 (don't forget to save fp0). what to do now?
 991# well, we simply have to get to go to _real_unfl()!
 992funfl_unfl_on:
 993
 994# The `060 FPU multiplier hardware is such that if the result of a
 995# multiply operation is the smallest possible normalized number
 996# (0x00000000_80000000_00000000), then the machine will take an
 997# underflow exception. Since this is incorrect, we check here to see
 998# if our emulation, after re-doing the operation, decided that
 999# no underflow was called for.
1000        btst            &unfl_bit,FPSR_EXCEPT(%a6)
1001        beq.w           funfl_chkinex
1002
1003funfl_unfl_on2:
1004        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP (fp1) to stack
1005
1006        mov.w           &0xe003,2+FP_SRC(%a6)   # save exc status
1007
1008        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
1009        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1010        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1011
1012        frestore        FP_SRC(%a6)             # do this after fmovm,other f<op>s!
1013
1014        unlk            %a6
1015
1016        bra.l           _real_unfl
1017
1018# underflow occurred but is disabled. meanwhile, inexact is enabled. Therefore,
1019# we must jump to real_inex().
1020funfl_inex_on:
1021
1022# The `060 FPU multiplier hardware is such that if the result of a
1023# multiply operation is the smallest possible normalized number
1024# (0x00000000_80000000_00000000), then the machine will take an
1025# underflow exception.
1026# But, whether bogus or not, if inexact is enabled AND it occurred,
1027# then we have to branch to real_inex.
1028
1029        btst            &inex2_bit,FPSR_EXCEPT(%a6)
1030        beq.w           funfl_exit
1031
1032funfl_inex_on2:
1033
1034        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP to stack
1035
1036        mov.b           &0xc4,1+EXC_VOFF(%a6)   # vector offset = 0xc4
1037        mov.w           &0xe001,2+FP_SRC(%a6)   # save exc status
1038
1039        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
1040        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1041        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1042
1043        frestore        FP_SRC(%a6)             # do this after fmovm,other f<op>s!
1044
1045        unlk            %a6
1046
1047        bra.l           _real_inex
1048
1049#######################################################################
1050funfl_out:
1051
1052
1053#$#     mov.l           FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
1054#$#     mov.l           FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
1055#$#     mov.l           FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
1056
1057# the src operand is definitely a NORM(!), so tag it as such
1058        mov.b           &NORM,STAG(%a6)         # set src optype tag
1059
1060        clr.l           %d0
1061        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec/mode
1062
1063        and.l           &0xffff00ff,USER_FPSR(%a6) # zero all but accured field
1064
1065        fmov.l          &0x0,%fpcr              # zero current control regs
1066        fmov.l          &0x0,%fpsr
1067
1068        lea             FP_SRC(%a6),%a0         # pass ptr to src operand
1069
1070        bsr.l           fout
1071
1072        btst            &unfl_bit,FPCR_ENABLE(%a6)
1073        bne.w           funfl_unfl_on2
1074
1075        btst            &inex2_bit,FPCR_ENABLE(%a6)
1076        bne.w           funfl_inex_on2
1077
1078        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
1079        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1080        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1081
1082        unlk            %a6
1083#$#     add.l           &24,%sp
1084
1085        btst            &0x7,(%sp)              # is trace on?
1086        beq.l           _fpsp_done              # no
1087
1088        fmov.l          %fpiar,0x8(%sp)         # "Current PC" is in FPIAR
1089        mov.w           &0x2024,0x6(%sp)        # stk fmt = 0x2; voff = 0x024
1090        bra.l           _real_trace
1091
1092#########################################################################
1093# XDEF **************************************************************** #
1094#       _fpsp_unsupp(): 060FPSP entry point for FP "Unimplemented       #
1095#                       Data Type" exception.                           #
1096#                                                                       #
1097#       This handler should be the first code executed upon taking the  #
1098#       FP Unimplemented Data Type exception in an operating system.    #
1099#                                                                       #
1100# XREF **************************************************************** #
1101#       _imem_read_{word,long}() - read instruction word/longword       #
1102#       fix_skewed_ops() - adjust src operand in fsave frame            #
1103#       set_tag_x() - determine optype of src/dst operands              #
1104#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
1105#       unnorm_fix() - change UNNORM operands to NORM or ZERO           #
1106#       load_fpn2() - load dst operand from FP regfile                  #
1107#       load_fpn1() - load src operand from FP regfile                  #
1108#       fout() - emulate an opclass 3 instruction                       #
1109#       tbl_unsupp - add of table of emulation routines for opclass 0,2 #
1110#       _real_inex() - "callout" to operating system inexact handler    #
1111#       _fpsp_done() - "callout" for exit; work all done                #
1112#       _real_trace() - "callout" for Trace enabled exception           #
1113#       funimp_skew() - adjust fsave src ops to "incorrect" value       #
1114#       _real_snan() - "callout" for SNAN exception                     #
1115#       _real_operr() - "callout" for OPERR exception                   #
1116#       _real_ovfl() - "callout" for OVFL exception                     #
1117#       _real_unfl() - "callout" for UNFL exception                     #
1118#       get_packed() - fetch packed operand from memory                 #
1119#                                                                       #
1120# INPUT *************************************************************** #
1121#       - The system stack contains the "Unimp Data Type" stk frame     #
1122#       - The fsave frame contains the ssrc op (for UNNORM/DENORM)      #
1123#                                                                       #
1124# OUTPUT ************************************************************** #
1125#       If Inexact exception (opclass 3):                               #
1126#       - The system stack is changed to an Inexact exception stk frame #
1127#       If SNAN exception (opclass 3):                                  #
1128#       - The system stack is changed to an SNAN exception stk frame    #
1129#       If OPERR exception (opclass 3):                                 #
1130#       - The system stack is changed to an OPERR exception stk frame   #
1131#       If OVFL exception (opclass 3):                                  #
1132#       - The system stack is changed to an OVFL exception stk frame    #
1133#       If UNFL exception (opclass 3):                                  #
1134#       - The system stack is changed to an UNFL exception stack frame  #
1135#       If Trace exception enabled:                                     #
1136#       - The system stack is changed to a Trace exception stack frame  #
1137#       Else: (normal case)                                             #
1138#       - Correct result has been stored as appropriate                 #
1139#                                                                       #
1140# ALGORITHM *********************************************************** #
1141#       Two main instruction types can enter here: (1) DENORM or UNNORM #
1142# unimplemented data types. These can be either opclass 0,2 or 3        #
1143# instructions, and (2) PACKED unimplemented data format instructions   #
1144# also of opclasses 0,2, or 3.                                          #
1145#       For UNNORM/DENORM opclass 0 and 2, the handler fetches the src  #
1146# operand from the fsave state frame and the dst operand (if dyadic)    #
1147# from the FP register file. The instruction is then emulated by        #
1148# choosing an emulation routine from a table of routines indexed by     #
1149# instruction type. Once the instruction has been emulated and result   #
1150# saved, then we check to see if any enabled exceptions resulted from   #
1151# instruction emulation. If none, then we exit through the "callout"    #
1152# _fpsp_done(). If there is an enabled FP exception, then we insert     #
1153# this exception into the FPU in the fsave state frame and then exit    #
1154# through _fpsp_done().                                                 #
1155#       PACKED opclass 0 and 2 is similar in how the instruction is     #
1156# emulated and exceptions handled. The differences occur in how the     #
1157# handler loads the packed op (by calling get_packed() routine) and     #
1158# by the fact that a Trace exception could be pending for PACKED ops.   #
1159# If a Trace exception is pending, then the current exception stack     #
1160# frame is changed to a Trace exception stack frame and an exit is      #
1161# made through _real_trace().                                           #
1162#       For UNNORM/DENORM opclass 3, the actual move out to memory is   #
1163# performed by calling the routine fout(). If no exception should occur #
1164# as the result of emulation, then an exit either occurs through        #
1165# _fpsp_done() or through _real_trace() if a Trace exception is pending #
1166# (a Trace stack frame must be created here, too). If an FP exception   #
1167# should occur, then we must create an exception stack frame of that    #
1168# type and jump to either _real_snan(), _real_operr(), _real_inex(),    #
1169# _real_unfl(), or _real_ovfl() as appropriate. PACKED opclass 3        #
1170# emulation is performed in a similar manner.                           #
1171#                                                                       #
1172#########################################################################
1173
1174#
1175# (1) DENORM and UNNORM (unimplemented) data types:
1176#
1177#                               post-instruction
1178#                               *****************
1179#                               *      EA       *
1180#        pre-instruction        *               *
1181#       *****************       *****************
1182#       * 0x0 *  0x0dc  *       * 0x3 *  0x0dc  *
1183#       *****************       *****************
1184#       *     Next      *       *     Next      *
1185#       *      PC       *       *      PC       *
1186#       *****************       *****************
1187#       *      SR       *       *      SR       *
1188#       *****************       *****************
1189#
1190# (2) PACKED format (unsupported) opclasses two and three:
1191#       *****************
1192#       *      EA       *
1193#       *               *
1194#       *****************
1195#       * 0x2 *  0x0dc  *
1196#       *****************
1197#       *     Next      *
1198#       *      PC       *
1199#       *****************
1200#       *      SR       *
1201#       *****************
1202#
1203        global          _fpsp_unsupp
1204_fpsp_unsupp:
1205
1206        link.w          %a6,&-LOCAL_SIZE        # init stack frame
1207
1208        fsave           FP_SRC(%a6)             # save fp state
1209
1210        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
1211        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
1212        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
1213
1214        btst            &0x5,EXC_SR(%a6)        # user or supervisor mode?
1215        bne.b           fu_s
1216fu_u:
1217        mov.l           %usp,%a0                # fetch user stack pointer
1218        mov.l           %a0,EXC_A7(%a6)         # save on stack
1219        bra.b           fu_cont
1220# if the exception is an opclass zero or two unimplemented data type
1221# exception, then the a7' calculated here is wrong since it doesn't
1222# stack an ea. however, we don't need an a7' for this case anyways.
1223fu_s:
1224        lea             0x4+EXC_EA(%a6),%a0     # load old a7'
1225        mov.l           %a0,EXC_A7(%a6)         # save on stack
1226
1227fu_cont:
1228
1229# the FPIAR holds the "current PC" of the faulting instruction
1230# the FPIAR should be set correctly for ALL exceptions passing through
1231# this point.
1232        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
1233        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
1234        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
1235        bsr.l           _imem_read_long         # fetch the instruction words
1236        mov.l           %d0,EXC_OPWORD(%a6)     # store OPWORD and EXTWORD
1237
1238############################
1239
1240        clr.b           SPCOND_FLG(%a6)         # clear special condition flag
1241
1242# Separate opclass three (fpn-to-mem) ops since they have a different
1243# stack frame and protocol.
1244        btst            &0x5,EXC_CMDREG(%a6)    # is it an fmove out?
1245        bne.w           fu_out                  # yes
1246
1247# Separate packed opclass two instructions.
1248        bfextu          EXC_CMDREG(%a6){&0:&6},%d0
1249        cmpi.b          %d0,&0x13
1250        beq.w           fu_in_pack
1251
1252
1253# I'm not sure at this point what FPSR bits are valid for this instruction.
1254# so, since the emulation routines re-create them anyways, zero exception field
1255        andi.l          &0x00ff00ff,USER_FPSR(%a6) # zero exception field
1256
1257        fmov.l          &0x0,%fpcr              # zero current control regs
1258        fmov.l          &0x0,%fpsr
1259
1260# Opclass two w/ memory-to-fpn operation will have an incorrect extended
1261# precision format if the src format was single or double and the
1262# source data type was an INF, NAN, DENORM, or UNNORM
1263        lea             FP_SRC(%a6),%a0         # pass ptr to input
1264        bsr.l           fix_skewed_ops
1265
1266# we don't know whether the src operand or the dst operand (or both) is the
1267# UNNORM or DENORM. call the function that tags the operand type. if the
1268# input is an UNNORM, then convert it to a NORM, DENORM, or ZERO.
1269        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
1270        bsr.l           set_tag_x               # tag the operand type
1271        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
1272        bne.b           fu_op2                  # no
1273        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
1274
1275fu_op2:
1276        mov.b           %d0,STAG(%a6)           # save src optype tag
1277
1278        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1279
1280# bit five of the fp extension word separates the monadic and dyadic operations
1281# at this point
1282        btst            &0x5,1+EXC_CMDREG(%a6)  # is operation monadic or dyadic?
1283        beq.b           fu_extract              # monadic
1284        cmpi.b          1+EXC_CMDREG(%a6),&0x3a # is operation an ftst?
1285        beq.b           fu_extract              # yes, so it's monadic, too
1286
1287        bsr.l           load_fpn2               # load dst into FP_DST
1288
1289        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
1290        bsr.l           set_tag_x               # tag the operand type
1291        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
1292        bne.b           fu_op2_done             # no
1293        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
1294fu_op2_done:
1295        mov.b           %d0,DTAG(%a6)           # save dst optype tag
1296
1297fu_extract:
1298        clr.l           %d0
1299        mov.b           FPCR_MODE(%a6),%d0      # fetch rnd mode/prec
1300
1301        bfextu          1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension
1302
1303        lea             FP_SRC(%a6),%a0
1304        lea             FP_DST(%a6),%a1
1305
1306        mov.l           (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr
1307        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
1308
1309#
1310# Exceptions in order of precedence:
1311#       BSUN    : none
1312#       SNAN    : all dyadic ops
1313#       OPERR   : fsqrt(-NORM)
1314#       OVFL    : all except ftst,fcmp
1315#       UNFL    : all except ftst,fcmp
1316#       DZ      : fdiv
1317#       INEX2   : all except ftst,fcmp
1318#       INEX1   : none (packed doesn't go through here)
1319#
1320
1321# we determine the highest priority exception(if any) set by the
1322# emulation routine that has also been enabled by the user.
1323        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions set
1324        bne.b           fu_in_ena               # some are enabled
1325
1326fu_in_cont:
1327# fcmp and ftst do not store any result.
1328        mov.b           1+EXC_CMDREG(%a6),%d0   # fetch extension
1329        andi.b          &0x38,%d0               # extract bits 3-5
1330        cmpi.b          %d0,&0x38               # is instr fcmp or ftst?
1331        beq.b           fu_in_exit              # yes
1332
1333        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1334        bsr.l           store_fpreg             # store the result
1335
1336fu_in_exit:
1337
1338        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1339        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1340        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1341
1342        unlk            %a6
1343
1344        bra.l           _fpsp_done
1345
1346fu_in_ena:
1347        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enabled
1348        bfffo           %d0{&24:&8},%d0         # find highest priority exception
1349        bne.b           fu_in_exc               # there is at least one set
1350
1351#
1352# No exceptions occurred that were also enabled. Now:
1353#
1354#       if (OVFL && ovfl_disabled && inexact_enabled) {
1355#           branch to _real_inex() (even if the result was exact!);
1356#       } else {
1357#           save the result in the proper fp reg (unless the op is fcmp or ftst);
1358#           return;
1359#       }
1360#
1361        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
1362        beq.b           fu_in_cont              # no
1363
1364fu_in_ovflchk:
1365        btst            &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
1366        beq.b           fu_in_cont              # no
1367        bra.w           fu_in_exc_ovfl          # go insert overflow frame
1368
1369#
1370# An exception occurred and that exception was enabled:
1371#
1372#       shift enabled exception field into lo byte of d0;
1373#       if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) ||
1374#           ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) {
1375#               /*
1376#                * this is the case where we must call _real_inex() now or else
1377#                * there will be no other way to pass it the exceptional operand
1378#                */
1379#               call _real_inex();
1380#       } else {
1381#               restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU;
1382#       }
1383#
1384fu_in_exc:
1385        subi.l          &24,%d0                 # fix offset to be 0-8
1386        cmpi.b          %d0,&0x6                # is exception INEX? (6)
1387        bne.b           fu_in_exc_exit          # no
1388
1389# the enabled exception was inexact
1390        btst            &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur?
1391        bne.w           fu_in_exc_unfl          # yes
1392        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur?
1393        bne.w           fu_in_exc_ovfl          # yes
1394
1395# here, we insert the correct fsave status value into the fsave frame for the
1396# corresponding exception. the operand in the fsave frame should be the original
1397# src operand.
1398fu_in_exc_exit:
1399        mov.l           %d0,-(%sp)              # save d0
1400        bsr.l           funimp_skew             # skew sgl or dbl inputs
1401        mov.l           (%sp)+,%d0              # restore d0
1402
1403        mov.w           (tbl_except.b,%pc,%d0.w*2),2+FP_SRC(%a6) # create exc status
1404
1405        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1406        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1407        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1408
1409        frestore        FP_SRC(%a6)             # restore src op
1410
1411        unlk            %a6
1412
1413        bra.l           _fpsp_done
1414
1415tbl_except:
1416        short           0xe000,0xe006,0xe004,0xe005
1417        short           0xe003,0xe002,0xe001,0xe001
1418
1419fu_in_exc_unfl:
1420        mov.w           &0x4,%d0
1421        bra.b           fu_in_exc_exit
1422fu_in_exc_ovfl:
1423        mov.w           &0x03,%d0
1424        bra.b           fu_in_exc_exit
1425
1426# If the input operand to this operation was opclass two and a single
1427# or double precision denorm, inf, or nan, the operand needs to be
1428# "corrected" in order to have the proper equivalent extended precision
1429# number.
1430        global          fix_skewed_ops
1431fix_skewed_ops:
1432        bfextu          EXC_CMDREG(%a6){&0:&6},%d0 # extract opclass,src fmt
1433        cmpi.b          %d0,&0x11               # is class = 2 & fmt = sgl?
1434        beq.b           fso_sgl                 # yes
1435        cmpi.b          %d0,&0x15               # is class = 2 & fmt = dbl?
1436        beq.b           fso_dbl                 # yes
1437        rts                                     # no
1438
1439fso_sgl:
1440        mov.w           LOCAL_EX(%a0),%d0       # fetch src exponent
1441        andi.w          &0x7fff,%d0             # strip sign
1442        cmpi.w          %d0,&0x3f80             # is |exp| == $3f80?
1443        beq.b           fso_sgl_dnrm_zero       # yes
1444        cmpi.w          %d0,&0x407f             # no; is |exp| == $407f?
1445        beq.b           fso_infnan              # yes
1446        rts                                     # no
1447
1448fso_sgl_dnrm_zero:
1449        andi.l          &0x7fffffff,LOCAL_HI(%a0) # clear j-bit
1450        beq.b           fso_zero                # it's a skewed zero
1451fso_sgl_dnrm:
1452# here, we count on norm not to alter a0...
1453        bsr.l           norm                    # normalize mantissa
1454        neg.w           %d0                     # -shft amt
1455        addi.w          &0x3f81,%d0             # adjust new exponent
1456        andi.w          &0x8000,LOCAL_EX(%a0)   # clear old exponent
1457        or.w            %d0,LOCAL_EX(%a0)       # insert new exponent
1458        rts
1459
1460fso_zero:
1461        andi.w          &0x8000,LOCAL_EX(%a0)   # clear bogus exponent
1462        rts
1463
1464fso_infnan:
1465        andi.b          &0x7f,LOCAL_HI(%a0)     # clear j-bit
1466        ori.w           &0x7fff,LOCAL_EX(%a0)   # make exponent = $7fff
1467        rts
1468
1469fso_dbl:
1470        mov.w           LOCAL_EX(%a0),%d0       # fetch src exponent
1471        andi.w          &0x7fff,%d0             # strip sign
1472        cmpi.w          %d0,&0x3c00             # is |exp| == $3c00?
1473        beq.b           fso_dbl_dnrm_zero       # yes
1474        cmpi.w          %d0,&0x43ff             # no; is |exp| == $43ff?
1475        beq.b           fso_infnan              # yes
1476        rts                                     # no
1477
1478fso_dbl_dnrm_zero:
1479        andi.l          &0x7fffffff,LOCAL_HI(%a0) # clear j-bit
1480        bne.b           fso_dbl_dnrm            # it's a skewed denorm
1481        tst.l           LOCAL_LO(%a0)           # is it a zero?
1482        beq.b           fso_zero                # yes
1483fso_dbl_dnrm:
1484# here, we count on norm not to alter a0...
1485        bsr.l           norm                    # normalize mantissa
1486        neg.w           %d0                     # -shft amt
1487        addi.w          &0x3c01,%d0             # adjust new exponent
1488        andi.w          &0x8000,LOCAL_EX(%a0)   # clear old exponent
1489        or.w            %d0,LOCAL_EX(%a0)       # insert new exponent
1490        rts
1491
1492#################################################################
1493
1494# fmove out took an unimplemented data type exception.
1495# the src operand is in FP_SRC. Call _fout() to write out the result and
1496# to determine which exceptions, if any, to take.
1497fu_out:
1498
1499# Separate packed move outs from the UNNORM and DENORM move outs.
1500        bfextu          EXC_CMDREG(%a6){&3:&3},%d0
1501        cmpi.b          %d0,&0x3
1502        beq.w           fu_out_pack
1503        cmpi.b          %d0,&0x7
1504        beq.w           fu_out_pack
1505
1506
1507# I'm not sure at this point what FPSR bits are valid for this instruction.
1508# so, since the emulation routines re-create them anyways, zero exception field.
1509# fmove out doesn't affect ccodes.
1510        and.l           &0xffff00ff,USER_FPSR(%a6) # zero exception field
1511
1512        fmov.l          &0x0,%fpcr              # zero current control regs
1513        fmov.l          &0x0,%fpsr
1514
1515# the src can ONLY be a DENORM or an UNNORM! so, don't make any big subroutine
1516# call here. just figure out what it is...
1517        mov.w           FP_SRC_EX(%a6),%d0      # get exponent
1518        andi.w          &0x7fff,%d0             # strip sign
1519        beq.b           fu_out_denorm           # it's a DENORM
1520
1521        lea             FP_SRC(%a6),%a0
1522        bsr.l           unnorm_fix              # yes; fix it
1523
1524        mov.b           %d0,STAG(%a6)
1525
1526        bra.b           fu_out_cont
1527fu_out_denorm:
1528        mov.b           &DENORM,STAG(%a6)
1529fu_out_cont:
1530
1531        clr.l           %d0
1532        mov.b           FPCR_MODE(%a6),%d0      # fetch rnd mode/prec
1533
1534        lea             FP_SRC(%a6),%a0         # pass ptr to src operand
1535
1536        mov.l           (%a6),EXC_A6(%a6)       # in case a6 changes
1537        bsr.l           fout                    # call fmove out routine
1538
1539# Exceptions in order of precedence:
1540#       BSUN    : none
1541#       SNAN    : none
1542#       OPERR   : fmove.{b,w,l} out of large UNNORM
1543#       OVFL    : fmove.{s,d}
1544#       UNFL    : fmove.{s,d,x}
1545#       DZ      : none
1546#       INEX2   : all
1547#       INEX1   : none (packed doesn't travel through here)
1548
1549# determine the highest priority exception(if any) set by the
1550# emulation routine that has also been enabled by the user.
1551        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions enabled
1552        bne.w           fu_out_ena              # some are enabled
1553
1554fu_out_done:
1555
1556        mov.l           EXC_A6(%a6),(%a6)       # in case a6 changed
1557
1558# on extended precision opclass three instructions using pre-decrement or
1559# post-increment addressing mode, the address register is not updated. is the
1560# address register was the stack pointer used from user mode, then let's update
1561# it here. if it was used from supervisor mode, then we have to handle this
1562# as a special case.
1563        btst            &0x5,EXC_SR(%a6)
1564        bne.b           fu_out_done_s
1565
1566        mov.l           EXC_A7(%a6),%a0         # restore a7
1567        mov.l           %a0,%usp
1568
1569fu_out_done_cont:
1570        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1571        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1572        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1573
1574        unlk            %a6
1575
1576        btst            &0x7,(%sp)              # is trace on?
1577        bne.b           fu_out_trace            # yes
1578
1579        bra.l           _fpsp_done
1580
1581# is the ea mode pre-decrement of the stack pointer from supervisor mode?
1582# ("fmov.x fpm,-(a7)") if so,
1583fu_out_done_s:
1584        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
1585        bne.b           fu_out_done_cont
1586
1587# the extended precision result is still in fp0. but, we need to save it
1588# somewhere on the stack until we can copy it to its final resting place.
1589# here, we're counting on the top of the stack to be the old place-holders
1590# for fp0/fp1 which have already been restored. that way, we can write
1591# over those destinations with the shifted stack frame.
1592        fmovm.x         &0x80,FP_SRC(%a6)       # put answer on stack
1593
1594        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1595        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1596        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1597
1598        mov.l           (%a6),%a6               # restore frame pointer
1599
1600        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
1601        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
1602
1603# now, copy the result to the proper place on the stack
1604        mov.l           LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
1605        mov.l           LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
1606        mov.l           LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
1607
1608        add.l           &LOCAL_SIZE-0x8,%sp
1609
1610        btst            &0x7,(%sp)
1611        bne.b           fu_out_trace
1612
1613        bra.l           _fpsp_done
1614
1615fu_out_ena:
1616        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enabled
1617        bfffo           %d0{&24:&8},%d0         # find highest priority exception
1618        bne.b           fu_out_exc              # there is at least one set
1619
1620# no exceptions were set.
1621# if a disabled overflow occurred and inexact was enabled but the result
1622# was exact, then a branch to _real_inex() is made.
1623        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
1624        beq.w           fu_out_done             # no
1625
1626fu_out_ovflchk:
1627        btst            &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
1628        beq.w           fu_out_done             # no
1629        bra.w           fu_inex                 # yes
1630
1631#
1632# The fp move out that took the "Unimplemented Data Type" exception was
1633# being traced. Since the stack frames are similar, get the "current" PC
1634# from FPIAR and put it in the trace stack frame then jump to _real_trace().
1635#
1636#                 UNSUPP FRAME             TRACE FRAME
1637#               *****************       *****************
1638#               *      EA       *       *    Current    *
1639#               *               *       *      PC       *
1640#               *****************       *****************
1641#               * 0x3 *  0x0dc  *       * 0x2 *  0x024  *
1642#               *****************       *****************
1643#               *     Next      *       *     Next      *
1644#               *      PC       *       *      PC       *
1645#               *****************       *****************
1646#               *      SR       *       *      SR       *
1647#               *****************       *****************
1648#
1649fu_out_trace:
1650        mov.w           &0x2024,0x6(%sp)
1651        fmov.l          %fpiar,0x8(%sp)
1652        bra.l           _real_trace
1653
1654# an exception occurred and that exception was enabled.
1655fu_out_exc:
1656        subi.l          &24,%d0                 # fix offset to be 0-8
1657
1658# we don't mess with the existing fsave frame. just re-insert it and
1659# jump to the "_real_{}()" handler...
1660        mov.w           (tbl_fu_out.b,%pc,%d0.w*2),%d0
1661        jmp             (tbl_fu_out.b,%pc,%d0.w*1)
1662
1663        swbeg           &0x8
1664tbl_fu_out:
1665        short           tbl_fu_out      - tbl_fu_out    # BSUN can't happen
1666        short           tbl_fu_out      - tbl_fu_out    # SNAN can't happen
1667        short           fu_operr        - tbl_fu_out    # OPERR
1668        short           fu_ovfl         - tbl_fu_out    # OVFL
1669        short           fu_unfl         - tbl_fu_out    # UNFL
1670        short           tbl_fu_out      - tbl_fu_out    # DZ can't happen
1671        short           fu_inex         - tbl_fu_out    # INEX2
1672        short           tbl_fu_out      - tbl_fu_out    # INEX1 won't make it here
1673
1674# for snan,operr,ovfl,unfl, src op is still in FP_SRC so just
1675# frestore it.
1676fu_snan:
1677        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1678        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1679        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1680
1681        mov.w           &0x30d8,EXC_VOFF(%a6)   # vector offset = 0xd8
1682        mov.w           &0xe006,2+FP_SRC(%a6)
1683
1684        frestore        FP_SRC(%a6)
1685
1686        unlk            %a6
1687
1688
1689        bra.l           _real_snan
1690
1691fu_operr:
1692        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1693        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1694        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1695
1696        mov.w           &0x30d0,EXC_VOFF(%a6)   # vector offset = 0xd0
1697        mov.w           &0xe004,2+FP_SRC(%a6)
1698
1699        frestore        FP_SRC(%a6)
1700
1701        unlk            %a6
1702
1703
1704        bra.l           _real_operr
1705
1706fu_ovfl:
1707        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP to the stack
1708
1709        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1710        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1711        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1712
1713        mov.w           &0x30d4,EXC_VOFF(%a6)   # vector offset = 0xd4
1714        mov.w           &0xe005,2+FP_SRC(%a6)
1715
1716        frestore        FP_SRC(%a6)             # restore EXOP
1717
1718        unlk            %a6
1719
1720        bra.l           _real_ovfl
1721
1722# underflow can happen for extended precision. extended precision opclass
1723# three instruction exceptions don't update the stack pointer. so, if the
1724# exception occurred from user mode, then simply update a7 and exit normally.
1725# if the exception occurred from supervisor mode, check if
1726fu_unfl:
1727        mov.l           EXC_A6(%a6),(%a6)       # restore a6
1728
1729        btst            &0x5,EXC_SR(%a6)
1730        bne.w           fu_unfl_s
1731
1732        mov.l           EXC_A7(%a6),%a0         # restore a7 whether we need
1733        mov.l           %a0,%usp                # to or not...
1734
1735fu_unfl_cont:
1736        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP to the stack
1737
1738        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1739        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1740        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1741
1742        mov.w           &0x30cc,EXC_VOFF(%a6)   # vector offset = 0xcc
1743        mov.w           &0xe003,2+FP_SRC(%a6)
1744
1745        frestore        FP_SRC(%a6)             # restore EXOP
1746
1747        unlk            %a6
1748
1749        bra.l           _real_unfl
1750
1751fu_unfl_s:
1752        cmpi.b          SPCOND_FLG(%a6),&mda7_flg # was the <ea> mode -(sp)?
1753        bne.b           fu_unfl_cont
1754
1755# the extended precision result is still in fp0. but, we need to save it
1756# somewhere on the stack until we can copy it to its final resting place
1757# (where the exc frame is currently). make sure it's not at the top of the
1758# frame or it will get overwritten when the exc stack frame is shifted "down".
1759        fmovm.x         &0x80,FP_SRC(%a6)       # put answer on stack
1760        fmovm.x         &0x40,FP_DST(%a6)       # put EXOP on stack
1761
1762        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1763        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1764        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1765
1766        mov.w           &0x30cc,EXC_VOFF(%a6)   # vector offset = 0xcc
1767        mov.w           &0xe003,2+FP_DST(%a6)
1768
1769        frestore        FP_DST(%a6)             # restore EXOP
1770
1771        mov.l           (%a6),%a6               # restore frame pointer
1772
1773        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
1774        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
1775        mov.l           LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
1776
1777# now, copy the result to the proper place on the stack
1778        mov.l           LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
1779        mov.l           LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
1780        mov.l           LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
1781
1782        add.l           &LOCAL_SIZE-0x8,%sp
1783
1784        bra.l           _real_unfl
1785
1786# fmove in and out enter here.
1787fu_inex:
1788        fmovm.x         &0x40,FP_SRC(%a6)       # save EXOP to the stack
1789
1790        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1791        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1792        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1793
1794        mov.w           &0x30c4,EXC_VOFF(%a6)   # vector offset = 0xc4
1795        mov.w           &0xe001,2+FP_SRC(%a6)
1796
1797        frestore        FP_SRC(%a6)             # restore EXOP
1798
1799        unlk            %a6
1800
1801
1802        bra.l           _real_inex
1803
1804#########################################################################
1805#########################################################################
1806fu_in_pack:
1807
1808
1809# I'm not sure at this point what FPSR bits are valid for this instruction.
1810# so, since the emulation routines re-create them anyways, zero exception field
1811        andi.l          &0x0ff00ff,USER_FPSR(%a6) # zero exception field
1812
1813        fmov.l          &0x0,%fpcr              # zero current control regs
1814        fmov.l          &0x0,%fpsr
1815
1816        bsr.l           get_packed              # fetch packed src operand
1817
1818        lea             FP_SRC(%a6),%a0         # pass ptr to src
1819        bsr.l           set_tag_x               # set src optype tag
1820
1821        mov.b           %d0,STAG(%a6)           # save src optype tag
1822
1823        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1824
1825# bit five of the fp extension word separates the monadic and dyadic operations
1826# at this point
1827        btst            &0x5,1+EXC_CMDREG(%a6)  # is operation monadic or dyadic?
1828        beq.b           fu_extract_p            # monadic
1829        cmpi.b          1+EXC_CMDREG(%a6),&0x3a # is operation an ftst?
1830        beq.b           fu_extract_p            # yes, so it's monadic, too
1831
1832        bsr.l           load_fpn2               # load dst into FP_DST
1833
1834        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
1835        bsr.l           set_tag_x               # tag the operand type
1836        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
1837        bne.b           fu_op2_done_p           # no
1838        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
1839fu_op2_done_p:
1840        mov.b           %d0,DTAG(%a6)           # save dst optype tag
1841
1842fu_extract_p:
1843        clr.l           %d0
1844        mov.b           FPCR_MODE(%a6),%d0      # fetch rnd mode/prec
1845
1846        bfextu          1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension
1847
1848        lea             FP_SRC(%a6),%a0
1849        lea             FP_DST(%a6),%a1
1850
1851        mov.l           (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr
1852        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
1853
1854#
1855# Exceptions in order of precedence:
1856#       BSUN    : none
1857#       SNAN    : all dyadic ops
1858#       OPERR   : fsqrt(-NORM)
1859#       OVFL    : all except ftst,fcmp
1860#       UNFL    : all except ftst,fcmp
1861#       DZ      : fdiv
1862#       INEX2   : all except ftst,fcmp
1863#       INEX1   : all
1864#
1865
1866# we determine the highest priority exception(if any) set by the
1867# emulation routine that has also been enabled by the user.
1868        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions enabled
1869        bne.w           fu_in_ena_p             # some are enabled
1870
1871fu_in_cont_p:
1872# fcmp and ftst do not store any result.
1873        mov.b           1+EXC_CMDREG(%a6),%d0   # fetch extension
1874        andi.b          &0x38,%d0               # extract bits 3-5
1875        cmpi.b          %d0,&0x38               # is instr fcmp or ftst?
1876        beq.b           fu_in_exit_p            # yes
1877
1878        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1879        bsr.l           store_fpreg             # store the result
1880
1881fu_in_exit_p:
1882
1883        btst            &0x5,EXC_SR(%a6)        # user or supervisor?
1884        bne.w           fu_in_exit_s_p          # supervisor
1885
1886        mov.l           EXC_A7(%a6),%a0         # update user a7
1887        mov.l           %a0,%usp
1888
1889fu_in_exit_cont_p:
1890        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1891        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1892        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1893
1894        unlk            %a6                     # unravel stack frame
1895
1896        btst            &0x7,(%sp)              # is trace on?
1897        bne.w           fu_trace_p              # yes
1898
1899        bra.l           _fpsp_done              # exit to os
1900
1901# the exception occurred in supervisor mode. check to see if the
1902# addressing mode was (a7)+. if so, we'll need to shift the
1903# stack frame "up".
1904fu_in_exit_s_p:
1905        btst            &mia7_bit,SPCOND_FLG(%a6) # was ea mode (a7)+
1906        beq.b           fu_in_exit_cont_p       # no
1907
1908        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1909        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1910        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1911
1912        unlk            %a6                     # unravel stack frame
1913
1914# shift the stack frame "up". we don't really care about the <ea> field.
1915        mov.l           0x4(%sp),0x10(%sp)
1916        mov.l           0x0(%sp),0xc(%sp)
1917        add.l           &0xc,%sp
1918
1919        btst            &0x7,(%sp)              # is trace on?
1920        bne.w           fu_trace_p              # yes
1921
1922        bra.l           _fpsp_done              # exit to os
1923
1924fu_in_ena_p:
1925        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enabled & set
1926        bfffo           %d0{&24:&8},%d0         # find highest priority exception
1927        bne.b           fu_in_exc_p             # at least one was set
1928
1929#
1930# No exceptions occurred that were also enabled. Now:
1931#
1932#       if (OVFL && ovfl_disabled && inexact_enabled) {
1933#           branch to _real_inex() (even if the result was exact!);
1934#       } else {
1935#           save the result in the proper fp reg (unless the op is fcmp or ftst);
1936#           return;
1937#       }
1938#
1939        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
1940        beq.w           fu_in_cont_p            # no
1941
1942fu_in_ovflchk_p:
1943        btst            &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
1944        beq.w           fu_in_cont_p            # no
1945        bra.w           fu_in_exc_ovfl_p        # do _real_inex() now
1946
1947#
1948# An exception occurred and that exception was enabled:
1949#
1950#       shift enabled exception field into lo byte of d0;
1951#       if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) ||
1952#           ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) {
1953#               /*
1954#                * this is the case where we must call _real_inex() now or else
1955#                * there will be no other way to pass it the exceptional operand
1956#                */
1957#               call _real_inex();
1958#       } else {
1959#               restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU;
1960#       }
1961#
1962fu_in_exc_p:
1963        subi.l          &24,%d0                 # fix offset to be 0-8
1964        cmpi.b          %d0,&0x6                # is exception INEX? (6 or 7)
1965        blt.b           fu_in_exc_exit_p        # no
1966
1967# the enabled exception was inexact
1968        btst            &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur?
1969        bne.w           fu_in_exc_unfl_p        # yes
1970        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur?
1971        bne.w           fu_in_exc_ovfl_p        # yes
1972
1973# here, we insert the correct fsave status value into the fsave frame for the
1974# corresponding exception. the operand in the fsave frame should be the original
1975# src operand.
1976# as a reminder for future predicted pain and agony, we are passing in fsave the
1977# "non-skewed" operand for cases of sgl and dbl src INFs,NANs, and DENORMs.
1978# this is INCORRECT for enabled SNAN which would give to the user the skewed SNAN!!!
1979fu_in_exc_exit_p:
1980        btst            &0x5,EXC_SR(%a6)        # user or supervisor?
1981        bne.w           fu_in_exc_exit_s_p      # supervisor
1982
1983        mov.l           EXC_A7(%a6),%a0         # update user a7
1984        mov.l           %a0,%usp
1985
1986fu_in_exc_exit_cont_p:
1987        mov.w           (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6)
1988
1989        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
1990        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1991        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
1992
1993        frestore        FP_SRC(%a6)             # restore src op
1994
1995        unlk            %a6
1996
1997        btst            &0x7,(%sp)              # is trace enabled?
1998        bne.w           fu_trace_p              # yes
1999
2000        bra.l           _fpsp_done
2001
2002tbl_except_p:
2003        short           0xe000,0xe006,0xe004,0xe005
2004        short           0xe003,0xe002,0xe001,0xe001
2005
2006fu_in_exc_ovfl_p:
2007        mov.w           &0x3,%d0
2008        bra.w           fu_in_exc_exit_p
2009
2010fu_in_exc_unfl_p:
2011        mov.w           &0x4,%d0
2012        bra.w           fu_in_exc_exit_p
2013
2014fu_in_exc_exit_s_p:
2015        btst            &mia7_bit,SPCOND_FLG(%a6)
2016        beq.b           fu_in_exc_exit_cont_p
2017
2018        mov.w           (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6)
2019
2020        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2021        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2022        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2023
2024        frestore        FP_SRC(%a6)             # restore src op
2025
2026        unlk            %a6                     # unravel stack frame
2027
2028# shift stack frame "up". who cares about <ea> field.
2029        mov.l           0x4(%sp),0x10(%sp)
2030        mov.l           0x0(%sp),0xc(%sp)
2031        add.l           &0xc,%sp
2032
2033        btst            &0x7,(%sp)              # is trace on?
2034        bne.b           fu_trace_p              # yes
2035
2036        bra.l           _fpsp_done              # exit to os
2037
2038#
2039# The opclass two PACKED instruction that took an "Unimplemented Data Type"
2040# exception was being traced. Make the "current" PC the FPIAR and put it in the
2041# trace stack frame then jump to _real_trace().
2042#
2043#                 UNSUPP FRAME             TRACE FRAME
2044#               *****************       *****************
2045#               *      EA       *       *    Current    *
2046#               *               *       *      PC       *
2047#               *****************       *****************
2048#               * 0x2 * 0x0dc   *       * 0x2 *  0x024  *
2049#               *****************       *****************
2050#               *     Next      *       *     Next      *
2051#               *      PC       *       *      PC       *
2052#               *****************       *****************
2053#               *      SR       *       *      SR       *
2054#               *****************       *****************
2055fu_trace_p:
2056        mov.w           &0x2024,0x6(%sp)
2057        fmov.l          %fpiar,0x8(%sp)
2058
2059        bra.l           _real_trace
2060
2061#########################################################
2062#########################################################
2063fu_out_pack:
2064
2065
2066# I'm not sure at this point what FPSR bits are valid for this instruction.
2067# so, since the emulation routines re-create them anyways, zero exception field.
2068# fmove out doesn't affect ccodes.
2069        and.l           &0xffff00ff,USER_FPSR(%a6) # zero exception field
2070
2071        fmov.l          &0x0,%fpcr              # zero current control regs
2072        fmov.l          &0x0,%fpsr
2073
2074        bfextu          EXC_CMDREG(%a6){&6:&3},%d0
2075        bsr.l           load_fpn1
2076
2077# unlike other opclass 3, unimplemented data type exceptions, packed must be
2078# able to detect all operand types.
2079        lea             FP_SRC(%a6),%a0
2080        bsr.l           set_tag_x               # tag the operand type
2081        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
2082        bne.b           fu_op2_p                # no
2083        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
2084
2085fu_op2_p:
2086        mov.b           %d0,STAG(%a6)           # save src optype tag
2087
2088        clr.l           %d0
2089        mov.b           FPCR_MODE(%a6),%d0      # fetch rnd mode/prec
2090
2091        lea             FP_SRC(%a6),%a0         # pass ptr to src operand
2092
2093        mov.l           (%a6),EXC_A6(%a6)       # in case a6 changes
2094        bsr.l           fout                    # call fmove out routine
2095
2096# Exceptions in order of precedence:
2097#       BSUN    : no
2098#       SNAN    : yes
2099#       OPERR   : if ((k_factor > +17) || (dec. exp exceeds 3 digits))
2100#       OVFL    : no
2101#       UNFL    : no
2102#       DZ      : no
2103#       INEX2   : yes
2104#       INEX1   : no
2105
2106# determine the highest priority exception(if any) set by the
2107# emulation routine that has also been enabled by the user.
2108        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions enabled
2109        bne.w           fu_out_ena_p            # some are enabled
2110
2111fu_out_exit_p:
2112        mov.l           EXC_A6(%a6),(%a6)       # restore a6
2113
2114        btst            &0x5,EXC_SR(%a6)        # user or supervisor?
2115        bne.b           fu_out_exit_s_p         # supervisor
2116
2117        mov.l           EXC_A7(%a6),%a0         # update user a7
2118        mov.l           %a0,%usp
2119
2120fu_out_exit_cont_p:
2121        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2122        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2123        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2124
2125        unlk            %a6                     # unravel stack frame
2126
2127        btst            &0x7,(%sp)              # is trace on?
2128        bne.w           fu_trace_p              # yes
2129
2130        bra.l           _fpsp_done              # exit to os
2131
2132# the exception occurred in supervisor mode. check to see if the
2133# addressing mode was -(a7). if so, we'll need to shift the
2134# stack frame "down".
2135fu_out_exit_s_p:
2136        btst            &mda7_bit,SPCOND_FLG(%a6) # was ea mode -(a7)
2137        beq.b           fu_out_exit_cont_p      # no
2138
2139        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2140        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2141        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2142
2143        mov.l           (%a6),%a6               # restore frame pointer
2144
2145        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2146        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2147
2148# now, copy the result to the proper place on the stack
2149        mov.l           LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
2150        mov.l           LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
2151        mov.l           LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
2152
2153        add.l           &LOCAL_SIZE-0x8,%sp
2154
2155        btst            &0x7,(%sp)
2156        bne.w           fu_trace_p
2157
2158        bra.l           _fpsp_done
2159
2160fu_out_ena_p:
2161        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enabled
2162        bfffo           %d0{&24:&8},%d0         # find highest priority exception
2163        beq.w           fu_out_exit_p
2164
2165        mov.l           EXC_A6(%a6),(%a6)       # restore a6
2166
2167# an exception occurred and that exception was enabled.
2168# the only exception possible on packed move out are INEX, OPERR, and SNAN.
2169fu_out_exc_p:
2170        cmpi.b          %d0,&0x1a
2171        bgt.w           fu_inex_p2
2172        beq.w           fu_operr_p
2173
2174fu_snan_p:
2175        btst            &0x5,EXC_SR(%a6)
2176        bne.b           fu_snan_s_p
2177
2178        mov.l           EXC_A7(%a6),%a0
2179        mov.l           %a0,%usp
2180        bra.w           fu_snan
2181
2182fu_snan_s_p:
2183        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
2184        bne.w           fu_snan
2185
2186# the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
2187# the strategy is to move the exception frame "down" 12 bytes. then, we
2188# can store the default result where the exception frame was.
2189        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2190        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2191        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2192
2193        mov.w           &0x30d8,EXC_VOFF(%a6)   # vector offset = 0xd0
2194        mov.w           &0xe006,2+FP_SRC(%a6)   # set fsave status
2195
2196        frestore        FP_SRC(%a6)             # restore src operand
2197
2198        mov.l           (%a6),%a6               # restore frame pointer
2199
2200        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2201        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2202        mov.l           LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
2203
2204# now, we copy the default result to its proper location
2205        mov.l           LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
2206        mov.l           LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
2207        mov.l           LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
2208
2209        add.l           &LOCAL_SIZE-0x8,%sp
2210
2211
2212        bra.l           _real_snan
2213
2214fu_operr_p:
2215        btst            &0x5,EXC_SR(%a6)
2216        bne.w           fu_operr_p_s
2217
2218        mov.l           EXC_A7(%a6),%a0
2219        mov.l           %a0,%usp
2220        bra.w           fu_operr
2221
2222fu_operr_p_s:
2223        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
2224        bne.w           fu_operr
2225
2226# the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
2227# the strategy is to move the exception frame "down" 12 bytes. then, we
2228# can store the default result where the exception frame was.
2229        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2230        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2231        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2232
2233        mov.w           &0x30d0,EXC_VOFF(%a6)   # vector offset = 0xd0
2234        mov.w           &0xe004,2+FP_SRC(%a6)   # set fsave status
2235
2236        frestore        FP_SRC(%a6)             # restore src operand
2237
2238        mov.l           (%a6),%a6               # restore frame pointer
2239
2240        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2241        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2242        mov.l           LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
2243
2244# now, we copy the default result to its proper location
2245        mov.l           LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
2246        mov.l           LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
2247        mov.l           LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
2248
2249        add.l           &LOCAL_SIZE-0x8,%sp
2250
2251
2252        bra.l           _real_operr
2253
2254fu_inex_p2:
2255        btst            &0x5,EXC_SR(%a6)
2256        bne.w           fu_inex_s_p2
2257
2258        mov.l           EXC_A7(%a6),%a0
2259        mov.l           %a0,%usp
2260        bra.w           fu_inex
2261
2262fu_inex_s_p2:
2263        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
2264        bne.w           fu_inex
2265
2266# the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
2267# the strategy is to move the exception frame "down" 12 bytes. then, we
2268# can store the default result where the exception frame was.
2269        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0/fp1
2270        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2271        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2272
2273        mov.w           &0x30c4,EXC_VOFF(%a6)   # vector offset = 0xc4
2274        mov.w           &0xe001,2+FP_SRC(%a6)   # set fsave status
2275
2276        frestore        FP_SRC(%a6)             # restore src operand
2277
2278        mov.l           (%a6),%a6               # restore frame pointer
2279
2280        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2281        mov.l           LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2282        mov.l           LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
2283
2284# now, we copy the default result to its proper location
2285        mov.l           LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
2286        mov.l           LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
2287        mov.l           LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
2288
2289        add.l           &LOCAL_SIZE-0x8,%sp
2290
2291
2292        bra.l           _real_inex
2293
2294#########################################################################
2295
2296#
2297# if we're stuffing a source operand back into an fsave frame then we
2298# have to make sure that for single or double source operands that the
2299# format stuffed is as weird as the hardware usually makes it.
2300#
2301        global          funimp_skew
2302funimp_skew:
2303        bfextu          EXC_EXTWORD(%a6){&3:&3},%d0 # extract src specifier
2304        cmpi.b          %d0,&0x1                # was src sgl?
2305        beq.b           funimp_skew_sgl         # yes
2306        cmpi.b          %d0,&0x5                # was src dbl?
2307        beq.b           funimp_skew_dbl         # yes
2308        rts
2309
2310funimp_skew_sgl:
2311        mov.w           FP_SRC_EX(%a6),%d0      # fetch DENORM exponent
2312        andi.w          &0x7fff,%d0             # strip sign
2313        beq.b           funimp_skew_sgl_not
2314        cmpi.w          %d0,&0x3f80
2315        bgt.b           funimp_skew_sgl_not
2316        neg.w           %d0                     # make exponent negative
2317        addi.w          &0x3f81,%d0             # find amt to shift
2318        mov.l           FP_SRC_HI(%a6),%d1      # fetch DENORM hi(man)
2319        lsr.l           %d0,%d1                 # shift it
2320        bset            &31,%d1                 # set j-bit
2321        mov.l           %d1,FP_SRC_HI(%a6)      # insert new hi(man)
2322        andi.w          &0x8000,FP_SRC_EX(%a6)  # clear old exponent
2323        ori.w           &0x3f80,FP_SRC_EX(%a6)  # insert new "skewed" exponent
2324funimp_skew_sgl_not:
2325        rts
2326
2327funimp_skew_dbl:
2328        mov.w           FP_SRC_EX(%a6),%d0      # fetch DENORM exponent
2329        andi.w          &0x7fff,%d0             # strip sign
2330        beq.b           funimp_skew_dbl_not
2331        cmpi.w          %d0,&0x3c00
2332        bgt.b           funimp_skew_dbl_not
2333
2334        tst.b           FP_SRC_EX(%a6)          # make "internal format"
2335        smi.b           0x2+FP_SRC(%a6)
2336        mov.w           %d0,FP_SRC_EX(%a6)      # insert exponent with cleared sign
2337        clr.l           %d0                     # clear g,r,s
2338        lea             FP_SRC(%a6),%a0         # pass ptr to src op
2339        mov.w           &0x3c01,%d1             # pass denorm threshold
2340        bsr.l           dnrm_lp                 # denorm it
2341        mov.w           &0x3c00,%d0             # new exponent
2342        tst.b           0x2+FP_SRC(%a6)         # is sign set?
2343        beq.b           fss_dbl_denorm_done     # no
2344        bset            &15,%d0                 # set sign
2345fss_dbl_denorm_done:
2346        bset            &0x7,FP_SRC_HI(%a6)     # set j-bit
2347        mov.w           %d0,FP_SRC_EX(%a6)      # insert new exponent
2348funimp_skew_dbl_not:
2349        rts
2350
2351#########################################################################
2352        global          _mem_write2
2353_mem_write2:
2354        btst            &0x5,EXC_SR(%a6)
2355        beq.l           _dmem_write
2356        mov.l           0x0(%a0),FP_DST_EX(%a6)
2357        mov.l           0x4(%a0),FP_DST_HI(%a6)
2358        mov.l           0x8(%a0),FP_DST_LO(%a6)
2359        clr.l           %d1
2360        rts
2361
2362#########################################################################
2363# XDEF **************************************************************** #
2364#       _fpsp_effadd(): 060FPSP entry point for FP "Unimplemented       #
2365#                       effective address" exception.                   #
2366#                                                                       #
2367#       This handler should be the first code executed upon taking the  #
2368#       FP Unimplemented Effective Address exception in an operating    #
2369#       system.                                                         #
2370#                                                                       #
2371# XREF **************************************************************** #
2372#       _imem_read_long() - read instruction longword                   #
2373#       fix_skewed_ops() - adjust src operand in fsave frame            #
2374#       set_tag_x() - determine optype of src/dst operands              #
2375#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
2376#       unnorm_fix() - change UNNORM operands to NORM or ZERO           #
2377#       load_fpn2() - load dst operand from FP regfile                  #
2378#       tbl_unsupp - add of table of emulation routines for opclass 0,2 #
2379#       decbin() - convert packed data to FP binary data                #
2380#       _real_fpu_disabled() - "callout" for "FPU disabled" exception   #
2381#       _real_access() - "callout" for access error exception           #
2382#       _mem_read() - read extended immediate operand from memory       #
2383#       _fpsp_done() - "callout" for exit; work all done                #
2384#       _real_trace() - "callout" for Trace enabled exception           #
2385#       fmovm_dynamic() - emulate dynamic fmovm instruction             #
2386#       fmovm_ctrl() - emulate fmovm control instruction                #
2387#                                                                       #
2388# INPUT *************************************************************** #
2389#       - The system stack contains the "Unimplemented <ea>" stk frame  #
2390#                                                                       #
2391# OUTPUT ************************************************************** #
2392#       If access error:                                                #
2393#       - The system stack is changed to an access error stack frame    #
2394#       If FPU disabled:                                                #
2395#       - The system stack is changed to an FPU disabled stack frame    #
2396#       If Trace exception enabled:                                     #
2397#       - The system stack is changed to a Trace exception stack frame  #
2398#       Else: (normal case)                                             #
2399#       - None (correct result has been stored as appropriate)          #
2400#                                                                       #
2401# ALGORITHM *********************************************************** #
2402#       This exception handles 3 types of operations:                   #
2403# (1) FP Instructions using extended precision or packed immediate      #
2404#     addressing mode.                                                  #
2405# (2) The "fmovm.x" instruction w/ dynamic register specification.      #
2406# (3) The "fmovm.l" instruction w/ 2 or 3 control registers.            #
2407#                                                                       #
2408#       For immediate data operations, the data is read in w/ a         #
2409# _mem_read() "callout", converted to FP binary (if packed), and used   #
2410# as the source operand to the instruction specified by the instruction #
2411# word. If no FP exception should be reported ads a result of the       #
2412# emulation, then the result is stored to the destination register and  #
2413# the handler exits through _fpsp_done(). If an enabled exc has been    #
2414# signalled as a result of emulation, then an fsave state frame         #
2415# corresponding to the FP exception type must be entered into the 060   #
2416# FPU before exiting. In either the enabled or disabled cases, we       #
2417# must also check if a Trace exception is pending, in which case, we    #
2418# must create a Trace exception stack frame from the current exception  #
2419# stack frame. If no Trace is pending, we simply exit through           #
2420# _fpsp_done().                                                         #
2421#       For "fmovm.x", call the routine fmovm_dynamic() which will      #
2422# decode and emulate the instruction. No FP exceptions can be pending   #
2423# as a result of this operation emulation. A Trace exception can be     #
2424# pending, though, which means the current stack frame must be changed  #
2425# to a Trace stack frame and an exit made through _real_trace().        #
2426# For the case of "fmovm.x Dn,-(a7)", where the offending instruction   #
2427# was executed from supervisor mode, this handler must store the FP     #
2428# register file values to the system stack by itself since              #
2429# fmovm_dynamic() can't handle this. A normal exit is made through      #
2430# fpsp_done().                                                          #
2431#       For "fmovm.l", fmovm_ctrl() is used to emulate the instruction. #
2432# Again, a Trace exception may be pending and an exit made through      #
2433# _real_trace(). Else, a normal exit is made through _fpsp_done().      #
2434#                                                                       #
2435#       Before any of the above is attempted, it must be checked to     #
2436# see if the FPU is disabled. Since the "Unimp <ea>" exception is taken #
2437# before the "FPU disabled" exception, but the "FPU disabled" exception #
2438# has higher priority, we check the disabled bit in the PCR. If set,    #
2439# then we must create an 8 word "FPU disabled" exception stack frame    #
2440# from the current 4 word exception stack frame. This includes          #
2441# reproducing the effective address of the instruction to put on the    #
2442# new stack frame.                                                      #
2443#                                                                       #
2444#       In the process of all emulation work, if a _mem_read()          #
2445# "callout" returns a failing result indicating an access error, then   #
2446# we must create an access error stack frame from the current stack     #
2447# frame. This information includes a faulting address and a fault-      #
2448# status-longword. These are created within this handler.               #
2449#                                                                       #
2450#########################################################################
2451
2452        global          _fpsp_effadd
2453_fpsp_effadd:
2454
2455# This exception type takes priority over the "Line F Emulator"
2456# exception. Therefore, the FPU could be disabled when entering here.
2457# So, we must check to see if it's disabled and handle that case separately.
2458        mov.l           %d0,-(%sp)              # save d0
2459        movc            %pcr,%d0                # load proc cr
2460        btst            &0x1,%d0                # is FPU disabled?
2461        bne.w           iea_disabled            # yes
2462        mov.l           (%sp)+,%d0              # restore d0
2463
2464        link            %a6,&-LOCAL_SIZE        # init stack frame
2465
2466        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
2467        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
2468        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
2469
2470# PC of instruction that took the exception is the PC in the frame
2471        mov.l           EXC_PC(%a6),EXC_EXTWPTR(%a6)
2472
2473        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
2474        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
2475        bsr.l           _imem_read_long         # fetch the instruction words
2476        mov.l           %d0,EXC_OPWORD(%a6)     # store OPWORD and EXTWORD
2477
2478#########################################################################
2479
2480        tst.w           %d0                     # is operation fmovem?
2481        bmi.w           iea_fmovm               # yes
2482
2483#
2484# here, we will have:
2485#       fabs    fdabs   fsabs           facos           fmod
2486#       fadd    fdadd   fsadd           fasin           frem
2487#       fcmp                            fatan           fscale
2488#       fdiv    fddiv   fsdiv           fatanh          fsin
2489#       fint                            fcos            fsincos
2490#       fintrz                          fcosh           fsinh
2491#       fmove   fdmove  fsmove          fetox           ftan
2492#       fmul    fdmul   fsmul           fetoxm1         ftanh
2493#       fneg    fdneg   fsneg           fgetexp         ftentox
2494#       fsgldiv                         fgetman         ftwotox
2495#       fsglmul                         flog10
2496#       fsqrt                           flog2
2497#       fsub    fdsub   fssub           flogn
2498#       ftst                            flognp1
2499# which can all use f<op>.{x,p}
2500# so, now it's immediate data extended precision AND PACKED FORMAT!
2501#
2502iea_op:
2503        andi.l          &0x00ff00ff,USER_FPSR(%a6)
2504
2505        btst            &0xa,%d0                # is src fmt x or p?
2506        bne.b           iea_op_pack             # packed
2507
2508
2509        mov.l           EXC_EXTWPTR(%a6),%a0    # pass: ptr to #<data>
2510        lea             FP_SRC(%a6),%a1         # pass: ptr to super addr
2511        mov.l           &0xc,%d0                # pass: 12 bytes
2512        bsr.l           _imem_read              # read extended immediate
2513
2514        tst.l           %d1                     # did ifetch fail?
2515        bne.w           iea_iacc                # yes
2516
2517        bra.b           iea_op_setsrc
2518
2519iea_op_pack:
2520
2521        mov.l           EXC_EXTWPTR(%a6),%a0    # pass: ptr to #<data>
2522        lea             FP_SRC(%a6),%a1         # pass: ptr to super dst
2523        mov.l           &0xc,%d0                # pass: 12 bytes
2524        bsr.l           _imem_read              # read packed operand
2525
2526        tst.l           %d1                     # did ifetch fail?
2527        bne.w           iea_iacc                # yes
2528
2529# The packed operand is an INF or a NAN if the exponent field is all ones.
2530        bfextu          FP_SRC(%a6){&1:&15},%d0 # get exp
2531        cmpi.w          %d0,&0x7fff             # INF or NAN?
2532        beq.b           iea_op_setsrc           # operand is an INF or NAN
2533
2534# The packed operand is a zero if the mantissa is all zero, else it's
2535# a normal packed op.
2536        mov.b           3+FP_SRC(%a6),%d0       # get byte 4
2537        andi.b          &0x0f,%d0               # clear all but last nybble
2538        bne.b           iea_op_gp_not_spec      # not a zero
2539        tst.l           FP_SRC_HI(%a6)          # is lw 2 zero?
2540        bne.b           iea_op_gp_not_spec      # not a zero
2541        tst.l           FP_SRC_LO(%a6)          # is lw 3 zero?
2542        beq.b           iea_op_setsrc           # operand is a ZERO
2543iea_op_gp_not_spec:
2544        lea             FP_SRC(%a6),%a0         # pass: ptr to packed op
2545        bsr.l           decbin                  # convert to extended
2546        fmovm.x         &0x80,FP_SRC(%a6)       # make this the srcop
2547
2548iea_op_setsrc:
2549        addi.l          &0xc,EXC_EXTWPTR(%a6)   # update extension word pointer
2550
2551# FP_SRC now holds the src operand.
2552        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
2553        bsr.l           set_tag_x               # tag the operand type
2554        mov.b           %d0,STAG(%a6)           # could be ANYTHING!!!
2555        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
2556        bne.b           iea_op_getdst           # no
2557        bsr.l           unnorm_fix              # yes; convert to NORM/DENORM/ZERO
2558        mov.b           %d0,STAG(%a6)           # set new optype tag
2559iea_op_getdst:
2560        clr.b           STORE_FLG(%a6)          # clear "store result" boolean
2561
2562        btst            &0x5,1+EXC_CMDREG(%a6)  # is operation monadic or dyadic?
2563        beq.b           iea_op_extract          # monadic
2564        btst            &0x4,1+EXC_CMDREG(%a6)  # is operation fsincos,ftst,fcmp?
2565        bne.b           iea_op_spec             # yes
2566
2567iea_op_loaddst:
2568        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno
2569        bsr.l           load_fpn2               # load dst operand
2570
2571        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
2572        bsr.l           set_tag_x               # tag the operand type
2573        mov.b           %d0,DTAG(%a6)           # could be ANYTHING!!!
2574        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
2575        bne.b           iea_op_extract          # no
2576        bsr.l           unnorm_fix              # yes; convert to NORM/DENORM/ZERO
2577        mov.b           %d0,DTAG(%a6)           # set new optype tag
2578        bra.b           iea_op_extract
2579
2580# the operation is fsincos, ftst, or fcmp. only fcmp is dyadic
2581iea_op_spec:
2582        btst            &0x3,1+EXC_CMDREG(%a6)  # is operation fsincos?
2583        beq.b           iea_op_extract          # yes
2584# now, we're left with ftst and fcmp. so, first let's tag them so that they don't
2585# store a result. then, only fcmp will branch back and pick up a dst operand.
2586        st              STORE_FLG(%a6)          # don't store a final result
2587        btst            &0x1,1+EXC_CMDREG(%a6)  # is operation fcmp?
2588        beq.b           iea_op_loaddst          # yes
2589
2590iea_op_extract:
2591        clr.l           %d0
2592        mov.b           FPCR_MODE(%a6),%d0      # pass: rnd mode,prec
2593
2594        mov.b           1+EXC_CMDREG(%a6),%d1
2595        andi.w          &0x007f,%d1             # extract extension
2596
2597        fmov.l          &0x0,%fpcr
2598        fmov.l          &0x0,%fpsr
2599
2600        lea             FP_SRC(%a6),%a0
2601        lea             FP_DST(%a6),%a1
2602
2603        mov.l           (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
2604        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
2605
2606#
2607# Exceptions in order of precedence:
2608#       BSUN    : none
2609#       SNAN    : all operations
2610#       OPERR   : all reg-reg or mem-reg operations that can normally operr
2611#       OVFL    : same as OPERR
2612#       UNFL    : same as OPERR
2613#       DZ      : same as OPERR
2614#       INEX2   : same as OPERR
2615#       INEX1   : all packed immediate operations
2616#
2617
2618# we determine the highest priority exception(if any) set by the
2619# emulation routine that has also been enabled by the user.
2620        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions enabled
2621        bne.b           iea_op_ena              # some are enabled
2622
2623# now, we save the result, unless, of course, the operation was ftst or fcmp.
2624# these don't save results.
2625iea_op_save:
2626        tst.b           STORE_FLG(%a6)          # does this op store a result?
2627        bne.b           iea_op_exit1            # exit with no frestore
2628
2629iea_op_store:
2630        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno
2631        bsr.l           store_fpreg             # store the result
2632
2633iea_op_exit1:
2634        mov.l           EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC"
2635        mov.l           EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame
2636
2637        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
2638        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2639        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2640
2641        unlk            %a6                     # unravel the frame
2642
2643        btst            &0x7,(%sp)              # is trace on?
2644        bne.w           iea_op_trace            # yes
2645
2646        bra.l           _fpsp_done              # exit to os
2647
2648iea_op_ena:
2649        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enable and set
2650        bfffo           %d0{&24:&8},%d0         # find highest priority exception
2651        bne.b           iea_op_exc              # at least one was set
2652
2653# no exception occurred. now, did a disabled, exact overflow occur with inexact
2654# enabled? if so, then we have to stuff an overflow frame into the FPU.
2655        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur?
2656        beq.b           iea_op_save
2657
2658iea_op_ovfl:
2659        btst            &inex2_bit,FPCR_ENABLE(%a6) # is inexact enabled?
2660        beq.b           iea_op_store            # no
2661        bra.b           iea_op_exc_ovfl         # yes
2662
2663# an enabled exception occurred. we have to insert the exception type back into
2664# the machine.
2665iea_op_exc:
2666        subi.l          &24,%d0                 # fix offset to be 0-8
2667        cmpi.b          %d0,&0x6                # is exception INEX?
2668        bne.b           iea_op_exc_force        # no
2669
2670# the enabled exception was inexact. so, if it occurs with an overflow
2671# or underflow that was disabled, then we have to force an overflow or
2672# underflow frame.
2673        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur?
2674        bne.b           iea_op_exc_ovfl         # yes
2675        btst            &unfl_bit,FPSR_EXCEPT(%a6) # did underflow occur?
2676        bne.b           iea_op_exc_unfl         # yes
2677
2678iea_op_exc_force:
2679        mov.w           (tbl_iea_except.b,%pc,%d0.w*2),2+FP_SRC(%a6)
2680        bra.b           iea_op_exit2            # exit with frestore
2681
2682tbl_iea_except:
2683        short           0xe002, 0xe006, 0xe004, 0xe005
2684        short           0xe003, 0xe002, 0xe001, 0xe001
2685
2686iea_op_exc_ovfl:
2687        mov.w           &0xe005,2+FP_SRC(%a6)
2688        bra.b           iea_op_exit2
2689
2690iea_op_exc_unfl:
2691        mov.w           &0xe003,2+FP_SRC(%a6)
2692
2693iea_op_exit2:
2694        mov.l           EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC"
2695        mov.l           EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame
2696
2697        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
2698        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2699        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2700
2701        frestore        FP_SRC(%a6)             # restore exceptional state
2702
2703        unlk            %a6                     # unravel the frame
2704
2705        btst            &0x7,(%sp)              # is trace on?
2706        bne.b           iea_op_trace            # yes
2707
2708        bra.l           _fpsp_done              # exit to os
2709
2710#
2711# The opclass two instruction that took an "Unimplemented Effective Address"
2712# exception was being traced. Make the "current" PC the FPIAR and put it in
2713# the trace stack frame then jump to _real_trace().
2714#
2715#                UNIMP EA FRAME            TRACE FRAME
2716#               *****************       *****************
2717#               * 0x0 *  0x0f0  *       *    Current    *
2718#               *****************       *      PC       *
2719#               *    Current    *       *****************
2720#               *      PC       *       * 0x2 *  0x024  *
2721#               *****************       *****************
2722#               *      SR       *       *     Next      *
2723#               *****************       *      PC       *
2724#                                       *****************
2725#                                       *      SR       *
2726#                                       *****************
2727iea_op_trace:
2728        mov.l           (%sp),-(%sp)            # shift stack frame "down"
2729        mov.w           0x8(%sp),0x4(%sp)
2730        mov.w           &0x2024,0x6(%sp)        # stk fmt = 0x2; voff = 0x024
2731        fmov.l          %fpiar,0x8(%sp)         # "Current PC" is in FPIAR
2732
2733        bra.l           _real_trace
2734
2735#########################################################################
2736iea_fmovm:
2737        btst            &14,%d0                 # ctrl or data reg
2738        beq.w           iea_fmovm_ctrl
2739
2740iea_fmovm_data:
2741
2742        btst            &0x5,EXC_SR(%a6)        # user or supervisor mode
2743        bne.b           iea_fmovm_data_s
2744
2745iea_fmovm_data_u:
2746        mov.l           %usp,%a0
2747        mov.l           %a0,EXC_A7(%a6)         # store current a7
2748        bsr.l           fmovm_dynamic           # do dynamic fmovm
2749        mov.l           EXC_A7(%a6),%a0         # load possibly new a7
2750        mov.l           %a0,%usp                # update usp
2751        bra.w           iea_fmovm_exit
2752
2753iea_fmovm_data_s:
2754        clr.b           SPCOND_FLG(%a6)
2755        lea             0x2+EXC_VOFF(%a6),%a0
2756        mov.l           %a0,EXC_A7(%a6)
2757        bsr.l           fmovm_dynamic           # do dynamic fmovm
2758
2759        cmpi.b          SPCOND_FLG(%a6),&mda7_flg
2760        beq.w           iea_fmovm_data_predec
2761        cmpi.b          SPCOND_FLG(%a6),&mia7_flg
2762        bne.w           iea_fmovm_exit
2763
2764# right now, d0 = the size.
2765# the data has been fetched from the supervisor stack, but we have not
2766# incremented the stack pointer by the appropriate number of bytes.
2767# do it here.
2768iea_fmovm_data_postinc:
2769        btst            &0x7,EXC_SR(%a6)
2770        bne.b           iea_fmovm_data_pi_trace
2771
2772        mov.w           EXC_SR(%a6),(EXC_SR,%a6,%d0)
2773        mov.l           EXC_EXTWPTR(%a6),(EXC_PC,%a6,%d0)
2774        mov.w           &0x00f0,(EXC_VOFF,%a6,%d0)
2775
2776        lea             (EXC_SR,%a6,%d0),%a0
2777        mov.l           %a0,EXC_SR(%a6)
2778
2779        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
2780        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2781        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2782
2783        unlk            %a6
2784        mov.l           (%sp)+,%sp
2785        bra.l           _fpsp_done
2786
2787iea_fmovm_data_pi_trace:
2788        mov.w           EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0)
2789        mov.l           EXC_EXTWPTR(%a6),(EXC_PC-0x4,%a6,%d0)
2790        mov.w           &0x2024,(EXC_VOFF-0x4,%a6,%d0)
2791        mov.l           EXC_PC(%a6),(EXC_VOFF+0x2-0x4,%a6,%d0)
2792
2793        lea             (EXC_SR-0x4,%a6,%d0),%a0
2794        mov.l           %a0,EXC_SR(%a6)
2795
2796        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
2797        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2798        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2799
2800        unlk            %a6
2801        mov.l           (%sp)+,%sp
2802        bra.l           _real_trace
2803
2804# right now, d1 = size and d0 = the strg.
2805iea_fmovm_data_predec:
2806        mov.b           %d1,EXC_VOFF(%a6)       # store strg
2807        mov.b           %d0,0x1+EXC_VOFF(%a6)   # store size
2808
2809        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
2810        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2811        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2812
2813        mov.l           (%a6),-(%sp)            # make a copy of a6
2814        mov.l           %d0,-(%sp)              # save d0
2815        mov.l           %d1,-(%sp)              # save d1
2816        mov.l           EXC_EXTWPTR(%a6),-(%sp) # make a copy of Next PC
2817
2818        clr.l           %d0
2819        mov.b           0x1+EXC_VOFF(%a6),%d0   # fetch size
2820        neg.l           %d0                     # get negative of size
2821
2822        btst            &0x7,EXC_SR(%a6)        # is trace enabled?
2823        beq.b           iea_fmovm_data_p2
2824
2825        mov.w           EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0)
2826        mov.l           EXC_PC(%a6),(EXC_VOFF-0x2,%a6,%d0)
2827        mov.l           (%sp)+,(EXC_PC-0x4,%a6,%d0)
2828        mov.w           &0x2024,(EXC_VOFF-0x4,%a6,%d0)
2829
2830        pea             (%a6,%d0)               # create final sp
2831        bra.b           iea_fmovm_data_p3
2832
2833iea_fmovm_data_p2:
2834        mov.w           EXC_SR(%a6),(EXC_SR,%a6,%d0)
2835        mov.l           (%sp)+,(EXC_PC,%a6,%d0)
2836        mov.w           &0x00f0,(EXC_VOFF,%a6,%d0)
2837
2838        pea             (0x4,%a6,%d0)           # create final sp
2839
2840iea_fmovm_data_p3:
2841        clr.l           %d1
2842        mov.b           EXC_VOFF(%a6),%d1       # fetch strg
2843
2844        tst.b           %d1
2845        bpl.b           fm_1
2846        fmovm.x         &0x80,(0x4+0x8,%a6,%d0)
2847        addi.l          &0xc,%d0
2848fm_1:
2849        lsl.b           &0x1,%d1
2850        bpl.b           fm_2
2851        fmovm.x         &0x40,(0x4+0x8,%a6,%d0)
2852        addi.l          &0xc,%d0
2853fm_2:
2854        lsl.b           &0x1,%d1
2855        bpl.b           fm_3
2856        fmovm.x         &0x20,(0x4+0x8,%a6,%d0)
2857        addi.l          &0xc,%d0
2858fm_3:
2859        lsl.b           &0x1,%d1
2860        bpl.b           fm_4
2861        fmovm.x         &0x10,(0x4+0x8,%a6,%d0)
2862        addi.l          &0xc,%d0
2863fm_4:
2864        lsl.b           &0x1,%d1
2865        bpl.b           fm_5
2866        fmovm.x         &0x08,(0x4+0x8,%a6,%d0)
2867        addi.l          &0xc,%d0
2868fm_5:
2869        lsl.b           &0x1,%d1
2870        bpl.b           fm_6
2871        fmovm.x         &0x04,(0x4+0x8,%a6,%d0)
2872        addi.l          &0xc,%d0
2873fm_6:
2874        lsl.b           &0x1,%d1
2875        bpl.b           fm_7
2876        fmovm.x         &0x02,(0x4+0x8,%a6,%d0)
2877        addi.l          &0xc,%d0
2878fm_7:
2879        lsl.b           &0x1,%d1
2880        bpl.b           fm_end
2881        fmovm.x         &0x01,(0x4+0x8,%a6,%d0)
2882fm_end:
2883        mov.l           0x4(%sp),%d1
2884        mov.l           0x8(%sp),%d0
2885        mov.l           0xc(%sp),%a6
2886        mov.l           (%sp)+,%sp
2887
2888        btst            &0x7,(%sp)              # is trace enabled?
2889        beq.l           _fpsp_done
2890        bra.l           _real_trace
2891
2892#########################################################################
2893iea_fmovm_ctrl:
2894
2895        bsr.l           fmovm_ctrl              # load ctrl regs
2896
2897iea_fmovm_exit:
2898        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
2899        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2900        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2901
2902        btst            &0x7,EXC_SR(%a6)        # is trace on?
2903        bne.b           iea_fmovm_trace         # yes
2904
2905        mov.l           EXC_EXTWPTR(%a6),EXC_PC(%a6) # set Next PC
2906
2907        unlk            %a6                     # unravel the frame
2908
2909        bra.l           _fpsp_done              # exit to os
2910
2911#
2912# The control reg instruction that took an "Unimplemented Effective Address"
2913# exception was being traced. The "Current PC" for the trace frame is the
2914# PC stacked for Unimp EA. The "Next PC" is in EXC_EXTWPTR.
2915# After fixing the stack frame, jump to _real_trace().
2916#
2917#                UNIMP EA FRAME            TRACE FRAME
2918#               *****************       *****************
2919#               * 0x0 *  0x0f0  *       *    Current    *
2920#               *****************       *      PC       *
2921#               *    Current    *       *****************
2922#               *      PC       *       * 0x2 *  0x024  *
2923#               *****************       *****************
2924#               *      SR       *       *     Next      *
2925#               *****************       *      PC       *
2926#                                       *****************
2927#                                       *      SR       *
2928#                                       *****************
2929# this ain't a pretty solution, but it works:
2930# -restore a6 (not with unlk)
2931# -shift stack frame down over where old a6 used to be
2932# -add LOCAL_SIZE to stack pointer
2933iea_fmovm_trace:
2934        mov.l           (%a6),%a6               # restore frame pointer
2935        mov.w           EXC_SR+LOCAL_SIZE(%sp),0x0+LOCAL_SIZE(%sp)
2936        mov.l           EXC_PC+LOCAL_SIZE(%sp),0x8+LOCAL_SIZE(%sp)
2937        mov.l           EXC_EXTWPTR+LOCAL_SIZE(%sp),0x2+LOCAL_SIZE(%sp)
2938        mov.w           &0x2024,0x6+LOCAL_SIZE(%sp) # stk fmt = 0x2; voff = 0x024
2939        add.l           &LOCAL_SIZE,%sp         # clear stack frame
2940
2941        bra.l           _real_trace
2942
2943#########################################################################
2944# The FPU is disabled and so we should really have taken the "Line
2945# F Emulator" exception. So, here we create an 8-word stack frame
2946# from our 4-word stack frame. This means we must calculate the length
2947# the faulting instruction to get the "next PC". This is trivial for
2948# immediate operands but requires some extra work for fmovm dynamic
2949# which can use most addressing modes.
2950iea_disabled:
2951        mov.l           (%sp)+,%d0              # restore d0
2952
2953        link            %a6,&-LOCAL_SIZE        # init stack frame
2954
2955        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
2956
2957# PC of instruction that took the exception is the PC in the frame
2958        mov.l           EXC_PC(%a6),EXC_EXTWPTR(%a6)
2959        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
2960        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
2961        bsr.l           _imem_read_long         # fetch the instruction words
2962        mov.l           %d0,EXC_OPWORD(%a6)     # store OPWORD and EXTWORD
2963
2964        tst.w           %d0                     # is instr fmovm?
2965        bmi.b           iea_dis_fmovm           # yes
2966# instruction is using an extended precision immediate operand. Therefore,
2967# the total instruction length is 16 bytes.
2968iea_dis_immed:
2969        mov.l           &0x10,%d0               # 16 bytes of instruction
2970        bra.b           iea_dis_cont
2971iea_dis_fmovm:
2972        btst            &0xe,%d0                # is instr fmovm ctrl
2973        bne.b           iea_dis_fmovm_data      # no
2974# the instruction is a fmovm.l with 2 or 3 registers.
2975        bfextu          %d0{&19:&3},%d1
2976        mov.l           &0xc,%d0
2977        cmpi.b          %d1,&0x7                # move all regs?
2978        bne.b           iea_dis_cont
2979        addq.l          &0x4,%d0
2980        bra.b           iea_dis_cont
2981# the instruction is an fmovm.x dynamic which can use many addressing
2982# modes and thus can have several different total instruction lengths.
2983# call fmovm_calc_ea which will go through the ea calc process and,
2984# as a by-product, will tell us how long the instruction is.
2985iea_dis_fmovm_data:
2986        clr.l           %d0
2987        bsr.l           fmovm_calc_ea
2988        mov.l           EXC_EXTWPTR(%a6),%d0
2989        sub.l           EXC_PC(%a6),%d0
2990iea_dis_cont:
2991        mov.w           %d0,EXC_VOFF(%a6)       # store stack shift value
2992
2993        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
2994
2995        unlk            %a6
2996
2997# here, we actually create the 8-word frame from the 4-word frame,
2998# with the "next PC" as additional info.
2999# the <ea> field is let as undefined.
3000        subq.l          &0x8,%sp                # make room for new stack
3001        mov.l           %d0,-(%sp)              # save d0
3002        mov.w           0xc(%sp),0x4(%sp)       # move SR
3003        mov.l           0xe(%sp),0x6(%sp)       # move Current PC
3004        clr.l           %d0
3005        mov.w           0x12(%sp),%d0
3006        mov.l           0x6(%sp),0x10(%sp)      # move Current PC
3007        add.l           %d0,0x6(%sp)            # make Next PC
3008        mov.w           &0x402c,0xa(%sp)        # insert offset,frame format
3009        mov.l           (%sp)+,%d0              # restore d0
3010
3011        bra.l           _real_fpu_disabled
3012
3013##########
3014
3015iea_iacc:
3016        movc            %pcr,%d0
3017        btst            &0x1,%d0
3018        bne.b           iea_iacc_cont
3019        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3020        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1 on stack
3021iea_iacc_cont:
3022        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3023
3024        unlk            %a6
3025
3026        subq.w          &0x8,%sp                # make stack frame bigger
3027        mov.l           0x8(%sp),(%sp)          # store SR,hi(PC)
3028        mov.w           0xc(%sp),0x4(%sp)       # store lo(PC)
3029        mov.w           &0x4008,0x6(%sp)        # store voff
3030        mov.l           0x2(%sp),0x8(%sp)       # store ea
3031        mov.l           &0x09428001,0xc(%sp)    # store fslw
3032
3033iea_acc_done:
3034        btst            &0x5,(%sp)              # user or supervisor mode?
3035        beq.b           iea_acc_done2           # user
3036        bset            &0x2,0xd(%sp)           # set supervisor TM bit
3037
3038iea_acc_done2:
3039        bra.l           _real_access
3040
3041iea_dacc:
3042        lea             -LOCAL_SIZE(%a6),%sp
3043
3044        movc            %pcr,%d1
3045        btst            &0x1,%d1
3046        bne.b           iea_dacc_cont
3047        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1 on stack
3048        fmovm.l         LOCAL_SIZE+USER_FPCR(%sp),%fpcr,%fpsr,%fpiar # restore ctrl regs
3049iea_dacc_cont:
3050        mov.l           (%a6),%a6
3051
3052        mov.l           0x4+LOCAL_SIZE(%sp),-0x8+0x4+LOCAL_SIZE(%sp)
3053        mov.w           0x8+LOCAL_SIZE(%sp),-0x8+0x8+LOCAL_SIZE(%sp)
3054        mov.w           &0x4008,-0x8+0xa+LOCAL_SIZE(%sp)
3055        mov.l           %a0,-0x8+0xc+LOCAL_SIZE(%sp)
3056        mov.w           %d0,-0x8+0x10+LOCAL_SIZE(%sp)
3057        mov.w           &0x0001,-0x8+0x12+LOCAL_SIZE(%sp)
3058
3059        movm.l          LOCAL_SIZE+EXC_DREGS(%sp),&0x0303 # restore d0-d1/a0-a1
3060        add.w           &LOCAL_SIZE-0x4,%sp
3061
3062        bra.b           iea_acc_done
3063
3064#########################################################################
3065# XDEF **************************************************************** #
3066#       _fpsp_operr(): 060FPSP entry point for FP Operr exception.      #
3067#                                                                       #
3068#       This handler should be the first code executed upon taking the  #
3069#       FP Operand Error exception in an operating system.              #
3070#                                                                       #
3071# XREF **************************************************************** #
3072#       _imem_read_long() - read instruction longword                   #
3073#       fix_skewed_ops() - adjust src operand in fsave frame            #
3074#       _real_operr() - "callout" to operating system operr handler     #
3075#       _dmem_write_{byte,word,long}() - store data to mem (opclass 3)  #
3076#       store_dreg_{b,w,l}() - store data to data regfile (opclass 3)   #
3077#       facc_out_{b,w,l}() - store to memory took access error (opcl 3) #
3078#                                                                       #
3079# INPUT *************************************************************** #
3080#       - The system stack contains the FP Operr exception frame        #
3081#       - The fsave frame contains the source operand                   #
3082#                                                                       #
3083# OUTPUT ************************************************************** #
3084#       No access error:                                                #
3085#       - The system stack is unchanged                                 #
3086#       - The fsave frame contains the adjusted src op for opclass 0,2  #
3087#                                                                       #
3088# ALGORITHM *********************************************************** #
3089#       In a system where the FP Operr exception is enabled, the goal   #
3090# is to get to the handler specified at _real_operr(). But, on the 060, #
3091# for opclass zero and two instruction taking this exception, the       #
3092# input operand in the fsave frame may be incorrect for some cases      #
3093# and needs to be corrected. This handler calls fix_skewed_ops() to     #
3094# do just this and then exits through _real_operr().                    #
3095#       For opclass 3 instructions, the 060 doesn't store the default   #
3096# operr result out to memory or data register file as it should.        #
3097# This code must emulate the move out before finally exiting through    #
3098# _real_inex(). The move out, if to memory, is performed using          #
3099# _mem_write() "callout" routines that may return a failing result.     #
3100# In this special case, the handler must exit through facc_out()        #
3101# which creates an access error stack frame from the current operr      #
3102# stack frame.                                                          #
3103#                                                                       #
3104#########################################################################
3105
3106        global          _fpsp_operr
3107_fpsp_operr:
3108
3109        link.w          %a6,&-LOCAL_SIZE        # init stack frame
3110
3111        fsave           FP_SRC(%a6)             # grab the "busy" frame
3112
3113        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3114        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3115        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
3116
3117# the FPIAR holds the "current PC" of the faulting instruction
3118        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3119
3120        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3121        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3122        bsr.l           _imem_read_long         # fetch the instruction words
3123        mov.l           %d0,EXC_OPWORD(%a6)
3124
3125##############################################################################
3126
3127        btst            &13,%d0                 # is instr an fmove out?
3128        bne.b           foperr_out              # fmove out
3129
3130
3131# here, we simply see if the operand in the fsave frame needs to be "unskewed".
3132# this would be the case for opclass two operations with a source infinity or
3133# denorm operand in the sgl or dbl format. NANs also become skewed, but can't
3134# cause an operr so we don't need to check for them here.
3135        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3136        bsr.l           fix_skewed_ops          # fix src op
3137
3138foperr_exit:
3139        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3140        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3141        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3142
3143        frestore        FP_SRC(%a6)
3144
3145        unlk            %a6
3146        bra.l           _real_operr
3147
3148########################################################################
3149
3150#
3151# the hardware does not save the default result to memory on enabled
3152# operand error exceptions. we do this here before passing control to
3153# the user operand error handler.
3154#
3155# byte, word, and long destination format operations can pass
3156# through here. we simply need to test the sign of the src
3157# operand and save the appropriate minimum or maximum integer value
3158# to the effective address as pointed to by the stacked effective address.
3159#
3160# although packed opclass three operations can take operand error
3161# exceptions, they won't pass through here since they are caught
3162# first by the unsupported data format exception handler. that handler
3163# sends them directly to _real_operr() if necessary.
3164#
3165foperr_out:
3166
3167        mov.w           FP_SRC_EX(%a6),%d1      # fetch exponent
3168        andi.w          &0x7fff,%d1
3169        cmpi.w          %d1,&0x7fff
3170        bne.b           foperr_out_not_qnan
3171# the operand is either an infinity or a QNAN.
3172        tst.l           FP_SRC_LO(%a6)
3173        bne.b           foperr_out_qnan
3174        mov.l           FP_SRC_HI(%a6),%d1
3175        andi.l          &0x7fffffff,%d1
3176        beq.b           foperr_out_not_qnan
3177foperr_out_qnan:
3178        mov.l           FP_SRC_HI(%a6),L_SCR1(%a6)
3179        bra.b           foperr_out_jmp
3180
3181foperr_out_not_qnan:
3182        mov.l           &0x7fffffff,%d1
3183        tst.b           FP_SRC_EX(%a6)
3184        bpl.b           foperr_out_not_qnan2
3185        addq.l          &0x1,%d1
3186foperr_out_not_qnan2:
3187        mov.l           %d1,L_SCR1(%a6)
3188
3189foperr_out_jmp:
3190        bfextu          %d0{&19:&3},%d0         # extract dst format field
3191        mov.b           1+EXC_OPWORD(%a6),%d1   # extract <ea> mode,reg
3192        mov.w           (tbl_operr.b,%pc,%d0.w*2),%a0
3193        jmp             (tbl_operr.b,%pc,%a0)
3194
3195tbl_operr:
3196        short           foperr_out_l - tbl_operr # long word integer
3197        short           tbl_operr    - tbl_operr # sgl prec shouldn't happen
3198        short           tbl_operr    - tbl_operr # ext prec shouldn't happen
3199        short           foperr_exit  - tbl_operr # packed won't enter here
3200        short           foperr_out_w - tbl_operr # word integer
3201        short           tbl_operr    - tbl_operr # dbl prec shouldn't happen
3202        short           foperr_out_b - tbl_operr # byte integer
3203        short           tbl_operr    - tbl_operr # packed won't enter here
3204
3205foperr_out_b:
3206        mov.b           L_SCR1(%a6),%d0         # load positive default result
3207        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3208        ble.b           foperr_out_b_save_dn    # yes
3209        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3210        bsr.l           _dmem_write_byte        # write the default result
3211
3212        tst.l           %d1                     # did dstore fail?
3213        bne.l           facc_out_b              # yes
3214
3215        bra.w           foperr_exit
3216foperr_out_b_save_dn:
3217        andi.w          &0x0007,%d1
3218        bsr.l           store_dreg_b            # store result to regfile
3219        bra.w           foperr_exit
3220
3221foperr_out_w:
3222        mov.w           L_SCR1(%a6),%d0         # load positive default result
3223        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3224        ble.b           foperr_out_w_save_dn    # yes
3225        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3226        bsr.l           _dmem_write_word        # write the default result
3227
3228        tst.l           %d1                     # did dstore fail?
3229        bne.l           facc_out_w              # yes
3230
3231        bra.w           foperr_exit
3232foperr_out_w_save_dn:
3233        andi.w          &0x0007,%d1
3234        bsr.l           store_dreg_w            # store result to regfile
3235        bra.w           foperr_exit
3236
3237foperr_out_l:
3238        mov.l           L_SCR1(%a6),%d0         # load positive default result
3239        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3240        ble.b           foperr_out_l_save_dn    # yes
3241        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3242        bsr.l           _dmem_write_long        # write the default result
3243
3244        tst.l           %d1                     # did dstore fail?
3245        bne.l           facc_out_l              # yes
3246
3247        bra.w           foperr_exit
3248foperr_out_l_save_dn:
3249        andi.w          &0x0007,%d1
3250        bsr.l           store_dreg_l            # store result to regfile
3251        bra.w           foperr_exit
3252
3253#########################################################################
3254# XDEF **************************************************************** #
3255#       _fpsp_snan(): 060FPSP entry point for FP SNAN exception.        #
3256#                                                                       #
3257#       This handler should be the first code executed upon taking the  #
3258#       FP Signalling NAN exception in an operating system.             #
3259#                                                                       #
3260# XREF **************************************************************** #
3261#       _imem_read_long() - read instruction longword                   #
3262#       fix_skewed_ops() - adjust src operand in fsave frame            #
3263#       _real_snan() - "callout" to operating system SNAN handler       #
3264#       _dmem_write_{byte,word,long}() - store data to mem (opclass 3)  #
3265#       store_dreg_{b,w,l}() - store data to data regfile (opclass 3)   #
3266#       facc_out_{b,w,l,d,x}() - store to mem took acc error (opcl 3)   #
3267#       _calc_ea_fout() - fix An if <ea> is -() or ()+; also get <ea>   #
3268#                                                                       #
3269# INPUT *************************************************************** #
3270#       - The system stack contains the FP SNAN exception frame         #
3271#       - The fsave frame contains the source operand                   #
3272#                                                                       #
3273# OUTPUT ************************************************************** #
3274#       No access error:                                                #
3275#       - The system stack is unchanged                                 #
3276#       - The fsave frame contains the adjusted src op for opclass 0,2  #
3277#                                                                       #
3278# ALGORITHM *********************************************************** #
3279#       In a system where the FP SNAN exception is enabled, the goal    #
3280# is to get to the handler specified at _real_snan(). But, on the 060,  #
3281# for opclass zero and two instructions taking this exception, the      #
3282# input operand in the fsave frame may be incorrect for some cases      #
3283# and needs to be corrected. This handler calls fix_skewed_ops() to     #
3284# do just this and then exits through _real_snan().                     #
3285#       For opclass 3 instructions, the 060 doesn't store the default   #
3286# SNAN result out to memory or data register file as it should.         #
3287# This code must emulate the move out before finally exiting through    #
3288# _real_snan(). The move out, if to memory, is performed using          #
3289# _mem_write() "callout" routines that may return a failing result.     #
3290# In this special case, the handler must exit through facc_out()        #
3291# which creates an access error stack frame from the current SNAN       #
3292# stack frame.                                                          #
3293#       For the case of an extended precision opclass 3 instruction,    #
3294# if the effective addressing mode was -() or ()+, then the address     #
3295# register must get updated by calling _calc_ea_fout(). If the <ea>     #
3296# was -(a7) from supervisor mode, then the exception frame currently    #
3297# on the system stack must be carefully moved "down" to make room       #
3298# for the operand being moved.                                          #
3299#                                                                       #
3300#########################################################################
3301
3302        global          _fpsp_snan
3303_fpsp_snan:
3304
3305        link.w          %a6,&-LOCAL_SIZE        # init stack frame
3306
3307        fsave           FP_SRC(%a6)             # grab the "busy" frame
3308
3309        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3310        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3311        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
3312
3313# the FPIAR holds the "current PC" of the faulting instruction
3314        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3315
3316        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3317        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3318        bsr.l           _imem_read_long         # fetch the instruction words
3319        mov.l           %d0,EXC_OPWORD(%a6)
3320
3321##############################################################################
3322
3323        btst            &13,%d0                 # is instr an fmove out?
3324        bne.w           fsnan_out               # fmove out
3325
3326
3327# here, we simply see if the operand in the fsave frame needs to be "unskewed".
3328# this would be the case for opclass two operations with a source infinity or
3329# denorm operand in the sgl or dbl format. NANs also become skewed and must be
3330# fixed here.
3331        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3332        bsr.l           fix_skewed_ops          # fix src op
3333
3334fsnan_exit:
3335        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3336        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3337        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3338
3339        frestore        FP_SRC(%a6)
3340
3341        unlk            %a6
3342        bra.l           _real_snan
3343
3344########################################################################
3345
3346#
3347# the hardware does not save the default result to memory on enabled
3348# snan exceptions. we do this here before passing control to
3349# the user snan handler.
3350#
3351# byte, word, long, and packed destination format operations can pass
3352# through here. since packed format operations already were handled by
3353# fpsp_unsupp(), then we need to do nothing else for them here.
3354# for byte, word, and long, we simply need to test the sign of the src
3355# operand and save the appropriate minimum or maximum integer value
3356# to the effective address as pointed to by the stacked effective address.
3357#
3358fsnan_out:
3359
3360        bfextu          %d0{&19:&3},%d0         # extract dst format field
3361        mov.b           1+EXC_OPWORD(%a6),%d1   # extract <ea> mode,reg
3362        mov.w           (tbl_snan.b,%pc,%d0.w*2),%a0
3363        jmp             (tbl_snan.b,%pc,%a0)
3364
3365tbl_snan:
3366        short           fsnan_out_l - tbl_snan # long word integer
3367        short           fsnan_out_s - tbl_snan # sgl prec shouldn't happen
3368        short           fsnan_out_x - tbl_snan # ext prec shouldn't happen
3369        short           tbl_snan    - tbl_snan # packed needs no help
3370        short           fsnan_out_w - tbl_snan # word integer
3371        short           fsnan_out_d - tbl_snan # dbl prec shouldn't happen
3372        short           fsnan_out_b - tbl_snan # byte integer
3373        short           tbl_snan    - tbl_snan # packed needs no help
3374
3375fsnan_out_b:
3376        mov.b           FP_SRC_HI(%a6),%d0      # load upper byte of SNAN
3377        bset            &6,%d0                  # set SNAN bit
3378        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3379        ble.b           fsnan_out_b_dn          # yes
3380        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3381        bsr.l           _dmem_write_byte        # write the default result
3382
3383        tst.l           %d1                     # did dstore fail?
3384        bne.l           facc_out_b              # yes
3385
3386        bra.w           fsnan_exit
3387fsnan_out_b_dn:
3388        andi.w          &0x0007,%d1
3389        bsr.l           store_dreg_b            # store result to regfile
3390        bra.w           fsnan_exit
3391
3392fsnan_out_w:
3393        mov.w           FP_SRC_HI(%a6),%d0      # load upper word of SNAN
3394        bset            &14,%d0                 # set SNAN bit
3395        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3396        ble.b           fsnan_out_w_dn          # yes
3397        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3398        bsr.l           _dmem_write_word        # write the default result
3399
3400        tst.l           %d1                     # did dstore fail?
3401        bne.l           facc_out_w              # yes
3402
3403        bra.w           fsnan_exit
3404fsnan_out_w_dn:
3405        andi.w          &0x0007,%d1
3406        bsr.l           store_dreg_w            # store result to regfile
3407        bra.w           fsnan_exit
3408
3409fsnan_out_l:
3410        mov.l           FP_SRC_HI(%a6),%d0      # load upper longword of SNAN
3411        bset            &30,%d0                 # set SNAN bit
3412        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3413        ble.b           fsnan_out_l_dn          # yes
3414        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3415        bsr.l           _dmem_write_long        # write the default result
3416
3417        tst.l           %d1                     # did dstore fail?
3418        bne.l           facc_out_l              # yes
3419
3420        bra.w           fsnan_exit
3421fsnan_out_l_dn:
3422        andi.w          &0x0007,%d1
3423        bsr.l           store_dreg_l            # store result to regfile
3424        bra.w           fsnan_exit
3425
3426fsnan_out_s:
3427        cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3428        ble.b           fsnan_out_d_dn          # yes
3429        mov.l           FP_SRC_EX(%a6),%d0      # fetch SNAN sign
3430        andi.l          &0x80000000,%d0         # keep sign
3431        ori.l           &0x7fc00000,%d0         # insert new exponent,SNAN bit
3432        mov.l           FP_SRC_HI(%a6),%d1      # load mantissa
3433        lsr.l           &0x8,%d1                # shift mantissa for sgl
3434        or.l            %d1,%d0                 # create sgl SNAN
3435        mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3436        bsr.l           _dmem_write_long        # write the default result
3437
3438        tst.l           %d1                     # did dstore fail?
3439        bne.l           facc_out_l              # yes
3440
3441        bra.w           fsnan_exit
3442fsnan_out_d_dn:
3443        mov.l           FP_SRC_EX(%a6),%d0      # fetch SNAN sign
3444        andi.l          &0x80000000,%d0         # keep sign
3445        ori.l           &0x7fc00000,%d0         # insert new exponent,SNAN bit
3446        mov.l           %d1,-(%sp)
3447        mov.l           FP_SRC_HI(%a6),%d1      # load mantissa
3448        lsr.l           &0x8,%d1                # shift mantissa for sgl
3449        or.l            %d1,%d0                 # create sgl SNAN
3450        mov.l           (%sp)+,%d1
3451        andi.w          &0x0007,%d1
3452        bsr.l           store_dreg_l            # store result to regfile
3453        bra.w           fsnan_exit
3454
3455fsnan_out_d:
3456        mov.l           FP_SRC_EX(%a6),%d0      # fetch SNAN sign
3457        andi.l          &0x80000000,%d0         # keep sign
3458        ori.l           &0x7ff80000,%d0         # insert new exponent,SNAN bit
3459        mov.l           FP_SRC_HI(%a6),%d1      # load hi mantissa
3460        mov.l           %d0,FP_SCR0_EX(%a6)     # store to temp space
3461        mov.l           &11,%d0                 # load shift amt
3462        lsr.l           %d0,%d1
3463        or.l            %d1,FP_SCR0_EX(%a6)     # create dbl hi
3464        mov.l           FP_SRC_HI(%a6),%d1      # load hi mantissa
3465        andi.l          &0x000007ff,%d1
3466        ror.l           %d0,%d1
3467        mov.l           %d1,FP_SCR0_HI(%a6)     # store to temp space
3468        mov.l           FP_SRC_LO(%a6),%d1      # load lo mantissa
3469        lsr.l           %d0,%d1
3470        or.l            %d1,FP_SCR0_HI(%a6)     # create dbl lo
3471        lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
3472        mov.l           EXC_EA(%a6),%a1         # pass: dst addr
3473        movq.l          &0x8,%d0                # pass: size of 8 bytes
3474        bsr.l           _dmem_write             # write the default result
3475
3476        tst.l           %d1                     # did dstore fail?
3477        bne.l           facc_out_d              # yes
3478
3479        bra.w           fsnan_exit
3480
3481# for extended precision, if the addressing mode is pre-decrement or
3482# post-increment, then the address register did not get updated.
3483# in addition, for pre-decrement, the stacked <ea> is incorrect.
3484fsnan_out_x:
3485        clr.b           SPCOND_FLG(%a6)         # clear special case flag
3486
3487        mov.w           FP_SRC_EX(%a6),FP_SCR0_EX(%a6)
3488        clr.w           2+FP_SCR0(%a6)
3489        mov.l           FP_SRC_HI(%a6),%d0
3490        bset            &30,%d0
3491        mov.l           %d0,FP_SCR0_HI(%a6)
3492        mov.l           FP_SRC_LO(%a6),FP_SCR0_LO(%a6)
3493
3494        btst            &0x5,EXC_SR(%a6)        # supervisor mode exception?
3495        bne.b           fsnan_out_x_s           # yes
3496
3497        mov.l           %usp,%a0                # fetch user stack pointer
3498        mov.l           %a0,EXC_A7(%a6)         # save on stack for calc_ea()
3499        mov.l           (%a6),EXC_A6(%a6)
3500
3501        bsr.l           _calc_ea_fout           # find the correct ea,update An
3502        mov.l           %a0,%a1
3503        mov.l           %a0,EXC_EA(%a6)         # stack correct <ea>
3504
3505        mov.l           EXC_A7(%a6),%a0
3506        mov.l           %a0,%usp                # restore user stack pointer
3507        mov.l           EXC_A6(%a6),(%a6)
3508
3509fsnan_out_x_save:
3510        lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
3511        movq.l          &0xc,%d0                # pass: size of extended
3512        bsr.l           _dmem_write             # write the default result
3513
3514        tst.l           %d1                     # did dstore fail?
3515        bne.l           facc_out_x              # yes
3516
3517        bra.w           fsnan_exit
3518
3519fsnan_out_x_s:
3520        mov.l           (%a6),EXC_A6(%a6)
3521
3522        bsr.l           _calc_ea_fout           # find the correct ea,update An
3523        mov.l           %a0,%a1
3524        mov.l           %a0,EXC_EA(%a6)         # stack correct <ea>
3525
3526        mov.l           EXC_A6(%a6),(%a6)
3527
3528        cmpi.b          SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)?
3529        bne.b           fsnan_out_x_save        # no
3530
3531# the operation was "fmove.x SNAN,-(a7)" from supervisor mode.
3532        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3533        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3534        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3535
3536        frestore        FP_SRC(%a6)
3537
3538        mov.l           EXC_A6(%a6),%a6         # restore frame pointer
3539
3540        mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
3541        mov.l           LOCAL_SIZE+EXC_PC+0x2(%sp),LOCAL_SIZE+EXC_PC+0x2-0xc(%sp)
3542        mov.l           LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
3543
3544        mov.l           LOCAL_SIZE+FP_SCR0_EX(%sp),LOCAL_SIZE+EXC_SR(%sp)
3545        mov.l           LOCAL_SIZE+FP_SCR0_HI(%sp),LOCAL_SIZE+EXC_PC+0x2(%sp)
3546        mov.l           LOCAL_SIZE+FP_SCR0_LO(%sp),LOCAL_SIZE+EXC_EA(%sp)
3547
3548        add.l           &LOCAL_SIZE-0x8,%sp
3549
3550        bra.l           _real_snan
3551
3552#########################################################################
3553# XDEF **************************************************************** #
3554#       _fpsp_inex(): 060FPSP entry point for FP Inexact exception.     #
3555#                                                                       #
3556#       This handler should be the first code executed upon taking the  #
3557#       FP Inexact exception in an operating system.                    #
3558#                                                                       #
3559# XREF **************************************************************** #
3560#       _imem_read_long() - read instruction longword                   #
3561#       fix_skewed_ops() - adjust src operand in fsave frame            #
3562#       set_tag_x() - determine optype of src/dst operands              #
3563#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
3564#       unnorm_fix() - change UNNORM operands to NORM or ZERO           #
3565#       load_fpn2() - load dst operand from FP regfile                  #
3566#       smovcr() - emulate an "fmovcr" instruction                      #
3567#       fout() - emulate an opclass 3 instruction                       #
3568#       tbl_unsupp - add of table of emulation routines for opclass 0,2 #
3569#       _real_inex() - "callout" to operating system inexact handler    #
3570#                                                                       #
3571# INPUT *************************************************************** #
3572#       - The system stack contains the FP Inexact exception frame      #
3573#       - The fsave frame contains the source operand                   #
3574#                                                                       #
3575# OUTPUT ************************************************************** #
3576#       - The system stack is unchanged                                 #
3577#       - The fsave frame contains the adjusted src op for opclass 0,2  #
3578#                                                                       #
3579# ALGORITHM *********************************************************** #
3580#       In a system where the FP Inexact exception is enabled, the goal #
3581# is to get to the handler specified at _real_inex(). But, on the 060,  #
3582# for opclass zero and two instruction taking this exception, the       #
3583# hardware doesn't store the correct result to the destination FP       #
3584# register as did the '040 and '881/2. This handler must emulate the    #
3585# instruction in order to get this value and then store it to the       #
3586# correct register before calling _real_inex().                         #
3587#       For opclass 3 instructions, the 060 doesn't store the default   #
3588# inexact result out to memory or data register file as it should.      #
3589# This code must emulate the move out by calling fout() before finally  #
3590# exiting through _real_inex().                                         #
3591#                                                                       #
3592#########################################################################
3593
3594        global          _fpsp_inex
3595_fpsp_inex:
3596
3597        link.w          %a6,&-LOCAL_SIZE        # init stack frame
3598
3599        fsave           FP_SRC(%a6)             # grab the "busy" frame
3600
3601        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3602        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3603        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
3604
3605# the FPIAR holds the "current PC" of the faulting instruction
3606        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3607
3608        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3609        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3610        bsr.l           _imem_read_long         # fetch the instruction words
3611        mov.l           %d0,EXC_OPWORD(%a6)
3612
3613##############################################################################
3614
3615        btst            &13,%d0                 # is instr an fmove out?
3616        bne.w           finex_out               # fmove out
3617
3618
3619# the hardware, for "fabs" and "fneg" w/ a long source format, puts the
3620# longword integer directly into the upper longword of the mantissa along
3621# w/ an exponent value of 0x401e. we convert this to extended precision here.
3622        bfextu          %d0{&19:&3},%d0         # fetch instr size
3623        bne.b           finex_cont              # instr size is not long
3624        cmpi.w          FP_SRC_EX(%a6),&0x401e  # is exponent 0x401e?
3625        bne.b           finex_cont              # no
3626        fmov.l          &0x0,%fpcr
3627        fmov.l          FP_SRC_HI(%a6),%fp0     # load integer src
3628        fmov.x          %fp0,FP_SRC(%a6)        # store integer as extended precision
3629        mov.w           &0xe001,0x2+FP_SRC(%a6)
3630
3631finex_cont:
3632        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3633        bsr.l           fix_skewed_ops          # fix src op
3634
3635# Here, we zero the ccode and exception byte field since we're going to
3636# emulate the whole instruction. Notice, though, that we don't kill the
3637# INEX1 bit. This is because a packed op has long since been converted
3638# to extended before arriving here. Therefore, we need to retain the
3639# INEX1 bit from when the operand was first converted.
3640        andi.l          &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field
3641
3642        fmov.l          &0x0,%fpcr              # zero current control regs
3643        fmov.l          &0x0,%fpsr
3644
3645        bfextu          EXC_EXTWORD(%a6){&0:&6},%d1 # extract upper 6 of cmdreg
3646        cmpi.b          %d1,&0x17               # is op an fmovecr?
3647        beq.w           finex_fmovcr            # yes
3648
3649        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3650        bsr.l           set_tag_x               # tag the operand type
3651        mov.b           %d0,STAG(%a6)           # maybe NORM,DENORM
3652
3653# bits four and five of the fp extension word separate the monadic and dyadic
3654# operations that can pass through fpsp_inex(). remember that fcmp and ftst
3655# will never take this exception, but fsincos will.
3656        btst            &0x5,1+EXC_CMDREG(%a6)  # is operation monadic or dyadic?
3657        beq.b           finex_extract           # monadic
3658
3659        btst            &0x4,1+EXC_CMDREG(%a6)  # is operation an fsincos?
3660        bne.b           finex_extract           # yes
3661
3662        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
3663        bsr.l           load_fpn2               # load dst into FP_DST
3664
3665        lea             FP_DST(%a6),%a0         # pass: ptr to dst op
3666        bsr.l           set_tag_x               # tag the operand type
3667        cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
3668        bne.b           finex_op2_done          # no
3669        bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
3670finex_op2_done:
3671        mov.b           %d0,DTAG(%a6)           # save dst optype tag
3672
3673finex_extract:
3674        clr.l           %d0
3675        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec/mode
3676
3677        mov.b           1+EXC_CMDREG(%a6),%d1
3678        andi.w          &0x007f,%d1             # extract extension
3679
3680        lea             FP_SRC(%a6),%a0
3681        lea             FP_DST(%a6),%a1
3682
3683        mov.l           (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
3684        jsr             (tbl_unsupp.l,%pc,%d1.l*1)
3685
3686# the operation has been emulated. the result is in fp0.
3687finex_save:
3688        bfextu          EXC_CMDREG(%a6){&6:&3},%d0
3689        bsr.l           store_fpreg
3690
3691finex_exit:
3692        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3693        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3694        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3695
3696        frestore        FP_SRC(%a6)
3697
3698        unlk            %a6
3699        bra.l           _real_inex
3700
3701finex_fmovcr:
3702        clr.l           %d0
3703        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec,mode
3704        mov.b           1+EXC_CMDREG(%a6),%d1
3705        andi.l          &0x0000007f,%d1         # pass rom offset
3706        bsr.l           smovcr
3707        bra.b           finex_save
3708
3709########################################################################
3710
3711#
3712# the hardware does not save the default result to memory on enabled
3713# inexact exceptions. we do this here before passing control to
3714# the user inexact handler.
3715#
3716# byte, word, and long destination format operations can pass
3717# through here. so can double and single precision.
3718# although packed opclass three operations can take inexact
3719# exceptions, they won't pass through here since they are caught
3720# first by the unsupported data format exception handler. that handler
3721# sends them directly to _real_inex() if necessary.
3722#
3723finex_out:
3724
3725        mov.b           &NORM,STAG(%a6)         # src is a NORM
3726
3727        clr.l           %d0
3728        mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec,mode
3729
3730        andi.l          &0xffff00ff,USER_FPSR(%a6) # zero exception field
3731
3732        lea             FP_SRC(%a6),%a0         # pass ptr to src operand
3733
3734        bsr.l           fout                    # store the default result
3735
3736        bra.b           finex_exit
3737
3738#########################################################################
3739# XDEF **************************************************************** #
3740#       _fpsp_dz(): 060FPSP entry point for FP DZ exception.            #
3741#                                                                       #
3742#       This handler should be the first code executed upon taking      #
3743#       the FP DZ exception in an operating system.                     #
3744#                                                                       #
3745# XREF **************************************************************** #
3746#       _imem_read_long() - read instruction longword from memory       #
3747#       fix_skewed_ops() - adjust fsave operand                         #
3748#       _real_dz() - "callout" exit point from FP DZ handler            #
3749#                                                                       #
3750# INPUT *************************************************************** #
3751#       - The system stack contains the FP DZ exception stack.          #
3752#       - The fsave frame contains the source operand.                  #
3753#                                                                       #
3754# OUTPUT ************************************************************** #
3755#       - The system stack contains the FP DZ exception stack.          #
3756#       - The fsave frame contains the adjusted source operand.         #
3757#                                                                       #
3758# ALGORITHM *********************************************************** #
3759#       In a system where the DZ exception is enabled, the goal is to   #
3760# get to the handler specified at _real_dz(). But, on the 060, when the #
3761# exception is taken, the input operand in the fsave state frame may    #
3762# be incorrect for some cases and need to be adjusted. So, this package #
3763# adjusts the operand using fix_skewed_ops() and then branches to       #
3764# _real_dz().                                                           #
3765#                                                                       #
3766#########################################################################
3767
3768        global          _fpsp_dz
3769_fpsp_dz:
3770
3771        link.w          %a6,&-LOCAL_SIZE        # init stack frame
3772
3773        fsave           FP_SRC(%a6)             # grab the "busy" frame
3774
3775        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3776        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3777        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
3778
3779# the FPIAR holds the "current PC" of the faulting instruction
3780        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3781
3782        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3783        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3784        bsr.l           _imem_read_long         # fetch the instruction words
3785        mov.l           %d0,EXC_OPWORD(%a6)
3786
3787##############################################################################
3788
3789
3790# here, we simply see if the operand in the fsave frame needs to be "unskewed".
3791# this would be the case for opclass two operations with a source zero
3792# in the sgl or dbl format.
3793        lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3794        bsr.l           fix_skewed_ops          # fix src op
3795
3796fdz_exit:
3797        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3798        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3799        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3800
3801        frestore        FP_SRC(%a6)
3802
3803        unlk            %a6
3804        bra.l           _real_dz
3805
3806#########################################################################
3807# XDEF **************************************************************** #
3808#       _fpsp_fline(): 060FPSP entry point for "Line F emulator" exc.   #
3809#                                                                       #
3810#       This handler should be the first code executed upon taking the  #
3811#       "Line F Emulator" exception in an operating system.             #
3812#                                                                       #
3813# XREF **************************************************************** #
3814#       _fpsp_unimp() - handle "FP Unimplemented" exceptions            #
3815#       _real_fpu_disabled() - handle "FPU disabled" exceptions         #
3816#       _real_fline() - handle "FLINE" exceptions                       #
3817#       _imem_read_long() - read instruction longword                   #
3818#                                                                       #
3819# INPUT *************************************************************** #
3820#       - The system stack contains a "Line F Emulator" exception       #
3821#         stack frame.                                                  #
3822#                                                                       #
3823# OUTPUT ************************************************************** #
3824#       - The system stack is unchanged                                 #
3825#                                                                       #
3826# ALGORITHM *********************************************************** #
3827#       When a "Line F Emulator" exception occurs, there are 3 possible #
3828# exception types, denoted by the exception stack frame format number:  #
3829#       (1) FPU unimplemented instruction (6 word stack frame)          #
3830#       (2) FPU disabled (8 word stack frame)                           #
3831#       (3) Line F (4 word stack frame)                                 #
3832#                                                                       #
3833#       This module determines which and forks the flow off to the      #
3834# appropriate "callout" (for "disabled" and "Line F") or to the         #
3835# correct emulation code (for "FPU unimplemented").                     #
3836#       This code also must check for "fmovecr" instructions w/ a       #
3837# non-zero <ea> field. These may get flagged as "Line F" but should     #
3838# really be flagged as "FPU Unimplemented". (This is a "feature" on     #
3839# the '060.                                                             #
3840#                                                                       #
3841#########################################################################
3842
3843        global          _fpsp_fline
3844_fpsp_fline:
3845
3846# check to see if this exception is a "FP Unimplemented Instruction"
3847# exception. if so, branch directly to that handler's entry point.
3848        cmpi.w          0x6(%sp),&0x202c
3849        beq.l           _fpsp_unimp
3850
3851# check to see if the FPU is disabled. if so, jump to the OS entry
3852# point for that condition.
3853        cmpi.w          0x6(%sp),&0x402c
3854        beq.l           _real_fpu_disabled
3855
3856# the exception was an "F-Line Illegal" exception. we check to see
3857# if the F-Line instruction is an "fmovecr" w/ a non-zero <ea>. if
3858# so, convert the F-Line exception stack frame to an FP Unimplemented
3859# Instruction exception stack frame else branch to the OS entry
3860# point for the F-Line exception handler.
3861        link.w          %a6,&-LOCAL_SIZE        # init stack frame
3862
3863        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3864
3865        mov.l           EXC_PC(%a6),EXC_EXTWPTR(%a6)
3866        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3867        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3868        bsr.l           _imem_read_long         # fetch instruction words
3869
3870        bfextu          %d0{&0:&10},%d1         # is it an fmovecr?
3871        cmpi.w          %d1,&0x03c8
3872        bne.b           fline_fline             # no
3873
3874        bfextu          %d0{&16:&6},%d1         # is it an fmovecr?
3875        cmpi.b          %d1,&0x17
3876        bne.b           fline_fline             # no
3877
3878# it's an fmovecr w/ a non-zero <ea> that has entered through
3879# the F-Line Illegal exception.
3880# so, we need to convert the F-Line exception stack frame into an
3881# FP Unimplemented Instruction stack frame and jump to that entry
3882# point.
3883#
3884# but, if the FPU is disabled, then we need to jump to the FPU disabled
3885# entry point.
3886        movc            %pcr,%d0
3887        btst            &0x1,%d0
3888        beq.b           fline_fmovcr
3889
3890        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3891
3892        unlk            %a6
3893
3894        sub.l           &0x8,%sp                # make room for "Next PC", <ea>
3895        mov.w           0x8(%sp),(%sp)
3896        mov.l           0xa(%sp),0x2(%sp)       # move "Current PC"
3897        mov.w           &0x402c,0x6(%sp)
3898        mov.l           0x2(%sp),0xc(%sp)
3899        addq.l          &0x4,0x2(%sp)           # set "Next PC"
3900
3901        bra.l           _real_fpu_disabled
3902
3903fline_fmovcr:
3904        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3905
3906        unlk            %a6
3907
3908        fmov.l          0x2(%sp),%fpiar         # set current PC
3909        addq.l          &0x4,0x2(%sp)           # set Next PC
3910
3911        mov.l           (%sp),-(%sp)
3912        mov.l           0x8(%sp),0x4(%sp)
3913        mov.b           &0x20,0x6(%sp)
3914
3915        bra.l           _fpsp_unimp
3916
3917fline_fline:
3918        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3919
3920        unlk            %a6
3921
3922        bra.l           _real_fline
3923
3924#########################################################################
3925# XDEF **************************************************************** #
3926#       _fpsp_unimp(): 060FPSP entry point for FP "Unimplemented        #
3927#                      Instruction" exception.                          #
3928#                                                                       #
3929#       This handler should be the first code executed upon taking the  #
3930#       FP Unimplemented Instruction exception in an operating system.  #
3931#                                                                       #
3932# XREF **************************************************************** #
3933#       _imem_read_{word,long}() - read instruction word/longword       #
3934#       load_fop() - load src/dst ops from memory and/or FP regfile     #
3935#       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
3936#       tbl_trans - addr of table of emulation routines for trnscndls   #
3937#       _real_access() - "callout" for access error exception           #
3938#       _fpsp_done() - "callout" for exit; work all done                #
3939#       _real_trace() - "callout" for Trace enabled exception           #
3940#       smovcr() - emulate "fmovecr" instruction                        #
3941#       funimp_skew() - adjust fsave src ops to "incorrect" value       #
3942#       _ftrapcc() - emulate an "ftrapcc" instruction                   #
3943#       _fdbcc() - emulate an "fdbcc" instruction                       #
3944#       _fscc() - emulate an "fscc" instruction                         #
3945#       _real_trap() - "callout" for Trap exception                     #
3946#       _real_bsun() - "callout" for enabled Bsun exception             #
3947#                                                                       #
3948# INPUT *************************************************************** #
3949#       - The system stack contains the "Unimplemented Instr" stk frame #
3950#                                                                       #
3951# OUTPUT ************************************************************** #
3952#       If access error:                                                #
3953#       - The system stack is changed to an access error stack frame    #
3954#       If Trace exception enabled:                                     #
3955#       - The system stack is changed to a Trace exception stack frame  #
3956#       Else: (normal case)                                             #
3957#       - Correct result has been stored as appropriate                 #
3958#                                                                       #
3959# ALGORITHM *********************************************************** #
3960#       There are two main cases of instructions that may enter here to #
3961# be emulated: (1) the FPgen instructions, most of which were also      #
3962# unimplemented on the 040, and (2) "ftrapcc", "fscc", and "fdbcc".     #
3963#       For the first set, this handler calls the routine load_fop()    #
3964# to load the source and destination (for dyadic) operands to be used   #
3965# for instruction emulation. The correct emulation routine is then      #
3966# chosen by decoding the instruction type and indexing into an          #
3967# emulation subroutine index table. After emulation returns, this       #
3968# handler checks to see if an exception should occur as a result of the #
3969# FP instruction emulation. If so, then an FP exception of the correct  #
3970# type is inserted into the FPU state frame using the "frestore"        #
3971# instruction before exiting through _fpsp_done(). In either the        #
3972# exceptional or non-exceptional cases, we must check to see if the     #
3973# Trace exception is enabled. If so, then we must create a Trace        #
3974# exception frame from the current exception frame and exit through     #
3975# _real_trace().                                                        #
3976#       For "fdbcc", "ftrapcc", and "fscc", the emulation subroutines   #
3977# _fdbcc(), _ftrapcc(), and _fscc() respectively are used. All three    #
3978# may flag that a BSUN exception should be taken. If so, then the       #
3979# current exception stack frame is converted into a BSUN exception      #
3980# stack frame and an exit is made through _real_bsun(). If the          #
3981# instruction was "ftrapcc" and a Trap exception should result, a Trap  #
3982# exception stack frame is created from the current frame and an exit   #
3983# is made through _real_trap(). If a Trace exception is pending, then   #
3984# a Trace exception frame is created from the current frame and a jump  #
3985# is made to _real_trace(). Finally, if none of these conditions exist, #
3986# then the handler exits though the callout _fpsp_done().               #
3987#                                                                       #
3988#       In any of the above scenarios, if a _mem_read() or _mem_write() #
3989# "callout" returns a failing value, then an access error stack frame   #
3990# is created from the current stack frame and an exit is made through   #
3991# _real_access().                                                       #
3992#                                                                       #
3993#########################################################################
3994
3995#
3996# FP UNIMPLEMENTED INSTRUCTION STACK FRAME:
3997#
3998#       *****************
3999#       *               * => <ea> of fp unimp instr.
4000#       -      EA       -
4001#       *               *
4002#       *****************
4003#       * 0x2 *  0x02c  * => frame format and vector offset(vector #11)
4004#       *****************
4005#       *               *
4006#       -    Next PC    - => PC of instr to execute after exc handling
4007#       *               *
4008#       *****************
4009#       *      SR       * => SR at the time the exception was taken
4010#       *****************
4011#
4012# Note: the !NULL bit does not get set in the fsave frame when the
4013# machine encounters an fp unimp exception. Therefore, it must be set
4014# before leaving this handler.
4015#
4016        global          _fpsp_unimp
4017_fpsp_unimp:
4018
4019        link.w          %a6,&-LOCAL_SIZE        # init stack frame
4020
4021        movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
4022        fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
4023        fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1
4024
4025        btst            &0x5,EXC_SR(%a6)        # user mode exception?
4026        bne.b           funimp_s                # no; supervisor mode
4027
4028# save the value of the user stack pointer onto the stack frame
4029funimp_u:
4030        mov.l           %usp,%a0                # fetch user stack pointer
4031        mov.l           %a0,EXC_A7(%a6)         # store in stack frame
4032        bra.b           funimp_cont
4033
4034# store the value of the supervisor stack pointer BEFORE the exc occurred.
4035# old_sp is address just above stacked effective address.
4036funimp_s:
4037        lea             4+EXC_EA(%a6),%a0       # load old a7'
4038        mov.l           %a0,EXC_A7(%a6)         # store a7'
4039        mov.l           %a0,OLD_A7(%a6)         # make a copy
4040
4041funimp_cont:
4042
4043# the FPIAR holds the "current PC" of the faulting instruction.
4044        mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
4045
4046        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4047        addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
4048        bsr.l           _imem_read_long         # fetch the instruction words
4049        mov.l           %d0,EXC_OPWORD(%a6)
4050
4051############################################################################
4052
4053        fmov.l          &0x0,%fpcr              # clear FPCR
4054        fmov.l          &0x0,%fpsr              # clear FPSR
4055
4056        clr.b           SPCOND_FLG(%a6)         # clear "special case" flag
4057
4058# Divide the fp instructions into 8 types based on the TYPE field in
4059# bits 6-8 of the opword(classes 6,7 are undefined).
4060# (for the '060, only two types  can take this exception)
4061#       bftst           %d0{&7:&3}              # test TYPE
4062        btst            &22,%d0                 # type 0 or 1 ?
4063        bne.w           funimp_misc             # type 1
4064
4065#########################################
4066# TYPE == 0: General instructions       #
4067#########################################
4068funimp_gen:
4069
4070        clr.b           STORE_FLG(%a6)          # clear "store result" flag
4071
4072# clear the ccode byte and exception status byte
4073        andi.l          &0x00ff00ff,USER_FPSR(%a6)
4074
4075        bfextu          %d0{&16:&6},%d1         # extract upper 6 of cmdreg
4076        cmpi.b          %d1,&0x17               # is op an fmovecr?
4077        beq.w           funimp_fmovcr           # yes
4078
4079funimp_gen_op:
4080        bsr.l           _load_fop               # load
4081
4082        clr.l           %d0
4083        mov.b           FPCR_MODE(%a6),%d0      # fetch rnd mode
4084
4085        mov.b           1+EXC_CMDREG(%a6),%d1
4086        andi.w          &0x003f,%d1             # extract extension bits
4087        lsl.w           &0x3,%d1                # shift right 3 bits
4088        or.b            STAG(%a6),%d1           # insert src optag bits
4089
4090        lea             FP_DST(%a6),%a1         # pass dst ptr in a1
4091        lea             FP_SRC(%a6),%a0         # pass src ptr in a0
4092
4093        mov.w           (tbl_trans.w,%pc,%d1.w*2),%d1
4094        jsr             (tbl_trans.w,%pc,%d1.w*1) # emulate
4095
4096funimp_fsave:
4097        mov.b           FPCR_ENABLE(%a6),%d0    # fetch exceptions enabled
4098        bne.w           funimp_ena              # some are enabled
4099
4100funimp_store:
4101        bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # fetch Dn
4102        bsr.l           store_fpreg             # store result to fp regfile
4103
4104funimp_gen_exit:
4105        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
4106        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
4107        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
4108
4109funimp_gen_exit_cmp:
4110        cmpi.b          SPCOND_FLG(%a6),&mia7_flg # was the ea mode (sp)+ ?
4111        beq.b           funimp_gen_exit_a7      # yes
4112
4113        cmpi.b          SPCOND_FLG(%a6),&mda7_flg # was the ea mode -(sp) ?
4114        beq.b           funimp_gen_exit_a7      # yes
4115
4116funimp_gen_exit_cont:
4117        unlk            %a6
4118
4119funimp_gen_exit_cont2:
4120        btst            &0x7,(%sp)              # is trace on?
4121        beq.l           _fpsp_done              # no
4122
4123# this catches a problem with the case where an exception will be re-inserted
4124# into the machine. the frestore has already been executed...so, the fmov.l
4125# alone of the control register would trigger an unwanted exception.
4126# until I feel like fixing this, we'll sidestep the exception.
4127        fsave           -(%sp)
4128        fmov.l          %fpiar,0x14(%sp)        # "Current PC" is in FPIAR
4129        frestore        (%sp)+
4130        mov.w           &0x2024,0x6(%sp)        # stk fmt = 0x2; voff = 0x24
4131        bra.l           _real_trace
4132
4133funimp_gen_exit_a7:
4134        btst            &0x5,EXC_SR(%a6)        # supervisor or user mode?
4135        bne.b           funimp_gen_exit_a7_s    # supervisor
4136
4137        mov.l           %a0,-(%sp)
4138        mov.l           EXC_A7(%a6),%a0
4139        mov.l           %a0,%usp
4140        mov.l           (%sp)+,%a0
4141        bra.b           funimp_gen_exit_cont
4142
4143# if the instruction was executed from supervisor mode and the addressing
4144# mode was (a7)+, then the stack frame for the rte must be shifted "up"
4145# "n" bytes where "n" is the size of the src operand type.
4146# f<op>.{b,w,l,s,d,x,p}
4147funimp_gen_exit_a7_s:
4148        mov.l           %d0,-(%sp)              # save d0
4149        mov.l           EXC_A7(%a6),%d0         # load new a7'
4150        sub.l           OLD_A7(%a6),%d0         # subtract old a7'
4151        mov.l           0x2+EXC_PC(%a6),(0x2+EXC_PC,%a6,%d0) # shift stack frame
4152        mov.l           EXC_SR(%a6),(EXC_SR,%a6,%d0) # shift stack frame
4153        mov.w           %d0,EXC_SR(%a6)         # store incr number
4154        mov.l           (%sp)+,%d0              # restore d0
4155
4156        unlk            %a6
4157
4158        add.w           (%sp),%sp               # stack frame shifted
4159        bra.b           funimp_gen_exit_cont2
4160
4161######################
4162# fmovecr.x #ccc,fpn #
4163######################
4164funimp_fmovcr:
4165        clr.l           %d0
4166        mov.b           FPCR_MODE(%a6),%d0
4167        mov.b           1+EXC_CMDREG(%a6),%d1
4168        andi.l          &0x0000007f,%d1         # pass rom offset in d1
4169        bsr.l           smovcr
4170        bra.w           funimp_fsave
4171
4172#########################################################################
4173
4174#
4175# the user has enabled some exceptions. we figure not to see this too
4176# often so that's why it gets lower priority.
4177#
4178funimp_ena:
4179
4180# was an exception set that was also enabled?
4181        and.b           FPSR_EXCEPT(%a6),%d0    # keep only ones enabled and set
4182        bfffo           %d0{&24:&8},%d0         # find highest priority exception
4183        bne.b           funimp_exc              # at least one was set
4184
4185# no exception that was enabled was set BUT if we got an exact overflow
4186# and overflow wasn't enabled but inexact was (yech!) then this is
4187# an inexact exception; otherwise, return to normal non-exception flow.
4188        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur?
4189        beq.w           funimp_store            # no; return to normal flow
4190
4191# the overflow w/ exact result happened but was inexact set in the FPCR?
4192funimp_ovfl:
4193        btst            &inex2_bit,FPCR_ENABLE(%a6) # is inexact enabled?
4194        beq.w           funimp_store            # no; return to normal flow
4195        bra.b           funimp_exc_ovfl         # yes
4196
4197# some exception happened that was actually enabled.
4198# we'll insert this new exception into the FPU and then return.
4199funimp_exc:
4200        subi.l          &24,%d0                 # fix offset to be 0-8
4201        cmpi.b          %d0,&0x6                # is exception INEX?
4202        bne.b           funimp_exc_force        # no
4203
4204# the enabled exception was inexact. so, if it occurs with an overflow
4205# or underflow that was disabled, then we have to force an overflow or
4206# underflow frame. the eventual overflow or underflow handler will see that
4207# it's actually an inexact and act appropriately. this is the only easy
4208# way to have the EXOP available for the enabled inexact handler when
4209# a disabled overflow or underflow has also happened.
4210        btst            &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur?
4211        bne.b           funimp_exc_ovfl         # yes
4212        btst            &unfl_bit,FPSR_EXCEPT(%a6) # did underflow occur?
4213        bne.b           funimp_exc_unfl         # yes
4214
4215# force the fsave exception status bits to signal an exception of the
4216# appropriate type. don't forget to "skew" the source operand in case we
4217# "unskewed" the one the hardware initially gave us.
4218funimp_exc_force:
4219        mov.l           %d0,-(%sp)              # save d0
4220        bsr.l           funimp_skew             # check for special case
4221        mov.l           (%sp)+,%d0              # restore d0
4222        mov.w           (tbl_funimp_except.b,%pc,%d0.w*2),2+FP_SRC(%a6)
4223        bra.b           funimp_gen_exit2        # exit with frestore
4224
4225tbl_funimp_except:
4226        short           0xe002, 0xe006, 0xe004, 0xe005
4227        short           0xe003, 0xe002, 0xe001, 0xe001
4228
4229# insert an overflow frame
4230funimp_exc_ovfl:
4231        bsr.l           funimp_skew             # check for special case
4232        mov.w           &0xe005,2+FP_SRC(%a6)
4233        bra.b           funimp_gen_exit2
4234
4235# insert an underflow frame
4236funimp_exc_unfl:
4237        bsr.l           funimp_skew             # check for special case
4238        mov.w           &0xe003,2+FP_SRC(%a6)
4239
4240# this is the general exit point for an enabled exception that will be
4241# restored into the machine for the instruction just emulated.
4242funimp_gen_exit2:
4243        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
4244        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
4245        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
4246
4247        frestore        FP_SRC(%a6)             # insert exceptional status
4248
4249        bra.w           funimp_gen_exit_cmp
4250
4251############################################################################
4252
4253#
4254# TYPE == 1: FDB<cc>, FS<cc>, FTRAP<cc>
4255#
4256# These instructions were implemented on the '881/2 and '040 in hardware but
4257# are emulated in software on the '060.
4258#
4259funimp_misc:
4260        bfextu          %d0{&10:&3},%d1         # extract mode field
4261        cmpi.b          %d1,&0x1                # is it an fdb<cc>?
4262        beq.w           funimp_fdbcc            # yes
4263        cmpi.b          %d1,&0x7                # is it an fs<cc>?
4264        bne.w           funimp_fscc             # yes
4265        bfextu          %d0{&13:&3},%d1
4266        cmpi.b          %d1,&0x2                # is it an fs<cc>?
4267        blt.w           funimp_fscc             # yes
4268
4269#########################
4270# ftrap<cc>             #
4271# ftrap<cc>.w #<data>   #
4272# ftrap<cc>.l #<data>   #
4273#########################
4274funimp_ftrapcc:
4275
4276        bsr.l           _ftrapcc                # FTRAP<cc>()
4277
4278        cmpi.b          SPCOND_FLG(%a6),&fbsun_flg # is enabled bsun occurring?
4279        beq.w           funimp_bsun             # yes
4280
4281        cmpi.b          SPCOND_FLG(%a6),&ftrapcc_flg # should a trap occur?
4282        bne.w           funimp_done             # no
4283
4284#        FP UNIMP FRAME            TRAP  FRAME
4285#       *****************       *****************
4286#       **    <EA>     **       **  Current PC **
4287#       *****************       *****************
4288#       * 0x2 *  0x02c  *       * 0x2 *  0x01c  *
4289#       *****************       *****************
4290#       **   Next PC   **       **   Next PC   **
4291#       *****************       *****************
4292#       *      SR       *       *      SR       *
4293#       *****************       *****************
4294#           (6 words)               (6 words)
4295#
4296# the ftrapcc instruction should take a trap. so, here we must create a
4297# trap stack frame from an unimplemented fp instruction stack frame and
4298# jump to the user supplied entry point for the trap exception
4299funimp_ftrapcc_tp:
4300        mov.l           USER_FPIAR(%a6),EXC_EA(%a6) # Address = Current PC
4301        mov.w           &0x201c,EXC_VOFF(%a6)   # Vector Offset = 0x01c
4302
4303        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
4304        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
4305        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
4306
4307        unlk            %a6
4308        bra.l           _real_trap
4309
4310#########################
4311# fdb<cc> Dn,<label>    #
4312#########################
4313funimp_fdbcc:
4314
4315        mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4316        addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4317        bsr.l           _imem_read_word         # read displacement
4318
4319        tst.l           %d1                     # did ifetch fail?
4320        bne.w           funimp_iacc             # yes
4321
4322        ext.l           %d0                     # sign extend displacement
4323
4324        bsr.l           _fdbcc                  # FDB<cc>()
4325
4326        cmpi.b          SPCOND_FLG(%a6),&fbsun_flg # is enabled bsun occurring?
4327        beq.w           funimp_bsun
4328
4329        bra.w           funimp_done             # branch to finish
4330
4331#################
4332# fs<cc>.b <ea> #
4333#################
4334funimp_fscc:
4335
4336        bsr.l           _fscc                   # FS<cc>()
4337
4338# I am assuming here that an "fs<cc>.b -(An)" or "fs<cc>.b (An)+" instruction
4339# does not need to update "An" before taking a bsun exception.
4340        cmpi.b          SPCOND_FLG(%a6),&fbsun_flg # is enabled bsun occurring?
4341        beq.w           funimp_bsun
4342
4343        btst            &0x5,EXC_SR(%a6)        # yes; is it a user mode exception?
4344        bne.b           funimp_fscc_s           # no
4345
4346funimp_fscc_u:
4347        mov.l           EXC_A7(%a6),%a0         # yes; set new USP
4348        mov.l           %a0,%usp
4349        bra.w           funimp_done             # branch to finish
4350
4351# remember, I'm assuming that post-increment is bogus...(it IS!!!)
4352# so, the least significant WORD of the stacked effective address got
4353# overwritten by the "fs<cc> -(An)". We must shift the stack frame "down"
4354# so that the rte will work correctly without destroying the result.
4355# even though the operation size is byte, the stack ptr is decr by 2.
4356#
4357# remember, also, this instruction may be traced.
4358funimp_fscc_s:
4359        cmpi.b          SPCOND_FLG(%a6),&mda7_flg # was a7 modified?
4360        bne.w           funimp_done             # no
4361
4362        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
4363        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
4364        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
4365
4366        unlk            %a6
4367
4368        btst            &0x7,(%sp)              # is trace enabled?
4369        bne.b           funimp_fscc_s_trace     # yes
4370
4371        subq.l          &0x2,%sp
4372        mov.l           0x2(%sp),(%sp)          # shift SR,hi(PC) "down"
4373        mov.l           0x6(%sp),0x4(%sp)       # shift lo(PC),voff "down"
4374        bra.l           _fpsp_done
4375
4376funimp_fscc_s_trace:
4377        subq.l          &0x2,%sp
4378        mov.l           0x2(%sp),(%sp)          # shift SR,hi(PC) "down"
4379        mov.w           0x6(%sp),0x4(%sp)       # shift lo(PC)
4380        mov.w           &0x2024,0x6(%sp)        # fmt/voff = $2024
4381        fmov.l          %fpiar,0x8(%sp)         # insert "current PC"
4382
4383        bra.l           _real_trace
4384
4385#
4386# The ftrap<cc>, fs<cc>, or fdb<cc> is to take an enabled bsun. we must convert
4387# the fp unimplemented instruction exception stack frame into a bsun stack frame,
4388# restore a bsun exception into the machine, and branch to the user
4389# supplied bsun hook.
4390#
4391#        FP UNIMP FRAME            BSUN FRAME
4392#       *****************       *****************
4393#       **    <EA>     **       * 0x0 * 0x0c0   *
4394#       *****************       *****************
4395#       * 0x2 *  0x02c  *       ** Current PC  **
4396#       *****************       *****************
4397#       **   Next PC   **       *      SR       *
4398#       *****************       *****************
4399#       *      SR       *           (4 words)
4400#       *****************
4401#           (6 words)
4402#
4403funimp_bsun:
4404        mov.w           &0x00c0,2+EXC_EA(%a6)   # Fmt = 0x0; Vector Offset = 0x0c0
4405        mov.l           USER_FPIAR(%a6),EXC_VOFF(%a6) # PC = Current PC
4406        mov.w           EXC_SR(%a6),2+EXC_PC(%a6) # shift SR "up"
4407
4408        mov.w           &0xe000,2+FP_SRC(%a6)   # bsun exception enabled
4409
4410        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
4411        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
4412        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
4413
4414        frestore        FP_SRC(%a6)             # restore bsun exception
4415
4416        unlk            %a6
4417
4418        addq.l          &0x4,%sp                # erase sludge
4419
4420        bra.l           _real_bsun              # branch to user bsun hook
4421
4422#
4423# all ftrapcc/fscc/fdbcc processing has been completed. unwind the stack frame
4424# and return.
4425#
4426# as usual, we have to check for trace mode being on here. since instructions
4427# modifying the supervisor stack frame don't pass through here, this is a
4428# relatively easy task.
4429#
4430funimp_done:
4431        fmovm.x         EXC_FP0(%a6),&0xc0      # restore fp0-fp1
4432        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
4433        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
4434
4435        unlk            %a6
4436
4437        btst            &0x7,(%sp)              # is trace enabled?
4438        bne.b           funimp_trace            # yes
4439
4440        bra.l           _fpsp_done
4441
4442#        FP UNIMP FRAME           TRACE  FRAME
4443#       *****************       *****************
4444#       **    <EA>     **       **  Current PC **
4445#       *****************       *****************
4446#       * 0x2 *  0x02c  *       * 0x2 *  0x024  *
4447#       *****************       *****************
4448#       **   Next PC   **       **   Next PC   **
4449#       *****************       *****************
4450#       *      SR       *       *      SR       *
4451#       *****************       *****************
4452#           (6 words)               (6 words)
4453#
4454# the fscc instruction should take a trace trap. so, here we must create a
4455# trace stack frame from an unimplemented fp instruction stack frame and
4456# jump to the user supplied entry point for the trace exception
4457funimp_trace:
4458        fmov.l          %fpiar,0x8(%sp)         # current PC is in fpiar
4459        mov.b           &0x24,0x7(%sp)          # vector offset = 0x024
4460
4461        bra.l           _real_trace
4462
4463################################################################
4464
4465        global          tbl_trans
4466        swbeg           &0x1c0
4467tbl_trans:
4468        short           tbl_trans - tbl_trans   # $00-0 fmovecr all
4469        short           tbl_trans - tbl_trans   # $00-1 fmovecr all
4470        short           tbl_trans - tbl_trans   # $00-2 fmovecr all
4471        short           tbl_trans - tbl_trans   # $00-3 fmovecr all
4472        short           tbl_trans - tbl_trans   # $00-4 fmovecr all
4473        short           tbl_trans - tbl_trans   # $00-5 fmovecr all
4474        short           tbl_trans - tbl_trans   # $00-6 fmovecr all
4475        short           tbl_trans - tbl_trans   # $00-7 fmovecr all
4476
4477        short           tbl_trans - tbl_trans   # $01-0 fint norm
4478        short           tbl_trans - tbl_trans   # $01-1 fint zero
4479        short           tbl_trans - tbl_trans   # $01-2 fint inf
4480        short           tbl_trans - tbl_trans   # $01-3 fint qnan
4481        short           tbl_trans - tbl_trans   # $01-5 fint denorm
4482        short           tbl_trans - tbl_trans   # $01-4 fint snan
4483        short           tbl_trans - tbl_trans   # $01-6 fint unnorm
4484        short           tbl_trans - tbl_trans   # $01-7 ERROR
4485
4486        short           ssinh    - tbl_trans    # $02-0 fsinh norm
4487        short           src_zero - tbl_trans    # $02-1 fsinh zero
4488        short           src_inf  - tbl_trans    # $02-2 fsinh inf
4489        short           src_qnan - tbl_trans    # $02-3 fsinh qnan
4490        short           ssinhd   - tbl_trans    # $02-5 fsinh denorm
4491        short           src_snan - tbl_trans    # $02-4 fsinh snan
4492        short           tbl_trans - tbl_trans   # $02-6 fsinh unnorm
4493        short           tbl_trans - tbl_trans   # $02-7 ERROR
4494
4495        short           tbl_trans - tbl_trans   # $03-0 fintrz norm
4496        short           tbl_trans - tbl_trans   # $03-1 fintrz zero
4497        short           tbl_trans - tbl_trans   # $03-2 fintrz inf
4498        short           tbl_trans - tbl_trans   # $03-3 fintrz qnan
4499        short           tbl_trans - tbl_trans   # $03-5 fintrz denorm
4500        short           tbl_trans - tbl_trans   # $03-4 fintrz snan
4501        short           tbl_trans - tbl_trans   # $03-6 fintrz unnorm
4502        short           tbl_trans - tbl_trans   # $03-7 ERROR
4503
4504        short           tbl_trans - tbl_trans   # $04-0 fsqrt norm
4505        short           tbl_trans - tbl_trans   # $04-1 fsqrt zero
4506        short           tbl_trans - tbl_trans   # $04-2 fsqrt inf
4507        short           tbl_trans - tbl_trans   # $04-3 fsqrt qnan
4508        short           tbl_trans - tbl_trans   # $04-5 fsqrt denorm
4509        short           tbl_trans - tbl_trans   # $04-4 fsqrt snan
4510        short           tbl_trans - tbl_trans   # $04-6 fsqrt unnorm
4511        short           tbl_trans - tbl_trans   # $04-7 ERROR
4512
4513        short           tbl_trans - tbl_trans   # $05-0 ERROR
4514        short           tbl_trans - tbl_trans   # $05-1 ERROR
4515        short           tbl_trans - tbl_trans   # $05-2 ERROR
4516        short           tbl_trans - tbl_trans   # $05-3 ERROR
4517        short           tbl_trans - tbl_trans   # $05-4 ERROR
4518        short           tbl_trans - tbl_trans   # $05-5 ERROR
4519        short           tbl_trans - tbl_trans   # $05-6 ERROR
4520        short           tbl_trans - tbl_trans   # $05-7 ERROR
4521
4522        short           slognp1  - tbl_trans    # $06-0 flognp1 norm
4523        short           src_zero - tbl_trans    # $06-1 flognp1 zero
4524        short           sopr_inf - tbl_trans    # $06-2 flognp1 inf
4525        short           src_qnan - tbl_trans    # $06-3 flognp1 qnan
4526        short           slognp1d - tbl_trans    # $06-5 flognp1 denorm
4527        short           src_snan - tbl_trans    # $06-4 flognp1 snan
4528        short           tbl_trans - tbl_trans   # $06-6 flognp1 unnorm
4529        short           tbl_trans - tbl_trans   # $06-7 ERROR
4530
4531        short           tbl_trans - tbl_trans   # $07-0 ERROR
4532        short           tbl_trans - tbl_trans   # $07-1 ERROR
4533        short           tbl_trans - tbl_trans   # $07-2 ERROR
4534        short           tbl_trans - tbl_trans   # $07-3 ERROR
4535        short           tbl_trans - tbl_trans   # $07-4 ERROR
4536        short           tbl_trans - tbl_trans   # $07-5 ERROR
4537        short           tbl_trans - tbl_trans   # $07-6 ERROR
4538        short           tbl_trans - tbl_trans   # $07-7 ERROR
4539
4540        short           setoxm1  - tbl_trans    # $08-0 fetoxm1 norm
4541        short           src_zero - tbl_trans    # $08-1 fetoxm1 zero
4542        short           setoxm1i - tbl_trans    # $08-2 fetoxm1 inf
4543        short           src_qnan - tbl_trans    # $08-3 fetoxm1 qnan
4544        short           setoxm1d - tbl_trans    # $08-5 fetoxm1 denorm
4545        short           src_snan - tbl_trans    # $08-4 fetoxm1 snan
4546        short           tbl_trans - tbl_trans   # $08-6 fetoxm1 unnorm
4547        short           tbl_trans - tbl_trans   # $08-7 ERROR
4548
4549        short           stanh    - tbl_trans    # $09-0 ftanh norm
4550        short           src_zero - tbl_trans    # $09-1 ftanh zero
4551        short           src_one  - tbl_trans    # $09-2 ftanh inf
4552        short           src_qnan - tbl_trans    # $09-3 ftanh qnan
4553        short           stanhd   - tbl_trans    # $09-5 ftanh denorm
4554        short           src_snan - tbl_trans    # $09-4 ftanh snan
4555        short           tbl_trans - tbl_trans   # $09-6 ftanh unnorm
4556        short           tbl_trans - tbl_trans   # $09-7 ERROR
4557
4558        short           satan    - tbl_trans    # $0a-0 fatan norm
4559        short           src_zero - tbl_trans    # $0a-1 fatan zero
4560        short           spi_2    - tbl_trans    # $0a-2 fatan inf
4561        short           src_qnan - tbl_trans    # $0a-3 fatan qnan
4562        short           satand   - tbl_trans    # $0a-5 fatan denorm
4563        short           src_snan - tbl_trans    # $0a-4 fatan snan
4564        short           tbl_trans - tbl_trans   # $0a-6 fatan unnorm
4565        short           tbl_trans - tbl_trans   # $0a-7 ERROR
4566
4567        short           tbl_trans - tbl_trans   # $0b-0 ERROR
4568        short           tbl_trans - tbl_trans   # $0b-1 ERROR
4569        short           tbl_trans - tbl_trans   # $0b-2 ERROR
4570        short           tbl_trans - tbl_trans   # $0b-3 ERROR
4571        short           tbl_trans - tbl_trans   # $0b-4 ERROR
4572        short           tbl_trans - tbl_trans   # $0b-5 ERROR
4573        short           tbl_trans - tbl_trans   # $0b-6 ERROR
4574        short           tbl_trans - tbl_trans   # $0b-7 ERROR
4575
4576        short           sasin    - tbl_trans    # $0c-0 fasin norm
4577        short           src_zero - tbl_trans    # $0c-1 fasin zero
4578        short           t_operr  - tbl_trans    # $0c-2 fasin inf
4579        short           src_qnan - tbl_trans    # $0c-3 fasin qnan
4580        short           sasind   - tbl_trans    # $0c-5 fasin denorm
4581        short           src_snan - tbl_trans    # $0c-4 fasin snan
4582        short           tbl_trans - tbl_trans   # $0c-6 fasin unnorm
4583        short           tbl_trans - tbl_trans   # $0c-7 ERROR
4584
4585        short           satanh   - tbl_trans    # $0d-0 fatanh norm
4586        short           src_zero - tbl_trans    # $0d-1 fatanh zero
4587        short           t_operr  - tbl_trans    # $0d-2 fatanh inf
4588        short           src_qnan - tbl_trans    # $0d-3 fatanh qnan
4589        short           satanhd  - tbl_trans    # $0d-5 fatanh denorm
4590        short           src_snan - tbl_trans    # $0d-4 fatanh snan
4591        short           tbl_trans - tbl_trans   # $0d-6 fatanh unnorm
4592        short           tbl_trans - tbl_trans   # $0d-7 ERROR
4593
4594        short           ssin     - tbl_trans    # $0e-0 fsin norm
4595        short           src_zero - tbl_trans    # $0e-1 fsin zero
4596        short           t_operr  - tbl_trans    # $0e-2 fsin inf
4597        short           src_qnan - tbl_trans    # $0e-3 fsin qnan
4598        short           ssind    - tbl_trans    # $0e-5 fsin denorm
4599        short           src_snan - tbl_trans    # $0e-4 fsin snan
4600        short           tbl_trans - tbl_trans   # $0e-6 fsin unnorm
4601        short           tbl_trans - tbl_trans   # $0e-7 ERROR
4602
4603        short           stan     - tbl_trans    # $0f-0 ftan norm
4604        short           src_zero - tbl_trans    # $0f-1 ftan zero
4605        short           t_operr  - tbl_trans    # $0f-2 ftan inf
4606        short           src_qnan - tbl_trans    # $0f-3 ftan qnan
4607        short           stand    - tbl_trans    # $0f-5 ftan denorm
4608        short           src_snan - tbl_trans    # $0f-4 ftan snan
4609        short           tbl_trans - tbl_trans   # $0f-6 ftan unnorm
4610        short           tbl_trans - tbl_trans   # $0f-7 ERROR
4611
4612        short           setox    - tbl_trans    # $10-0 fetox norm
4613        short           ld_pone  - tbl_trans    # $10-1 fetox zero
4614        short           szr_inf  - tbl_trans    # $10-2 fetox inf
4615        short           src_qnan - tbl_trans    # $10-3 fetox qnan
4616        short           setoxd   - tbl_trans    # $10-5 fetox denorm
4617        short           src_snan - tbl_trans    # $10-4 fetox snan
4618        short           tbl_trans - tbl_trans   # $10-6 fetox unnorm
4619        short           tbl_trans - tbl_trans   # $10-7 ERROR
4620
4621        short           stwotox  - tbl_trans    # $11-0 ftwotox norm
4622        short           ld_pone  - tbl_trans    # $11-1 ftwotox zero
4623        short           szr_inf  - tbl_trans    # $11-2 ftwotox inf
4624        short           src_qnan - tbl_trans    # $11-3 ftwotox qnan
4625        short           stwotoxd - tbl_trans    # $11-5 ftwotox denorm
4626        short           src_snan - tbl_trans    # $11-4 ftwotox snan
4627        short           tbl_trans - tbl_trans   # $11-6 ftwotox unnorm
4628        short           tbl_trans - tbl_trans   # $11-7 ERROR
4629
4630        short           stentox  - tbl_trans    # $12-0 ftentox norm
4631        short           ld_pone  - tbl_trans    # $12-1 ftentox zero
4632        short           szr_inf  - tbl_trans    # $12-2 ftentox inf
4633        short           src_qnan - tbl_trans    # $12-3 ftentox qnan
4634        short           stentoxd - tbl_trans    # $12-5 ftentox denorm
4635        short           src_snan - tbl_trans    # $12-4 ftentox snan
4636        short           tbl_trans - tbl_trans   # $12-6 ftentox unnorm
4637        short           tbl_trans - tbl_trans   # $12-7 ERROR
4638
4639        short           tbl_trans - tbl_trans   # $13-0 ERROR
4640        short           tbl_trans - tbl_trans   # $13-1 ERROR
4641        short           tbl_trans - tbl_trans   # $13-2 ERROR
4642        short           tbl_trans - tbl_trans   # $13-3 ERROR
4643        short           tbl_trans - tbl_trans   # $13-4 ERROR
4644        short           tbl_trans - tbl_trans   # $13-5 ERROR
4645        short           tbl_trans - tbl_trans   # $13-6 ERROR
4646        short           tbl_trans - tbl_trans   # $13-7 ERROR
4647
4648        short           slogn    - tbl_trans    # $14-0 flogn norm
4649        short           t_dz2    - tbl_trans    # $14-1 flogn zero
4650        short           sopr_inf - tbl_trans    # $14-2 flogn inf
4651        short           src_qnan - tbl_trans    # $14-3 flogn qnan
4652        short           slognd   - tbl_trans    # $14-5 flogn denorm
4653        short           src_snan - tbl_trans    # $14-4 flogn snan
4654        short           tbl_trans - tbl_trans   # $14-6 flogn unnorm
4655        short           tbl_trans - tbl_trans   # $14-7 ERROR
4656
4657        short           slog10   - tbl_trans    # $15-0 flog10 norm
4658        short           t_dz2    - tbl_trans    # $15-1 flog10 zero
4659        short           sopr_inf - tbl_trans    # $15-2 flog10 inf
4660        short           src_qnan - tbl_trans    # $15-3 flog10 qnan
4661        short           slog10d  - tbl_trans    # $15-5 flog10 denorm
4662        short           src_snan - tbl_trans    # $15-4 flog10 snan
4663        short           tbl_trans - tbl_trans   # $15-6 flog10 unnorm
4664        short           tbl_trans - tbl_trans   # $15-7 ERROR
4665
4666        short           slog2    - tbl_trans    # $16-0 flog2 norm
4667        short           t_dz2    - tbl_trans    # $16-1 flog2 zero
4668        short           sopr_inf - tbl_trans    # $16-2 flog2 inf
4669        short           src_qnan - tbl_trans    # $16-3 flog2 qnan
4670        short           slog2d   - tbl_trans    # $16-5 flog2 denorm
4671        short           src_snan - tbl_trans    # $16-4 flog2 snan
4672        short           tbl_trans - tbl_trans   # $16-6 flog2 unnorm
4673        short           tbl_trans - tbl_trans   # $16-7 ERROR
4674
4675        short           tbl_trans - tbl_trans   # $17-0 ERROR
4676        short           tbl_trans - tbl_trans   # $17-1 ERROR
4677        short           tbl_trans - tbl_trans   # $17-2 ERROR
4678        short           tbl_trans - tbl_trans   # $17-3 ERROR
4679        short           tbl_trans - tbl_trans   # $17-4 ERROR
4680        short           tbl_trans - tbl_trans   # $17-5 ERROR
4681        short           tbl_trans - tbl_trans   # $17-6 ERROR
4682        short           tbl_trans - tbl_trans   # $17-7 ERROR
4683
4684        short           tbl_trans - tbl_trans   # $18-0 fabs norm
4685        short           tbl_trans - tbl_trans   # $18-1 fabs zero
4686        short           tbl_trans - tbl_trans   # $18-2 fabs inf
4687        short           tbl_trans - tbl_trans   # $18-3 fabs qnan
4688        short           tbl_trans - tbl_trans   # $18-5 fabs denorm
4689        short           tbl_trans - tbl_trans   # $18-4 fabs snan
4690        short           tbl_trans - tbl_trans   # $18-6 fabs unnorm
4691        short           tbl_trans - tbl_trans   # $18-7 ERROR
4692
4693        short           scosh    - tbl_trans    # $19-0 fcosh norm
4694        short           ld_pone  - tbl_trans    # $19-1 fcosh zero
4695        short           ld_pinf  - tbl_trans    # $19-2 fcosh inf
4696        short           src_qnan - tbl_trans    # $19-3 fcosh qnan
4697        short           scoshd   - tbl_trans    # $19-5 fcosh denorm
4698        short           src_snan - tbl_trans    # $19-4 fcosh snan
4699        short           tbl_trans - tbl_trans   # $19-6 fcosh unnorm
4700        short           tbl_trans - tbl_trans   # $19-7 ERROR
4701
4702        short           tbl_trans - tbl_trans   # $1a-0 fneg norm
4703        short           tbl_trans - tbl_trans   # $1a-1 fneg zero
4704        short           tbl_trans - tbl_trans   # $1a-2 fneg inf
4705        short           tbl_trans - tbl_trans   # $1a-3 fneg qnan
4706        short           tbl_trans - tbl_trans   # $1a-5 fneg denorm
4707        short           tbl_trans - tbl_trans   # $1a-4 fneg snan
4708        short           tbl_trans - tbl_trans   # $1a-6 fneg unnorm
4709        short           tbl_trans - tbl_trans   # $1a-7 ERROR
4710
4711        short           tbl_trans - tbl_trans   # $1b-0 ERROR
4712        short           tbl_trans - tbl_trans   # $1b-1 ERROR
4713        short           tbl_trans - tbl_trans   # $1b-2 ERROR
4714        short           tbl_trans - tbl_trans   # $1b-3 ERROR
4715        short           tbl_trans - tbl_trans   # $1b-4 ERROR
4716        short           tbl_trans - tbl_trans   # $1b-5 ERROR
4717        short           tbl_trans - tbl_trans   # $1b-6 ERROR
4718        short           tbl_trans - tbl_trans   # $1b-7 ERROR
4719
4720        short           sacos    - tbl_trans    # $1c-0 facos norm
4721        short           ld_ppi2  - tbl_trans    # $1c-1 facos zero
4722        short           t_operr  - tbl_trans    # $1c-2 facos inf
4723        short           src_qnan - tbl_trans    # $1c-3 facos qnan
4724        short           sacosd   - tbl_trans    # $1c-5 facos denorm
4725        short           src_snan - tbl_trans    # $1c-4 facos snan
4726        short           tbl_trans - tbl_trans   # $1c-6 facos unnorm
4727        short           tbl_trans - tbl_trans   # $1c-7 ERROR
4728
4729        short           scos     - tbl_trans    # $1d-0 fcos norm
4730        short           ld_pone  - tbl_trans    # $1d-1 fcos zero
4731        short           t_operr  - tbl_trans    # $1d-2 fcos inf
4732        short           src_qnan - tbl_trans    # $1d-3 fcos qnan
4733        short           scosd    - tbl_trans    # $1d-5 fcos denorm
4734        short           src_snan - tbl_trans    # $1d-4 fcos snan
4735        short           tbl_trans - tbl_trans   # $1d-6 fcos unnorm
4736        short           tbl_trans - tbl_trans   # $1d-7 ERROR
4737
4738        short           sgetexp  - tbl_trans    # $1e-0 fgetexp norm
4739        short           src_zero - tbl_trans    # $1e-1 fgetexp zero
4740        short           t_operr  - tbl_trans    # $1e-2 fgetexp inf
4741        short           src_qnan - tbl_trans    # $1e-3 fgetexp qnan
4742        short           sgetexpd - tbl_trans    # $1e-5 fgetexp denorm
4743        short           src_snan - tbl_trans    # $1e-4 fgetexp snan
4744        short           tbl_trans - tbl_trans   # $1e-6 fgetexp unnorm
4745        short           tbl_trans - tbl_trans   # $1e-7 ERROR
4746
4747        short           sgetman  - tbl_trans    # $1f-0 fgetman norm
4748        short           src_zero - tbl_trans    # $1f-1 fgetman zero
4749        short           t_operr  - tbl_trans    # $1f-2 fgetman inf
4750        short           src_qnan - tbl_trans    # $1f-3 fgetman qnan
4751        short           sgetmand - tbl_trans    # $1f-5 fgetman denorm
4752        short           src_snan - tbl_trans    # $1f-4 fgetman snan
4753        short           tbl_trans - tbl_trans   # $1f-6 fgetman unnorm
4754        short           tbl_trans - tbl_trans   # $1f-7 ERROR
4755
4756        short           tbl_trans - tbl_trans   # $20-0 fdiv norm
4757        short           tbl_trans - tbl_trans   # $20-1 fdiv zero
4758        short           tbl_trans - tbl_trans   # $20-2 fdiv inf
4759        short           tbl_trans - tbl_trans   # $20-3 fdiv qnan
4760        short           tbl_trans - tbl_trans   # $20-5 fdiv denorm
4761        short           tbl_trans - tbl_trans   # $20-4 fdiv snan
4762        short           tbl_trans - tbl_trans   # $20-6 fdiv unnorm
4763        short           tbl_trans - tbl_trans   # $20-7 ERROR
4764
4765        short           smod_snorm - tbl_trans  # $21-0 fmod norm
4766        short           smod_szero - tbl_trans  # $21-1 fmod zero
4767        short           smod_sinf - tbl_trans   # $21-2 fmod inf
4768        short           sop_sqnan - tbl_trans   # $21-3 fmod qnan
4769        short           smod_sdnrm - tbl_trans  # $21-5 fmod denorm
4770        short           sop_ssnan - tbl_trans   # $21-4 fmod snan
4771        short           tbl_trans - tbl_trans   # $21-6 fmod unnorm
4772        short           tbl_trans - tbl_trans   # $21-7 ERROR
4773
4774        short           tbl_trans - tbl_trans   # $22-0 fadd norm
4775        short           tbl_trans - tbl_trans   # $22-1 fadd zero
4776        short           tbl_trans - tbl_trans   # $22-2 fadd inf
4777        short           tbl_trans - tbl_trans   # $22-3 fadd qnan
4778        short           tbl_trans - tbl_trans   # $22-5 fadd denorm
4779        short           tbl_trans - tbl_trans   # $22-4 fadd snan
4780        short           tbl_trans - tbl_trans   # $22-6 fadd unnorm
4781        short           tbl_trans - tbl_trans   # $22-7 ERROR
4782
4783        short           tbl_trans - tbl_trans   # $23-0 fmul norm
4784        short           tbl_trans - tbl_trans   # $23-1 fmul zero
4785        short           tbl_trans - tbl_trans   # $23-2 fmul inf
4786        short           tbl_trans - tbl_trans   # $23-3 fmul qnan
4787        short           tbl_trans - tbl_trans   # $23-5 fmul denorm
4788        short           tbl_trans - tbl_trans   # $23-4 fmul snan
4789        short           tbl_trans - tbl_trans   # $23-6 fmul unnorm
4790        short           tbl_trans - tbl_trans   # $23-7 ERROR
4791
4792        short           tbl_trans - tbl_trans   # $24-0 fsgldiv norm
4793        short           tbl_trans - tbl_trans   # $24-1 fsgldiv zero
4794        short           tbl_trans - tbl_trans   # $24-2 fsgldiv inf
4795        short           tbl_trans - tbl_trans   # $24-3 fsgldiv qnan
4796        short           tbl_trans - tbl_trans   # $24-5 fsgldiv denorm
4797        short           tbl_trans - tbl_trans   # $24-4 fsgldiv snan
4798        short           tbl_trans - tbl_trans   # $24-6 fsgldiv unnorm
4799        short           tbl_trans - tbl_trans   # $24-7 ERROR
4800
4801        short           srem_snorm - tbl_trans  # $25-0 frem norm
4802        short           srem_szero - tbl_trans  # $25-1 frem zero
4803        short           srem_sinf - tbl_trans   # $25-2 frem inf
4804        short           sop_sqnan - tbl_trans   # $25-3 frem qnan
4805        short           srem_sdnrm - tbl_trans  # $25-5 frem denorm
4806        short           sop_ssnan - tbl_trans   # $25-4 frem snan
4807        short           tbl_trans - tbl_trans   # $25-6 frem unnorm
4808        short           tbl_trans - tbl_trans   # $25-7 ERROR
4809
4810        short           sscale_snorm - tbl_trans # $26-0 fscale norm
4811        short           sscale_szero - tbl_trans # $26-1 fscale zero
4812        short           sscale_sinf - tbl_trans # $26-2 fscale inf
4813        short           sop_sqnan - tbl_trans   # $26-3 fscale qnan
4814        short           sscale_sdnrm - tbl_trans # $26-5 fscale denorm
4815        short           sop_ssnan - tbl_trans   # $26-4 fscale snan
4816        short           tbl_trans - tbl_trans   # $26-6 fscale unnorm
4817        short           tbl_trans - tbl_trans   # $26-7 ERROR
4818
4819        short           tbl_trans - tbl_trans   # $27-0 fsglmul norm
4820        short           tbl_trans - tbl_trans   # $27-1 fsglmul zero
4821        short           tbl_trans - tbl_trans   # $27-2 fsglmul inf
4822        short           tbl_trans - tbl_trans   # $27-3 fsglmul qnan
4823        short           tbl_trans - tbl_trans   # $27-5 fsglmul denorm
4824        short           tbl_trans - tbl_trans   # $27-4 fsglmul snan
4825        short           tbl_trans - tbl_trans   # $27-6 fsglmul unnorm
4826        short           tbl_trans - tbl_trans   # $27-7 ERROR
4827
4828        short           tbl_trans - tbl_trans   # $28-0 fsub norm
4829        short           tbl_trans - tbl_trans   # $28-1 fsub zero
4830        short           tbl_trans - tbl_trans   # $28-2 fsub inf
4831        short           tbl_trans - tbl_trans   # $28-3 fsub qnan
4832        short           tbl_trans - tbl_trans   # $28-5 fsub denorm
4833        short           tbl_trans - tbl_trans   # $28-4 fsub snan
4834        short           tbl_trans - tbl_trans   # $28-6 fsub unnorm
4835        short           tbl_trans - tbl_trans   # $28-7 ERROR
4836
4837        short           tbl_trans - tbl_trans   # $29-0 ERROR
4838        short           tbl_trans - tbl_trans   # $29-1 ERROR
4839        short           tbl_trans - tbl_trans   # $29-2 ERROR
4840        short           tbl_trans - tbl_trans   # $29-3 ERROR
4841        short           tbl_trans - tbl_trans   # $29-4 ERROR
4842        short           tbl_trans - tbl_trans   # $29-5 ERROR
4843        short           tbl_trans - tbl_trans   # $29-6 ERROR
4844        short           tbl_trans - tbl_trans   # $29-7 ERROR
4845
4846        short           tbl_trans - tbl_trans   # $2a-0 ERROR
4847        short           tbl_trans - tbl_trans   # $2a-1 ERROR
4848        short           tbl_trans - tbl_trans   # $2a-2 ERROR
4849        short           tbl_trans - tbl_trans   # $2a-3 ERROR
4850        short           tbl_trans - tbl_trans   # $2a-4 ERROR
4851        short           tbl_trans - tbl_trans   # $2a-5 ERROR
4852        short           tbl_trans - tbl_trans   # $2a-6 ERROR
4853        short           tbl_trans - tbl_trans   # $2a-7 ERROR
4854
4855        short           tbl_trans - tbl_trans   # $2b-0 ERROR
4856        short           tbl_trans - tbl_trans   # $2b-1 ERROR
4857        short           tbl_trans - tbl_trans   # $2b-2 ERROR
4858        short           tbl_trans - tbl_trans   # $2b-3 ERROR
4859        short           tbl_trans - tbl_trans   # $2b-4 ERROR
4860        short           tbl_trans - tbl_trans   # $2b-5 ERROR
4861        short           tbl_trans - tbl_trans   # $2b-6 ERROR
4862        short           tbl_trans - tbl_trans   # $2b-7 ERROR
4863
4864        short           tbl_trans - tbl_trans   # $2c-0 ERROR
4865        short           tbl_trans - tbl_trans   # $2c-1 ERROR
4866        short           tbl_trans - tbl_trans   # $2c-2 ERROR
4867        short           tbl_trans - tbl_trans   # $2c-3 ERROR
4868        short           tbl_trans - tbl_trans   # $2c-4 ERROR
4869        short           tbl_trans - tbl_trans   # $2c-5 ERROR
4870        short           tbl_trans - tbl_trans   # $2c-6 ERROR
4871        short           tbl_trans - tbl_trans   # $2c-7 ERROR
4872
4873        short           tbl_trans - tbl_trans   # $2d-0 ERROR
4874        short           tbl_trans - tbl_trans   # $2d-1 ERROR
4875        short           tbl_trans - tbl_trans   # $2d-2 ERROR
4876        short           tbl_trans - tbl_trans   # $2d-3 ERROR
4877        short           tbl_trans - tbl_trans   # $2d-4 ERROR
4878        short           tbl_trans - tbl_trans   # $2d-5 ERROR
4879        short           tbl_trans - tbl_trans   # $2d-6 ERROR
4880        short           tbl_trans - tbl_trans   # $2d-7 ERROR
4881
4882        short           tbl_trans - tbl_trans   # $2e-0 ERROR
4883        short           tbl_trans - tbl_trans   # $2e-1 ERROR
4884        short           tbl_trans - tbl_trans   # $2e-2 ERROR
4885        short           tbl_trans - tbl_trans   # $2e-3 ERROR
4886        short           tbl_trans - tbl_trans   # $2e-4 ERROR
4887        short           tbl_trans - tbl_trans   # $2e-5 ERROR
4888        short           tbl_trans - tbl_trans   # $2e-6 ERROR
4889        short           tbl_trans - tbl_trans   # $2e-7 ERROR
4890
4891        short           tbl_trans - tbl_trans   # $2f-0 ERROR
4892        short           tbl_trans - tbl_trans   # $2f-1 ERROR
4893        short           tbl_trans - tbl_trans   # $2f-2 ERROR
4894        short           tbl_trans - tbl_trans   # $2f-3 ERROR
4895        short           tbl_trans - tbl_trans   # $2f-4 ERROR
4896        short           tbl_trans - tbl_trans   # $2f-5 ERROR
4897        short           tbl_trans - tbl_trans   # $2f-6 ERROR
4898        short           tbl_trans - tbl_trans   # $2f-7 ERROR
4899
4900        short           ssincos  - tbl_trans    # $30-0 fsincos norm
4901        short           ssincosz - tbl_trans    # $30-1 fsincos zero
4902        short           ssincosi - tbl_trans    # $30-2 fsincos inf
4903        short           ssincosqnan - tbl_trans # $30-3 fsincos qnan
4904        short           ssincosd - tbl_trans    # $30-5 fsincos denorm
4905        short           ssincossnan - tbl_trans # $30-4 fsincos snan
4906        short           tbl_trans - tbl_trans   # $30-6 fsincos unnorm
4907        short           tbl_trans - tbl_trans   # $30-7 ERROR
4908
4909        short           ssincos  - tbl_trans    # $31-0 fsincos norm
4910        short           ssincosz - tbl_trans    # $31-1 fsincos zero
4911        short           ssincosi - tbl_trans    # $31-2 fsincos inf
4912        short           ssincosqnan - tbl_trans # $31-3 fsincos qnan
4913        short           ssincosd - tbl_trans    # $31-5 fsincos denorm
4914        short           ssincossnan - tbl_trans # $31-4 fsincos snan
4915        short           tbl_trans - tbl_trans   # $31-6 fsincos unnorm
4916        short           tbl_trans - tbl_trans   # $31-7 ERROR
4917
4918        short           ssincos  - tbl_trans    # $32-0 fsincos norm
4919        short           ssincosz - tbl_trans    # $32-1 fsincos zero
4920        short           ssincosi - tbl_trans    # $32-2 fsincos inf
4921        short           ssincosqnan - tbl_trans # $32-3 fsincos qnan
4922        short           ssincosd - tbl_trans    # $32-5 fsincos denorm
4923        short           ssincossnan - tbl_trans # $32-4 fsincos snan
4924        short           tbl_trans - tbl_trans   # $32-6 fsincos unnorm
4925        short           tbl_trans - tbl_trans   # $32-7 ERROR
4926
4927        short           ssincos  - tbl_trans    # $33-0 fsincos norm
4928        short           ssincosz - tbl_trans    # $33-1 fsincos zero
4929        short           ssincosi - tbl_trans    # $33-2 fsincos inf
4930        short           ssincosqnan - tbl_trans # $33-3 fsincos qnan
4931        short           ssincosd - tbl_trans    # $33-5 fsincos denorm
4932        short           ssincossnan - tbl_trans # $33-4 fsincos snan
4933        short           tbl_trans - tbl_trans   # $33-6 fsincos unnorm
4934        short           tbl_trans - tbl_trans   # $33-7 ERROR
4935
4936        short           ssincos  - tbl_trans    # $34-0 fsincos norm
4937        short           ssincosz - tbl_trans    # $34-1 fsincos zero
4938        short           ssincosi - tbl_trans    # $34-2 fsincos inf
4939        short           ssincosqnan - tbl_trans # $34-3 fsincos qnan
4940        short           ssincosd - tbl_trans    # $34-5 fsincos denorm
4941        short           ssincossnan - tbl_trans # $34-4 fsincos snan
4942        short           tbl_trans - tbl_trans   # $34-6 fsincos unnorm
4943        short           tbl_trans - tbl_trans   # $34-7 ERROR
4944
4945        short           ssincos  - tbl_trans    # $35-0 fsincos norm
4946        short           ssincosz - tbl_trans    # $35-1 fsincos zero
4947        short           ssincosi - tbl_trans    # $35-2 fsincos inf
4948        short           ssincosqnan - tbl_trans # $35-3 fsincos qnan
4949        short           ssincosd - tbl_trans    # $35-5 fsincos denorm
4950        short           ssincossnan - tbl_trans # $35-4 fsincos snan
4951        short           tbl_trans - tbl_trans   # $35-6 fsincos unnorm
4952        short           tbl_trans - tbl_trans   # $35-7 ERROR
4953
4954        short           ssincos  - tbl_trans    # $36-0 fsincos norm
4955        short           ssincosz - tbl_trans    # $36-1 fsincos zero
4956        short           ssincosi - tbl_trans    # $36-2 fsincos inf
4957        short           ssincosqnan - tbl_trans # $36-3 fsincos qnan
4958        short           ssincosd - tbl_trans    # $36-5 fsincos denorm
4959        short           ssincossnan - tbl_trans # $36-4 fsincos snan
4960        short           tbl_trans - tbl_trans   # $36-6 fsincos unnorm
4961        short           tbl_trans - tbl_trans   # $36-7 ERROR
4962
4963        short           ssincos  - tbl_trans    # $37-0 fsincos norm
4964        short           ssincosz - tbl_trans    # $37-1 fsincos zero
4965        short           ssincosi - tbl_trans    # $37-2 fsincos inf
4966        short           ssincosqnan - tbl_trans # $37-3 fsincos qnan
4967        short           ssincosd - tbl_trans    # $37-5 fsincos denorm
4968        short           ssincossnan - tbl_trans # $37-4 fsincos snan
4969        short           tbl_trans - tbl_trans   # $37-6 fsincos unnorm
4970        short           tbl_trans - tbl_trans   # $37-7 ERROR
4971
4972##########
4973
4974# the instruction fetch access for the displacement word for the
4975# fdbcc emulation failed. here, we create an access error frame
4976# from the current frame and branch to _real_access().
4977funimp_iacc:
4978        movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
4979        fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
4980        fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
4981
4982        mov.l           USER_FPIAR(%a6),EXC_PC(%a6) # store current PC
4983
4984        unlk            %a6
4985
4986        mov.l           (%sp),-(%sp)            # store SR,hi(PC)
4987        mov.w           0x8(%sp),0x4(%sp)       # store lo(PC)
4988        mov.w           &0x4008,0x6(%sp)        # store voff
4989        mov.l           0x2(%sp),0x8(%sp)       # store EA
4990        mov.l           &0x09428001,0xc(%sp)    # store FSLW
4991
4992        btst            &0x5,(%sp)              # user or supervisor mode?
4993        beq.b           funimp_iacc_end         # user
4994        bset            &0x2,0xd(%sp)           # set supervisor TM bit
4995
4996funimp_iacc_end:
4997        bra.l           _real_access
4998
4999#########################################################################
5000# ssin():     computes the sine of a normalized input                   #
5001# ssind():    computes the sine of a denormalized input                 #
5002# scos():     computes the cosine of a normalized input                 #
5003# scosd():    computes the cosine of a denormalized input               #
5004# ssincos():  computes the sine and cosine of a normalized input        #
5005# ssincosd(): computes the sine and cosine of a denormalized input      #
5006#                                                                       #
5007# INPUT *************************************************************** #
5008#       a0 = pointer to extended precision input                        #
5009#       d0 = round precision,mode                                       #
5010#                                                                       #
5011# OUTPUT ************************************************************** #
5012#       fp0 = sin(X) or cos(X)                                          #
5013#                                                                       #
5014#    For ssincos(X):                                                    #
5015#       fp0 = sin(X)                                                    #
5016#       fp1 = cos(X)                                                    #
5017#                                                                       #
5018# ACCURACY and MONOTONICITY ******************************************* #
5019#       The returned result is within 1 ulp in 64 significant bit, i.e. #
5020#       within 0.5001 ulp to 53 bits if the result is subsequently      #
5021#       rounded to double precision. The result is provably monotonic   #
5022#       in double precision.                                            #
5023#                                                                       #
5024# ALGORITHM *********************************************************** #
5025#                                                                       #
5026#       SIN and COS:                                                    #
5027#       1. If SIN is invoked, set AdjN := 0; otherwise, set AdjN := 1.  #
5028#                                                                       #
5029#       2. If |X| >= 15Pi or |X| < 2**(-40), go to 7.                   #
5030#                                                                       #
5031#       3. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let        #
5032#               k = N mod 4, so in particular, k = 0,1,2,or 3.          #
5033#               Overwrite k by k := k + AdjN.                           #
5034#                                                                       #
5035#       4. If k is even, go to 6.                                       #
5036#                                                                       #
5037#       5. (k is odd) Set j := (k-1)/2, sgn := (-1)**j.                 #
5038#               Return sgn*cos(r) where cos(r) is approximated by an    #
5039#               even polynomial in r, 1 + r*r*(B1+s*(B2+ ... + s*B8)),  #
5040#               s = r*r.                                                #
5041#               Exit.                                                   #
5042#                                                                       #
5043#       6. (k is even) Set j := k/2, sgn := (-1)**j. Return sgn*sin(r)  #
5044#               where sin(r) is approximated by an odd polynomial in r  #
5045#               r + r*s*(A1+s*(A2+ ... + s*A7)),        s = r*r.        #
5046#               Exit.                                                   #
5047#                                                                       #
5048#       7. If |X| > 1, go to 9.                                         #
5049#                                                                       #
5050#       8. (|X|<2**(-40)) If SIN is invoked, return X;                  #
5051#               otherwise return 1.                                     #
5052#                                                                       #
5053#       9. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi,           #
5054#               go back to 3.                                           #
5055#                                                                       #
5056#       SINCOS:                                                         #
5057#       1. If |X| >= 15Pi or |X| < 2**(-40), go to 6.                   #
5058#                                                                       #
5059#       2. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let        #
5060#               k = N mod 4, so in particular, k = 0,1,2,or 3.          #
5061#                                                                       #
5062#       3. If k is even, go to 5.                                       #
5063#                                                                       #
5064#       4. (k is odd) Set j1 := (k-1)/2, j2 := j1 (EOR) (k mod 2), ie.  #
5065#               j1 exclusive or with the l.s.b. of k.                   #
5066#               sgn1 := (-1)**j1, sgn2 := (-1)**j2.                     #
5067#               SIN(X) = sgn1 * cos(r) and COS(X) = sgn2*sin(r) where   #
5068#               sin(r) and cos(r) are computed as odd and even          #
5069#               polynomials in r, respectively. Exit                    #
5070#                                                                       #
5071#       5. (k is even) Set j1 := k/2, sgn1 := (-1)**j1.                 #
5072#               SIN(X) = sgn1 * sin(r) and COS(X) = sgn1*cos(r) where   #
5073#               sin(r) and cos(r) are computed as odd and even          #
5074#               polynomials in r, respectively. Exit                    #
5075#                                                                       #
5076#       6. If |X| > 1, go to 8.                                         #
5077#                                                                       #
5078#       7. (|X|<2**(-40)) SIN(X) = X and COS(X) = 1. Exit.              #
5079#                                                                       #
5080#       8. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi,           #
5081#               go back to 2.                                           #
5082#                                                                       #
5083#########################################################################
5084
5085SINA7:  long            0xBD6AAA77,0xCCC994F5
5086SINA6:  long            0x3DE61209,0x7AAE8DA1
5087SINA5:  long            0xBE5AE645,0x2A118AE4
5088SINA4:  long            0x3EC71DE3,0xA5341531
5089SINA3:  long            0xBF2A01A0,0x1A018B59,0x00000000,0x00000000
5090SINA2:  long            0x3FF80000,0x88888888,0x888859AF,0x00000000
5091SINA1:  long            0xBFFC0000,0xAAAAAAAA,0xAAAAAA99,0x00000000
5092
5093COSB8:  long            0x3D2AC4D0,0xD6011EE3
5094COSB7:  long            0xBDA9396F,0x9F45AC19
5095COSB6:  long            0x3E21EED9,0x0612C972
5096COSB5:  long            0xBE927E4F,0xB79D9FCF
5097COSB4:  long            0x3EFA01A0,0x1A01D423,0x00000000,0x00000000
5098COSB3:  long            0xBFF50000,0xB60B60B6,0x0B61D438,0x00000000
5099COSB2:  long            0x3FFA0000,0xAAAAAAAA,0xAAAAAB5E
5100COSB1:  long            0xBF000000
5101
5102        set             INARG,FP_SCR0
5103
5104        set             X,FP_SCR0
5105#       set             XDCARE,X+2
5106        set             XFRAC,X+4
5107
5108        set             RPRIME,FP_SCR0
5109        set             SPRIME,FP_SCR1
5110
5111        set             POSNEG1,L_SCR1
5112        set             TWOTO63,L_SCR1
5113
5114        set             ENDFLAG,L_SCR2
5115        set             INT,L_SCR2
5116
5117        set             ADJN,L_SCR3
5118
5119############################################
5120        global          ssin
5121ssin:
5122        mov.l           &0,ADJN(%a6)            # yes; SET ADJN TO 0
5123        bra.b           SINBGN
5124
5125############################################
5126        global          scos
5127scos:
5128        mov.l           &1,ADJN(%a6)            # yes; SET ADJN TO 1
5129
5130############################################
5131SINBGN:
5132#--SAVE FPCR, FP1. CHECK IF |X| IS TOO SMALL OR LARGE
5133
5134        fmov.x          (%a0),%fp0              # LOAD INPUT
5135        fmov.x          %fp0,X(%a6)             # save input at X
5136
5137# "COMPACTIFY" X
5138        mov.l           (%a0),%d1               # put exp in hi word
5139        mov.w           4(%a0),%d1              # fetch hi(man)
5140        and.l           &0x7FFFFFFF,%d1         # strip sign
5141
5142        cmpi.l          %d1,&0x3FD78000         # is |X| >= 2**(-40)?
5143        bge.b           SOK1                    # no
5144        bra.w           SINSM                   # yes; input is very small
5145
5146SOK1:
5147        cmp.l           %d1,&0x4004BC7E         # is |X| < 15 PI?
5148        blt.b           SINMAIN                 # no
5149        bra.w           SREDUCEX                # yes; input is very large
5150
5151#--THIS IS THE USUAL CASE, |X| <= 15 PI.
5152#--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP.
5153SINMAIN:
5154        fmov.x          %fp0,%fp1
5155        fmul.d          TWOBYPI(%pc),%fp1       # X*2/PI
5156
5157        lea             PITBL+0x200(%pc),%a1    # TABLE OF N*PI/2, N = -32,...,32
5158
5159        fmov.l          %fp1,INT(%a6)           # CONVERT TO INTEGER
5160
5161        mov.l           INT(%a6),%d1            # make a copy of N
5162        asl.l           &4,%d1                  # N *= 16
5163        add.l           %d1,%a1                 # tbl_addr = a1 + (N*16)
5164
5165# A1 IS THE ADDRESS OF N*PIBY2
5166# ...WHICH IS IN TWO PIECES Y1 & Y2
5167        fsub.x          (%a1)+,%fp0             # X-Y1
5168        fsub.s          (%a1),%fp0              # fp0 = R = (X-Y1)-Y2
5169
5170SINCONT:
5171#--continuation from REDUCEX
5172
5173#--GET N+ADJN AND SEE IF SIN(R) OR COS(R) IS NEEDED
5174        mov.l           INT(%a6),%d1
5175        add.l           ADJN(%a6),%d1           # SEE IF D0 IS ODD OR EVEN
5176        ror.l           &1,%d1                  # D0 WAS ODD IFF D0 IS NEGATIVE
5177        cmp.l           %d1,&0
5178        blt.w           COSPOLY
5179
5180#--LET J BE THE LEAST SIG. BIT OF D0, LET SGN := (-1)**J.
5181#--THEN WE RETURN       SGN*SIN(R). SGN*SIN(R) IS COMPUTED BY
5182#--R' + R'*S*(A1 + S(A2 + S(A3 + S(A4 + ... + SA7)))), WHERE
5183#--R' = SGN*R, S=R*R. THIS CAN BE REWRITTEN AS
5184#--R' + R'*S*( [A1+T(A3+T(A5+TA7))] + [S(A2+T(A4+TA6))])
5185#--WHERE T=S*S.
5186#--NOTE THAT A3 THROUGH A7 ARE STORED IN DOUBLE PRECISION
5187#--WHILE A1 AND A2 ARE IN DOUBLE-EXTENDED FORMAT.
5188SINPOLY:
5189        fmovm.x         &0x0c,-(%sp)            # save fp2/fp3
5190
5191        fmov.x          %fp0,X(%a6)             # X IS R
5192        fmul.x          %fp0,%fp0               # FP0 IS S
5193
5194        fmov.d          SINA7(%pc),%fp3
5195        fmov.d          SINA6(%pc),%fp2
5196
5197        fmov.x          %fp0,%fp1
5198        fmul.x          %fp1,%fp1               # FP1 IS T
5199
5200        ror.l           &1,%d1
5201        and.l           &0x80000000,%d1
5202# ...LEAST SIG. BIT OF D0 IN SIGN POSITION
5203        eor.l           %d1,X(%a6)              # X IS NOW R'= SGN*R
5204
5205        fmul.x          %fp1,%fp3               # TA7
5206        fmul.x          %fp1,%fp2               # TA6
5207
5208        fadd.d          SINA5(%pc),%fp3         # A5+TA7
5209        fadd.d          SINA4(%pc),%fp2         # A4+TA6
5210
5211        fmul.x          %fp1,%fp3               # T(A5+TA7)
5212        fmul.x          %fp1,%fp2               # T(A4+TA6)
5213
5214        fadd.d          SINA3(%pc),%fp3         # A3+T(A5+TA7)
5215        fadd.x          SINA2(%pc),%fp2         # A2+T(A4+TA6)
5216
5217        fmul.x          %fp3,%fp1               # T(A3+T(A5+TA7))
5218
5219        fmul.x          %fp0,%fp2               # S(A2+T(A4+TA6))
5220        fadd.x          SINA1(%pc),%fp1         # A1+T(A3+T(A5+TA7))
5221        fmul.x          X(%a6),%fp0             # R'*S
5222
5223        fadd.x          %fp2,%fp1               # [A1+T(A3+T(A5+TA7))]+[S(A2+T(A4+TA6))]
5224
5225        fmul.x          %fp1,%fp0               # SIN(R')-R'
5226
5227        fmovm.x         (%sp)+,&0x30            # restore fp2/fp3
5228
5229        fmov.l          %d0,%fpcr               # restore users round mode,prec
5230        fadd.x          X(%a6),%fp0             # last inst - possible exception set
5231        bra             t_inx2
5232
5233#--LET J BE THE LEAST SIG. BIT OF D0, LET SGN := (-1)**J.
5234#--THEN WE RETURN       SGN*COS(R). SGN*COS(R) IS COMPUTED BY
5235#--SGN + S'*(B1 + S(B2 + S(B3 + S(B4 + ... + SB8)))), WHERE
5236#--S=R*R AND S'=SGN*S. THIS CAN BE REWRITTEN AS
5237#--SGN + S'*([B1+T(B3+T(B5+TB7))] + [S(B2+T(B4+T(B6+TB8)))])
5238#--WHERE T=S*S.
5239#--NOTE THAT B4 THROUGH B8 ARE STORED IN DOUBLE PRECISION