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