Merge ../powerpc-merge
[linux-2.6] / arch / m68k / fpsp040 / do_func.S
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
28 DO_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
50 PONE:   .long   0x3fff0000,0x80000000,0x00000000        |+1
51 MONE:   .long   0xbfff0000,0x80000000,0x00000000        |-1
52 PZERO:  .long   0x00000000,0x00000000,0x00000000        |+0
53 MZERO:  .long   0x80000000,0x00000000,0x00000000        |-0
54 PINF:   .long   0x7fff0000,0x00000000,0x00000000        |+inf
55 MINF:   .long   0xffff0000,0x00000000,0x00000000        |-inf
56 QNAN:   .long   0x7fff0000,0xffffffff,0xffffffff        |non-signaling nan
57 PPIBY2:  .long  0x3FFF0000,0xC90FDAA2,0x2168C235        |+PI/2
58 MPIBY2:  .long  0xbFFF0000,0xC90FDAA2,0x2168C235        |-PI/2
59
60         .global do_func
61 do_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
75 not_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
94 serror:
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
104 snzrinx:
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
109 ld_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
116 szero:
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
124 sinf:
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
132 sone:
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
140 spi_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
148 szr_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
157 sopr_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
165 sslognp1:
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
176 setoxm1i:
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
187 sslogn:
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
200 sslognd:
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
209 sslog10:
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
222 sslog10d:
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
231 sslog2:
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
244 sslog2d:
245         btstb   #sign_bit,LOCAL_EX(%a0)
246         beq     slog2d
247         bra     t_operr         |take care of operands < 0
248
249 |
250 |       FMOD
251 |
252 pmodt:
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
273 pmod:
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
295 smod_snan:
296         bra     src_nan
297 smod_dnan:
298         bra     dst_nan
299 smod_oper:
300         bra     t_operr
301 smod_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
308 smod_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
313 smod_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
320 smod_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
325 smod_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 |
333 premt:
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
354 prem:
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
375 srem_snan:
376         bra     src_nan
377 srem_dnan:
378         bra     dst_nan
379 srem_oper:
380         bra     t_operr
381 srem_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
388 srem_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
393 srem_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
400 srem_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
405 srem_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 |
412 pscalet:
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
433 pscale:
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
452 scl_opr:
453         bra     t_operr
454
455 scl_dnan:
456         bra     dst_nan
457
458 scl_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
462 scl_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
466 scl_snan:
467         bra     src_nan
468 |
469 |       FSINCOS
470 |
471         .global ssincosz
472 ssincosz:
473         btstb   #sign_bit,ETEMP(%a6)    |get sign
474         beqs    sincosp
475         fmovex  MZERO,%fp0
476         bras    sincoscom
477 sincosp:
478         fmovex PZERO,%fp0
479 sincoscom:
480         fmovemx PONE,%fp1-%fp1  |do not allow FPSR to be affected
481         bra     sto_cos         |store cosine result
482
483         .global ssincosi
484 ssincosi:
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
491 ssincosnan:
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
506 ld_ppi2:
507         fmovex PPIBY2,%fp0              |load +pi/2
508         bra     t_inx2                  |set inex2 exc
509
510 |**Returns -PI/2
511         .global ld_mpi2
512 ld_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
519 ld_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
526 ld_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
533 ld_pone:
534         fmovex PONE,%fp0                |load +1
535         rts
536
537 |**Returns -1
538         .global ld_mone
539 ld_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
546 ld_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
553 ld_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