linux/arch/m68k/fpsp040/do_func.S
<<
>>
Prefs
   1|
   2|       do_func.sa 3.4 2/18/91
   3|
   4| Do_func performs the unimplemented operation.  The operation
   5| to be performed is determined from the lower 7 bits of the
   6| extension word (except in the case of fmovecr and fsincos).
   7| The opcode and tag bits form an index into a jump table in
   8| tbldo.sa.  Cases of zero, infinity and NaN are handled in
   9| do_func by forcing the default result.  Normalized and
  10| denormalized (there are no unnormalized numbers at this
  11| point) are passed onto the emulation code.
  12|
  13| CMDREG1B and STAG are extracted from the fsave frame
  14| and combined to form the table index.  The function called
  15| will start with a0 pointing to the ETEMP operand.  Dyadic
  16| functions can find FPTEMP at -12(a0).
  17|
  18| Called functions return their result in fp0.  Sincos returns
  19| sin(x) in fp0 and cos(x) in fp1.
  20|
  21
  22|               Copyright (C) Motorola, Inc. 1990
  23|                       All Rights Reserved
  24|
  25|       For details on the license for this file, please see the
  26|       file, README, in this same directory.
  27
  28DO_FUNC:        |idnt    2,1 | Motorola 040 Floating Point Software Package
  29
  30        |section        8
  31
  32#include "fpsp.h"
  33
  34        |xref   t_dz2
  35        |xref   t_operr
  36        |xref   t_inx2
  37        |xref   t_resdnrm
  38        |xref   dst_nan
  39        |xref   src_nan
  40        |xref   nrm_set
  41        |xref   sto_cos
  42
  43        |xref   tblpre
  44        |xref   slognp1,slogn,slog10,slog2
  45        |xref   slognd,slog10d,slog2d
  46        |xref   smod,srem
  47        |xref   sscale
  48        |xref   smovcr
  49
  50PONE:   .long   0x3fff0000,0x80000000,0x00000000        |+1
  51MONE:   .long   0xbfff0000,0x80000000,0x00000000        |-1
  52PZERO:  .long   0x00000000,0x00000000,0x00000000        |+0
  53MZERO:  .long   0x80000000,0x00000000,0x00000000        |-0
  54PINF:   .long   0x7fff0000,0x00000000,0x00000000        |+inf
  55MINF:   .long   0xffff0000,0x00000000,0x00000000        |-inf
  56QNAN:   .long   0x7fff0000,0xffffffff,0xffffffff        |non-signaling nan
  57PPIBY2:  .long  0x3FFF0000,0xC90FDAA2,0x2168C235        |+PI/2
  58MPIBY2:  .long  0xbFFF0000,0xC90FDAA2,0x2168C235        |-PI/2
  59
  60        .global do_func
  61do_func:
  62        clrb    CU_ONLY(%a6)
  63|
  64| Check for fmovecr.  It does not follow the format of fp gen
  65| unimplemented instructions.  The test is on the upper 6 bits;
  66| if they are $17, the inst is fmovecr.  Call entry smovcr
  67| directly.
  68|
  69        bfextu  CMDREG1B(%a6){#0:#6},%d0 |get opclass and src fields
  70        cmpil   #0x17,%d0               |if op class and size fields are $17,
  71|                               ;it is FMOVECR; if not, continue
  72        bnes    not_fmovecr
  73        jmp     smovcr          |fmovecr; jmp directly to emulation
  74
  75not_fmovecr:
  76        movew   CMDREG1B(%a6),%d0
  77        andl    #0x7F,%d0
  78        cmpil   #0x38,%d0               |if the extension is >= $38,
  79        bge     serror          |it is illegal
  80        bfextu  STAG(%a6){#0:#3},%d1
  81        lsll    #3,%d0          |make room for STAG
  82        addl    %d1,%d0         |combine for final index into table
  83        leal    tblpre,%a1      |start of monster jump table
  84        movel   (%a1,%d0.w*4),%a1       |real target address
  85        leal    ETEMP(%a6),%a0  |a0 is pointer to src op
  86        movel   USER_FPCR(%a6),%d1
  87        andl    #0xFF,%d1               | discard all but rounding mode/prec
  88        fmovel  #0,%fpcr
  89        jmp     (%a1)
  90|
  91|       ERROR
  92|
  93        .global serror
  94serror:
  95        st      STORE_FLG(%a6)
  96        rts
  97|
  98| These routines load forced values into fp0.  They are called
  99| by index into tbldo.
 100|
 101| Load a signed zero to fp0 and set inex2/ainex
 102|
 103        .global snzrinx
 104snzrinx:
 105        btstb   #sign_bit,LOCAL_EX(%a0) |get sign of source operand
 106        bnes    ld_mzinx        |if negative, branch
 107        bsr     ld_pzero        |bsr so we can return and set inx
 108        bra     t_inx2          |now, set the inx for the next inst
 109ld_mzinx:
 110        bsr     ld_mzero        |if neg, load neg zero, return here
 111        bra     t_inx2          |now, set the inx for the next inst
 112|
 113| Load a signed zero to fp0; do not set inex2/ainex
 114|
 115        .global szero
 116szero:
 117        btstb   #sign_bit,LOCAL_EX(%a0) |get sign of source operand
 118        bne     ld_mzero        |if neg, load neg zero
 119        bra     ld_pzero        |load positive zero
 120|
 121| Load a signed infinity to fp0; do not set inex2/ainex
 122|
 123        .global sinf
 124sinf:
 125        btstb   #sign_bit,LOCAL_EX(%a0) |get sign of source operand
 126        bne     ld_minf                 |if negative branch
 127        bra     ld_pinf
 128|
 129| Load a signed one to fp0; do not set inex2/ainex
 130|
 131        .global sone
 132sone:
 133        btstb   #sign_bit,LOCAL_EX(%a0) |check sign of source
 134        bne     ld_mone
 135        bra     ld_pone
 136|
 137| Load a signed pi/2 to fp0; do not set inex2/ainex
 138|
 139        .global spi_2
 140spi_2:
 141        btstb   #sign_bit,LOCAL_EX(%a0) |check sign of source
 142        bne     ld_mpi2
 143        bra     ld_ppi2
 144|
 145| Load either a +0 or +inf for plus/minus operand
 146|
 147        .global szr_inf
 148szr_inf:
 149        btstb   #sign_bit,LOCAL_EX(%a0) |check sign of source
 150        bne     ld_pzero
 151        bra     ld_pinf
 152|
 153| Result is either an operr or +inf for plus/minus operand
 154| [Used by slogn, slognp1, slog10, and slog2]
 155|
 156        .global sopr_inf
 157sopr_inf:
 158        btstb   #sign_bit,LOCAL_EX(%a0) |check sign of source
 159        bne     t_operr
 160        bra     ld_pinf
 161|
 162|       FLOGNP1
 163|
 164        .global sslognp1
 165sslognp1:
 166        fmovemx (%a0),%fp0-%fp0
 167        fcmpb   #-1,%fp0
 168        fbgt    slognp1
 169        fbeq    t_dz2           |if = -1, divide by zero exception
 170        fmovel  #0,%FPSR                |clr N flag
 171        bra     t_operr         |take care of operands < -1
 172|
 173|       FETOXM1
 174|
 175        .global setoxm1i
 176setoxm1i:
 177        btstb   #sign_bit,LOCAL_EX(%a0) |check sign of source
 178        bne     ld_mone
 179        bra     ld_pinf
 180|
 181|       FLOGN
 182|
 183| Test for 1.0 as an input argument, returning +zero.  Also check
 184| the sign and return operr if negative.
 185|
 186        .global sslogn
 187sslogn:
 188        btstb   #sign_bit,LOCAL_EX(%a0)
 189        bne     t_operr         |take care of operands < 0
 190        cmpiw   #0x3fff,LOCAL_EX(%a0) |test for 1.0 input
 191        bne     slogn
 192        cmpil   #0x80000000,LOCAL_HI(%a0)
 193        bne     slogn
 194        tstl    LOCAL_LO(%a0)
 195        bne     slogn
 196        fmovex  PZERO,%fp0
 197        rts
 198
 199        .global sslognd
 200sslognd:
 201        btstb   #sign_bit,LOCAL_EX(%a0)
 202        beq     slognd
 203        bra     t_operr         |take care of operands < 0
 204
 205|
 206|       FLOG10
 207|
 208        .global sslog10
 209sslog10:
 210        btstb   #sign_bit,LOCAL_EX(%a0)
 211        bne     t_operr         |take care of operands < 0
 212        cmpiw   #0x3fff,LOCAL_EX(%a0) |test for 1.0 input
 213        bne     slog10
 214        cmpil   #0x80000000,LOCAL_HI(%a0)
 215        bne     slog10
 216        tstl    LOCAL_LO(%a0)
 217        bne     slog10
 218        fmovex  PZERO,%fp0
 219        rts
 220
 221        .global sslog10d
 222sslog10d:
 223        btstb   #sign_bit,LOCAL_EX(%a0)
 224        beq     slog10d
 225        bra     t_operr         |take care of operands < 0
 226
 227|
 228|       FLOG2
 229|
 230        .global sslog2
 231sslog2:
 232        btstb   #sign_bit,LOCAL_EX(%a0)
 233        bne     t_operr         |take care of operands < 0
 234        cmpiw   #0x3fff,LOCAL_EX(%a0) |test for 1.0 input
 235        bne     slog2
 236        cmpil   #0x80000000,LOCAL_HI(%a0)
 237        bne     slog2
 238        tstl    LOCAL_LO(%a0)
 239        bne     slog2
 240        fmovex  PZERO,%fp0
 241        rts
 242
 243        .global sslog2d
 244sslog2d:
 245        btstb   #sign_bit,LOCAL_EX(%a0)
 246        beq     slog2d
 247        bra     t_operr         |take care of operands < 0
 248
 249|
 250|       FMOD
 251|
 252pmodt:
 253|                               ;$21 fmod
 254|                               ;dtag,stag
 255        .long   smod            |  00,00  norm,norm = normal
 256        .long   smod_oper       |  00,01  norm,zero = nan with operr
 257        .long   smod_fpn        |  00,10  norm,inf  = fpn
 258        .long   smod_snan       |  00,11  norm,nan  = nan
 259        .long   smod_zro        |  01,00  zero,norm = +-zero
 260        .long   smod_oper       |  01,01  zero,zero = nan with operr
 261        .long   smod_zro        |  01,10  zero,inf  = +-zero
 262        .long   smod_snan       |  01,11  zero,nan  = nan
 263        .long   smod_oper       |  10,00  inf,norm  = nan with operr
 264        .long   smod_oper       |  10,01  inf,zero  = nan with operr
 265        .long   smod_oper       |  10,10  inf,inf   = nan with operr
 266        .long   smod_snan       |  10,11  inf,nan   = nan
 267        .long   smod_dnan       |  11,00  nan,norm  = nan
 268        .long   smod_dnan       |  11,01  nan,zero  = nan
 269        .long   smod_dnan       |  11,10  nan,inf   = nan
 270        .long   smod_dnan       |  11,11  nan,nan   = nan
 271
 272        .global pmod
 273pmod:
 274        clrb    FPSR_QBYTE(%a6) | clear quotient field
 275        bfextu  STAG(%a6){#0:#3},%d0 |stag = d0
 276        bfextu  DTAG(%a6){#0:#3},%d1 |dtag = d1
 277
 278|
 279| Alias extended denorms to norms for the jump table.
 280|
 281        bclrl   #2,%d0
 282        bclrl   #2,%d1
 283
 284        lslb    #2,%d1
 285        orb     %d0,%d1         |d1{3:2} = dtag, d1{1:0} = stag
 286|                               ;Tag values:
 287|                               ;00 = norm or denorm
 288|                               ;01 = zero
 289|                               ;10 = inf
 290|                               ;11 = nan
 291        lea     pmodt,%a1
 292        movel   (%a1,%d1.w*4),%a1
 293        jmp     (%a1)
 294
 295smod_snan:
 296        bra     src_nan
 297smod_dnan:
 298        bra     dst_nan
 299smod_oper:
 300        bra     t_operr
 301smod_zro:
 302        moveb   ETEMP(%a6),%d1  |get sign of src op
 303        moveb   FPTEMP(%a6),%d0 |get sign of dst op
 304        eorb    %d0,%d1         |get exor of sign bits
 305        btstl   #7,%d1          |test for sign
 306        beqs    smod_zsn        |if clr, do not set sign big
 307        bsetb   #q_sn_bit,FPSR_QBYTE(%a6) |set q-byte sign bit
 308smod_zsn:
 309        btstl   #7,%d0          |test if + or -
 310        beq     ld_pzero        |if pos then load +0
 311        bra     ld_mzero        |else neg load -0
 312
 313smod_fpn:
 314        moveb   ETEMP(%a6),%d1  |get sign of src op
 315        moveb   FPTEMP(%a6),%d0 |get sign of dst op
 316        eorb    %d0,%d1         |get exor of sign bits
 317        btstl   #7,%d1          |test for sign
 318        beqs    smod_fsn        |if clr, do not set sign big
 319        bsetb   #q_sn_bit,FPSR_QBYTE(%a6) |set q-byte sign bit
 320smod_fsn:
 321        tstb    DTAG(%a6)       |filter out denormal destination case
 322        bpls    smod_nrm        |
 323        leal    FPTEMP(%a6),%a0 |a0<- addr(FPTEMP)
 324        bra     t_resdnrm       |force UNFL(but exact) result
 325smod_nrm:
 326        fmovel USER_FPCR(%a6),%fpcr |use user's rmode and precision
 327        fmovex FPTEMP(%a6),%fp0 |return dest to fp0
 328        rts
 329
 330|
 331|       FREM
 332|
 333premt:
 334|                               ;$25 frem
 335|                               ;dtag,stag
 336        .long   srem            |  00,00  norm,norm = normal
 337        .long   srem_oper       |  00,01  norm,zero = nan with operr
 338        .long   srem_fpn        |  00,10  norm,inf  = fpn
 339        .long   srem_snan       |  00,11  norm,nan  = nan
 340        .long   srem_zro        |  01,00  zero,norm = +-zero
 341        .long   srem_oper       |  01,01  zero,zero = nan with operr
 342        .long   srem_zro        |  01,10  zero,inf  = +-zero
 343        .long   srem_snan       |  01,11  zero,nan  = nan
 344        .long   srem_oper       |  10,00  inf,norm  = nan with operr
 345        .long   srem_oper       |  10,01  inf,zero  = nan with operr
 346        .long   srem_oper       |  10,10  inf,inf   = nan with operr
 347        .long   srem_snan       |  10,11  inf,nan   = nan
 348        .long   srem_dnan       |  11,00  nan,norm  = nan
 349        .long   srem_dnan       |  11,01  nan,zero  = nan
 350        .long   srem_dnan       |  11,10  nan,inf   = nan
 351        .long   srem_dnan       |  11,11  nan,nan   = nan
 352
 353        .global prem
 354prem:
 355        clrb    FPSR_QBYTE(%a6)   |clear quotient field
 356        bfextu  STAG(%a6){#0:#3},%d0 |stag = d0
 357        bfextu  DTAG(%a6){#0:#3},%d1 |dtag = d1
 358|
 359| Alias extended denorms to norms for the jump table.
 360|
 361        bclr    #2,%d0
 362        bclr    #2,%d1
 363
 364        lslb    #2,%d1
 365        orb     %d0,%d1         |d1{3:2} = dtag, d1{1:0} = stag
 366|                               ;Tag values:
 367|                               ;00 = norm or denorm
 368|                               ;01 = zero
 369|                               ;10 = inf
 370|                               ;11 = nan
 371        lea     premt,%a1
 372        movel   (%a1,%d1.w*4),%a1
 373        jmp     (%a1)
 374
 375srem_snan:
 376        bra     src_nan
 377srem_dnan:
 378        bra     dst_nan
 379srem_oper:
 380        bra     t_operr
 381srem_zro:
 382        moveb   ETEMP(%a6),%d1  |get sign of src op
 383        moveb   FPTEMP(%a6),%d0 |get sign of dst op
 384        eorb    %d0,%d1         |get exor of sign bits
 385        btstl   #7,%d1          |test for sign
 386        beqs    srem_zsn        |if clr, do not set sign big
 387        bsetb   #q_sn_bit,FPSR_QBYTE(%a6) |set q-byte sign bit
 388srem_zsn:
 389        btstl   #7,%d0          |test if + or -
 390        beq     ld_pzero        |if pos then load +0
 391        bra     ld_mzero        |else neg load -0
 392
 393srem_fpn:
 394        moveb   ETEMP(%a6),%d1  |get sign of src op
 395        moveb   FPTEMP(%a6),%d0 |get sign of dst op
 396        eorb    %d0,%d1         |get exor of sign bits
 397        btstl   #7,%d1          |test for sign
 398        beqs    srem_fsn        |if clr, do not set sign big
 399        bsetb   #q_sn_bit,FPSR_QBYTE(%a6) |set q-byte sign bit
 400srem_fsn:
 401        tstb    DTAG(%a6)       |filter out denormal destination case
 402        bpls    srem_nrm        |
 403        leal    FPTEMP(%a6),%a0 |a0<- addr(FPTEMP)
 404        bra     t_resdnrm       |force UNFL(but exact) result
 405srem_nrm:
 406        fmovel USER_FPCR(%a6),%fpcr |use user's rmode and precision
 407        fmovex FPTEMP(%a6),%fp0 |return dest to fp0
 408        rts
 409|
 410|       FSCALE
 411|
 412pscalet:
 413|                               ;$26 fscale
 414|                               ;dtag,stag
 415        .long   sscale          |  00,00  norm,norm = result
 416        .long   sscale          |  00,01  norm,zero = fpn
 417        .long   scl_opr         |  00,10  norm,inf  = nan with operr
 418        .long   scl_snan        |  00,11  norm,nan  = nan
 419        .long   scl_zro         |  01,00  zero,norm = +-zero
 420        .long   scl_zro         |  01,01  zero,zero = +-zero
 421        .long   scl_opr         |  01,10  zero,inf  = nan with operr
 422        .long   scl_snan        |  01,11  zero,nan  = nan
 423        .long   scl_inf         |  10,00  inf,norm  = +-inf
 424        .long   scl_inf         |  10,01  inf,zero  = +-inf
 425        .long   scl_opr         |  10,10  inf,inf   = nan with operr
 426        .long   scl_snan        |  10,11  inf,nan   = nan
 427        .long   scl_dnan        |  11,00  nan,norm  = nan
 428        .long   scl_dnan        |  11,01  nan,zero  = nan
 429        .long   scl_dnan        |  11,10  nan,inf   = nan
 430        .long   scl_dnan        |  11,11  nan,nan   = nan
 431
 432        .global pscale
 433pscale:
 434        bfextu  STAG(%a6){#0:#3},%d0 |stag in d0
 435        bfextu  DTAG(%a6){#0:#3},%d1 |dtag in d1
 436        bclrl   #2,%d0          |alias  denorm into norm
 437        bclrl   #2,%d1          |alias  denorm into norm
 438        lslb    #2,%d1
 439        orb     %d0,%d1         |d1{4:2} = dtag, d1{1:0} = stag
 440|                               ;dtag values     stag values:
 441|                               ;000 = norm      00 = norm
 442|                               ;001 = zero      01 = zero
 443|                               ;010 = inf       10 = inf
 444|                               ;011 = nan       11 = nan
 445|                               ;100 = dnrm
 446|
 447|
 448        leal    pscalet,%a1     |load start of jump table
 449        movel   (%a1,%d1.w*4),%a1       |load a1 with label depending on tag
 450        jmp     (%a1)           |go to the routine
 451
 452scl_opr:
 453        bra     t_operr
 454
 455scl_dnan:
 456        bra     dst_nan
 457
 458scl_zro:
 459        btstb   #sign_bit,FPTEMP_EX(%a6)        |test if + or -
 460        beq     ld_pzero                |if pos then load +0
 461        bra     ld_mzero                |if neg then load -0
 462scl_inf:
 463        btstb   #sign_bit,FPTEMP_EX(%a6)        |test if + or -
 464        beq     ld_pinf                 |if pos then load +inf
 465        bra     ld_minf                 |else neg load -inf
 466scl_snan:
 467        bra     src_nan
 468|
 469|       FSINCOS
 470|
 471        .global ssincosz
 472ssincosz:
 473        btstb   #sign_bit,ETEMP(%a6)    |get sign
 474        beqs    sincosp
 475        fmovex  MZERO,%fp0
 476        bras    sincoscom
 477sincosp:
 478        fmovex PZERO,%fp0
 479sincoscom:
 480        fmovemx PONE,%fp1-%fp1  |do not allow FPSR to be affected
 481        bra     sto_cos         |store cosine result
 482
 483        .global ssincosi
 484ssincosi:
 485        fmovex QNAN,%fp1        |load NAN
 486        bsr     sto_cos         |store cosine result
 487        fmovex QNAN,%fp0        |load NAN
 488        bra     t_operr
 489
 490        .global ssincosnan
 491ssincosnan:
 492        movel   ETEMP_EX(%a6),FP_SCR1(%a6)
 493        movel   ETEMP_HI(%a6),FP_SCR1+4(%a6)
 494        movel   ETEMP_LO(%a6),FP_SCR1+8(%a6)
 495        bsetb   #signan_bit,FP_SCR1+4(%a6)
 496        fmovemx FP_SCR1(%a6),%fp1-%fp1
 497        bsr     sto_cos
 498        bra     src_nan
 499|
 500| This code forces default values for the zero, inf, and nan cases
 501| in the transcendentals code.  The CC bits must be set in the
 502| stacked FPSR to be correctly reported.
 503|
 504|**Returns +PI/2
 505        .global ld_ppi2
 506ld_ppi2:
 507        fmovex PPIBY2,%fp0              |load +pi/2
 508        bra     t_inx2                  |set inex2 exc
 509
 510|**Returns -PI/2
 511        .global ld_mpi2
 512ld_mpi2:
 513        fmovex MPIBY2,%fp0              |load -pi/2
 514        orl     #neg_mask,USER_FPSR(%a6)        |set N bit
 515        bra     t_inx2                  |set inex2 exc
 516
 517|**Returns +inf
 518        .global ld_pinf
 519ld_pinf:
 520        fmovex PINF,%fp0                |load +inf
 521        orl     #inf_mask,USER_FPSR(%a6)        |set I bit
 522        rts
 523
 524|**Returns -inf
 525        .global ld_minf
 526ld_minf:
 527        fmovex MINF,%fp0                |load -inf
 528        orl     #neg_mask+inf_mask,USER_FPSR(%a6)       |set N and I bits
 529        rts
 530
 531|**Returns +1
 532        .global ld_pone
 533ld_pone:
 534        fmovex PONE,%fp0                |load +1
 535        rts
 536
 537|**Returns -1
 538        .global ld_mone
 539ld_mone:
 540        fmovex MONE,%fp0                |load -1
 541        orl     #neg_mask,USER_FPSR(%a6)        |set N bit
 542        rts
 543
 544|**Returns +0
 545        .global ld_pzero
 546ld_pzero:
 547        fmovex PZERO,%fp0               |load +0
 548        orl     #z_mask,USER_FPSR(%a6)  |set Z bit
 549        rts
 550
 551|**Returns -0
 552        .global ld_mzero
 553ld_mzero:
 554        fmovex MZERO,%fp0               |load -0
 555        orl     #neg_mask+z_mask,USER_FPSR(%a6) |set N and Z bits
 556        rts
 557
 558        |end
 559