OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [m68k/] [fpsp040/] [res_func.S] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
|
2
|       res_func.sa 3.9 7/29/91
3
|
4
| Normalizes denormalized numbers if necessary and updates the
5
| stack frame.  The function is then restored back into the
6
| machine and the 040 completes the operation.  This routine
7
| is only used by the unsupported data type/format handler.
8
| (Exception vector 55).
9
|
10
| For packed move out (fmove.p fpm,) the operation is
11
| completed here; data is packed and moved to user memory.
12
| The stack is restored to the 040 only in the case of a
13
| reportable exception in the conversion.
14
|
15
|
16
|               Copyright (C) Motorola, Inc. 1990
17
|                       All Rights Reserved
18
|
19
|       For details on the license for this file, please see the
20
|       file, README, in this same directory.
21
 
22
RES_FUNC:    |idnt    2,1 | Motorola 040 Floating Point Software Package
23
 
24
        |section        8
25
 
26
#include "fpsp.h"
27
 
28
sp_bnds:        .short  0x3f81,0x407e
29
                .short  0x3f6a,0x0000
30
dp_bnds:        .short  0x3c01,0x43fe
31
                .short  0x3bcd,0x0000
32
 
33
        |xref   mem_write
34
        |xref   bindec
35
        |xref   get_fline
36
        |xref   round
37
        |xref   denorm
38
        |xref   dest_ext
39
        |xref   dest_dbl
40
        |xref   dest_sgl
41
        |xref   unf_sub
42
        |xref   nrm_set
43
        |xref   dnrm_lp
44
        |xref   ovf_res
45
        |xref   reg_dest
46
        |xref   t_ovfl
47
        |xref   t_unfl
48
 
49
        .global res_func
50
        .global p_move
51
 
52
res_func:
53
        clrb    DNRM_FLG(%a6)
54
        clrb    RES_FLG(%a6)
55
        clrb    CU_ONLY(%a6)
56
        tstb    DY_MO_FLG(%a6)
57
        beqs    monadic
58
dyadic:
59
        btstb   #7,DTAG(%a6)    |if dop = norm=000, zero=001,
60
|                               ;inf=010 or nan=011
61
        beqs    monadic         |then branch
62
|                               ;else denorm
63
| HANDLE DESTINATION DENORM HERE
64
|                               ;set dtag to norm
65
|                               ;write the tag & fpte15 to the fstack
66
        leal    FPTEMP(%a6),%a0
67
 
68
        bclrb   #sign_bit,LOCAL_EX(%a0)
69
        sne     LOCAL_SGN(%a0)
70
 
71
        bsr     nrm_set         |normalize number (exp will go negative)
72
        bclrb   #sign_bit,LOCAL_EX(%a0) |get rid of false sign
73
        bfclr   LOCAL_SGN(%a0){#0:#8}   |change back to IEEE ext format
74
        beqs    dpos
75
        bsetb   #sign_bit,LOCAL_EX(%a0)
76
dpos:
77
        bfclr   DTAG(%a6){#0:#4}        |set tag to normalized, FPTE15 = 0
78
        bsetb   #4,DTAG(%a6)    |set FPTE15
79
        orb     #0x0f,DNRM_FLG(%a6)
80
monadic:
81
        leal    ETEMP(%a6),%a0
82
        btstb   #direction_bit,CMDREG1B(%a6)    |check direction
83
        bne     opclass3                        |it is a mv out
84
|
85
| At this point, only opclass 0 and 2 possible
86
|
87
        btstb   #7,STAG(%a6)    |if sop = norm=000, zero=001,
88
|                               ;inf=010 or nan=011
89
        bne     mon_dnrm        |else denorm
90
        tstb    DY_MO_FLG(%a6)  |all cases of dyadic instructions would
91
        bne     normal          |require normalization of denorm
92
 
93
| At this point:
94
|       monadic instructions:   fabs  = $18  fneg   = $1a  ftst   = $3a
95
|                               fmove = $00  fsmove = $40  fdmove = $44
96
|                               fsqrt = $05* fssqrt = $41  fdsqrt = $45
97
|                               (*fsqrt reencoded to $05)
98
|
99
        movew   CMDREG1B(%a6),%d0       |get command register
100
        andil   #0x7f,%d0                       |strip to only command word
101
|
102
| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
103
| fdsqrt are possible.
104
| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
105
| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
106
|
107
        btstl   #0,%d0
108
        bne     normal                  |weed out fsqrt instructions
109
|
110
| cu_norm handles fmove in instructions with normalized inputs.
111
| The routine round is used to correctly round the input for the
112
| destination precision and mode.
113
|
114
cu_norm:
115
        st      CU_ONLY(%a6)            |set cu-only inst flag
116
        movew   CMDREG1B(%a6),%d0
117
        andib   #0x3b,%d0               |isolate bits to select inst
118
        tstb    %d0
119
        beql    cu_nmove        |if zero, it is an fmove
120
        cmpib   #0x18,%d0
121
        beql    cu_nabs         |if $18, it is fabs
122
        cmpib   #0x1a,%d0
123
        beql    cu_nneg         |if $1a, it is fneg
124
|
125
| Inst is ftst.  Check the source operand and set the cc's accordingly.
126
| No write is done, so simply rts.
127
|
128
cu_ntst:
129
        movew   LOCAL_EX(%a0),%d0
130
        bclrl   #15,%d0
131
        sne     LOCAL_SGN(%a0)
132
        beqs    cu_ntpo
133
        orl     #neg_mask,USER_FPSR(%a6) |set N
134
cu_ntpo:
135
        cmpiw   #0x7fff,%d0     |test for inf/nan
136
        bnes    cu_ntcz
137
        tstl    LOCAL_HI(%a0)
138
        bnes    cu_ntn
139
        tstl    LOCAL_LO(%a0)
140
        bnes    cu_ntn
141
        orl     #inf_mask,USER_FPSR(%a6)
142
        rts
143
cu_ntn:
144
        orl     #nan_mask,USER_FPSR(%a6)
145
        movel   ETEMP_EX(%a6),FPTEMP_EX(%a6)    |set up fptemp sign for
146
|                                               ;snan handler
147
 
148
        rts
149
cu_ntcz:
150
        tstl    LOCAL_HI(%a0)
151
        bnel    cu_ntsx
152
        tstl    LOCAL_LO(%a0)
153
        bnel    cu_ntsx
154
        orl     #z_mask,USER_FPSR(%a6)
155
cu_ntsx:
156
        rts
157
|
158
| Inst is fabs.  Execute the absolute value function on the input.
159
| Branch to the fmove code.  If the operand is NaN, do nothing.
160
|
161
cu_nabs:
162
        moveb   STAG(%a6),%d0
163
        btstl   #5,%d0                  |test for NaN or zero
164
        bne     wr_etemp                |if either, simply write it
165
        bclrb   #7,LOCAL_EX(%a0)                |do abs
166
        bras    cu_nmove                |fmove code will finish
167
|
168
| Inst is fneg.  Execute the negate value function on the input.
169
| Fall though to the fmove code.  If the operand is NaN, do nothing.
170
|
171
cu_nneg:
172
        moveb   STAG(%a6),%d0
173
        btstl   #5,%d0                  |test for NaN or zero
174
        bne     wr_etemp                |if either, simply write it
175
        bchgb   #7,LOCAL_EX(%a0)                |do neg
176
|
177
| Inst is fmove.  This code also handles all result writes.
178
| If bit 2 is set, round is forced to double.  If it is clear,
179
| and bit 6 is set, round is forced to single.  If both are clear,
180
| the round precision is found in the fpcr.  If the rounding precision
181
| is double or single, round the result before the write.
182
|
183
cu_nmove:
184
        moveb   STAG(%a6),%d0
185
        andib   #0xe0,%d0                       |isolate stag bits
186
        bne     wr_etemp                |if not norm, simply write it
187
        btstb   #2,CMDREG1B+1(%a6)      |check for rd
188
        bne     cu_nmrd
189
        btstb   #6,CMDREG1B+1(%a6)      |check for rs
190
        bne     cu_nmrs
191
|
192
| The move or operation is not with forced precision.  Test for
193
| nan or inf as the input; if so, simply write it to FPn.  Use the
194
| FPCR_MODE byte to get rounding on norms and zeros.
195
|
196
cu_nmnr:
197
        bfextu  FPCR_MODE(%a6){#0:#2},%d0
198
        tstb    %d0                     |check for extended
199
        beq     cu_wrexn                |if so, just write result
200
        cmpib   #1,%d0                  |check for single
201
        beq     cu_nmrs                 |fall through to double
202
|
203
| The move is fdmove or round precision is double.
204
|
205
cu_nmrd:
206
        movel   #2,%d0                  |set up the size for denorm
207
        movew   LOCAL_EX(%a0),%d1               |compare exponent to double threshold
208
        andw    #0x7fff,%d1
209
        cmpw    #0x3c01,%d1
210
        bls     cu_nunfl
211
        bfextu  FPCR_MODE(%a6){#2:#2},%d1       |get rmode
212
        orl     #0x00020000,%d1         |or in rprec (double)
213
        clrl    %d0                     |clear g,r,s for round
214
        bclrb   #sign_bit,LOCAL_EX(%a0) |convert to internal format
215
        sne     LOCAL_SGN(%a0)
216
        bsrl    round
217
        bfclr   LOCAL_SGN(%a0){#0:#8}
218
        beqs    cu_nmrdc
219
        bsetb   #sign_bit,LOCAL_EX(%a0)
220
cu_nmrdc:
221
        movew   LOCAL_EX(%a0),%d1               |check for overflow
222
        andw    #0x7fff,%d1
223
        cmpw    #0x43ff,%d1
224
        bge     cu_novfl                |take care of overflow case
225
        bra     cu_wrexn
226
|
227
| The move is fsmove or round precision is single.
228
|
229
cu_nmrs:
230
        movel   #1,%d0
231
        movew   LOCAL_EX(%a0),%d1
232
        andw    #0x7fff,%d1
233
        cmpw    #0x3f81,%d1
234
        bls     cu_nunfl
235
        bfextu  FPCR_MODE(%a6){#2:#2},%d1
236
        orl     #0x00010000,%d1
237
        clrl    %d0
238
        bclrb   #sign_bit,LOCAL_EX(%a0)
239
        sne     LOCAL_SGN(%a0)
240
        bsrl    round
241
        bfclr   LOCAL_SGN(%a0){#0:#8}
242
        beqs    cu_nmrsc
243
        bsetb   #sign_bit,LOCAL_EX(%a0)
244
cu_nmrsc:
245
        movew   LOCAL_EX(%a0),%d1
246
        andw    #0x7FFF,%d1
247
        cmpw    #0x407f,%d1
248
        blt     cu_wrexn
249
|
250
| The operand is above precision boundaries.  Use t_ovfl to
251
| generate the correct value.
252
|
253
cu_novfl:
254
        bsr     t_ovfl
255
        bra     cu_wrexn
256
|
257
| The operand is below precision boundaries.  Use denorm to
258
| generate the correct value.
259
|
260
cu_nunfl:
261
        bclrb   #sign_bit,LOCAL_EX(%a0)
262
        sne     LOCAL_SGN(%a0)
263
        bsr     denorm
264
        bfclr   LOCAL_SGN(%a0){#0:#8}   |change back to IEEE ext format
265
        beqs    cu_nucont
266
        bsetb   #sign_bit,LOCAL_EX(%a0)
267
cu_nucont:
268
        bfextu  FPCR_MODE(%a6){#2:#2},%d1
269
        btstb   #2,CMDREG1B+1(%a6)      |check for rd
270
        bne     inst_d
271
        btstb   #6,CMDREG1B+1(%a6)      |check for rs
272
        bne     inst_s
273
        swap    %d1
274
        moveb   FPCR_MODE(%a6),%d1
275
        lsrb    #6,%d1
276
        swap    %d1
277
        bra     inst_sd
278
inst_d:
279
        orl     #0x00020000,%d1
280
        bra     inst_sd
281
inst_s:
282
        orl     #0x00010000,%d1
283
inst_sd:
284
        bclrb   #sign_bit,LOCAL_EX(%a0)
285
        sne     LOCAL_SGN(%a0)
286
        bsrl    round
287
        bfclr   LOCAL_SGN(%a0){#0:#8}
288
        beqs    cu_nuflp
289
        bsetb   #sign_bit,LOCAL_EX(%a0)
290
cu_nuflp:
291
        btstb   #inex2_bit,FPSR_EXCEPT(%a6)
292
        beqs    cu_nuninx
293
        orl     #aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL
294
cu_nuninx:
295
        tstl    LOCAL_HI(%a0)           |test for zero
296
        bnes    cu_nunzro
297
        tstl    LOCAL_LO(%a0)
298
        bnes    cu_nunzro
299
|
300
| The mantissa is zero from the denorm loop.  Check sign and rmode
301
| to see if rounding should have occurred which would leave the lsb.
302
|
303
        movel   USER_FPCR(%a6),%d0
304
        andil   #0x30,%d0               |isolate rmode
305
        cmpil   #0x20,%d0
306
        blts    cu_nzro
307
        bnes    cu_nrp
308
cu_nrm:
309
        tstw    LOCAL_EX(%a0)   |if positive, set lsb
310
        bges    cu_nzro
311
        btstb   #7,FPCR_MODE(%a6) |check for double
312
        beqs    cu_nincs
313
        bras    cu_nincd
314
cu_nrp:
315
        tstw    LOCAL_EX(%a0)   |if positive, set lsb
316
        blts    cu_nzro
317
        btstb   #7,FPCR_MODE(%a6) |check for double
318
        beqs    cu_nincs
319
cu_nincd:
320
        orl     #0x800,LOCAL_LO(%a0) |inc for double
321
        bra     cu_nunzro
322
cu_nincs:
323
        orl     #0x100,LOCAL_HI(%a0) |inc for single
324
        bra     cu_nunzro
325
cu_nzro:
326
        orl     #z_mask,USER_FPSR(%a6)
327
        moveb   STAG(%a6),%d0
328
        andib   #0xe0,%d0
329
        cmpib   #0x40,%d0               |check if input was tagged zero
330
        beqs    cu_numv
331
cu_nunzro:
332
        orl     #unfl_mask,USER_FPSR(%a6) |set unfl
333
cu_numv:
334
        movel   (%a0),ETEMP(%a6)
335
        movel   4(%a0),ETEMP_HI(%a6)
336
        movel   8(%a0),ETEMP_LO(%a6)
337
|
338
| Write the result to memory, setting the fpsr cc bits.  NaN and Inf
339
| bypass cu_wrexn.
340
|
341
cu_wrexn:
342
        tstw    LOCAL_EX(%a0)           |test for zero
343
        beqs    cu_wrzero
344
        cmpw    #0x8000,LOCAL_EX(%a0)   |test for zero
345
        bnes    cu_wreon
346
cu_wrzero:
347
        orl     #z_mask,USER_FPSR(%a6)  |set Z bit
348
cu_wreon:
349
        tstw    LOCAL_EX(%a0)
350
        bpl     wr_etemp
351
        orl     #neg_mask,USER_FPSR(%a6)
352
        bra     wr_etemp
353
 
354
|
355
| HANDLE SOURCE DENORM HERE
356
|
357
|                               ;clear denorm stag to norm
358
|                               ;write the new tag & ete15 to the fstack
359
mon_dnrm:
360
|
361
| At this point, check for the cases in which normalizing the
362
| denorm produces incorrect results.
363
|
364
        tstb    DY_MO_FLG(%a6)  |all cases of dyadic instructions would
365
        bnes    nrm_src         |require normalization of denorm
366
 
367
| At this point:
368
|       monadic instructions:   fabs  = $18  fneg   = $1a  ftst   = $3a
369
|                               fmove = $00  fsmove = $40  fdmove = $44
370
|                               fsqrt = $05* fssqrt = $41  fdsqrt = $45
371
|                               (*fsqrt reencoded to $05)
372
|
373
        movew   CMDREG1B(%a6),%d0       |get command register
374
        andil   #0x7f,%d0                       |strip to only command word
375
|
376
| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
377
| fdsqrt are possible.
378
| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
379
| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
380
|
381
        btstl   #0,%d0
382
        bnes    nrm_src         |weed out fsqrt instructions
383
        st      CU_ONLY(%a6)    |set cu-only inst flag
384
        bra     cu_dnrm         |fmove, fabs, fneg, ftst
385
|                               ;cases go to cu_dnrm
386
nrm_src:
387
        bclrb   #sign_bit,LOCAL_EX(%a0)
388
        sne     LOCAL_SGN(%a0)
389
        bsr     nrm_set         |normalize number (exponent will go
390
|                               ; negative)
391
        bclrb   #sign_bit,LOCAL_EX(%a0) |get rid of false sign
392
 
393
        bfclr   LOCAL_SGN(%a0){#0:#8}   |change back to IEEE ext format
394
        beqs    spos
395
        bsetb   #sign_bit,LOCAL_EX(%a0)
396
spos:
397
        bfclr   STAG(%a6){#0:#4}        |set tag to normalized, FPTE15 = 0
398
        bsetb   #4,STAG(%a6)    |set ETE15
399
        orb     #0xf0,DNRM_FLG(%a6)
400
normal:
401
        tstb    DNRM_FLG(%a6)   |check if any of the ops were denorms
402
        bne     ck_wrap         |if so, check if it is a potential
403
|                               ;wrap-around case
404
fix_stk:
405
        moveb   #0xfe,CU_SAVEPC(%a6)
406
        bclrb   #E1,E_BYTE(%a6)
407
 
408
        clrw    NMNEXC(%a6)
409
 
410
        st      RES_FLG(%a6)    |indicate that a restore is needed
411
        rts
412
 
413
|
414
| cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
415
| ftst) completely in software without an frestore to the 040.
416
|
417
cu_dnrm:
418
        st      CU_ONLY(%a6)
419
        movew   CMDREG1B(%a6),%d0
420
        andib   #0x3b,%d0               |isolate bits to select inst
421
        tstb    %d0
422
        beql    cu_dmove        |if zero, it is an fmove
423
        cmpib   #0x18,%d0
424
        beql    cu_dabs         |if $18, it is fabs
425
        cmpib   #0x1a,%d0
426
        beql    cu_dneg         |if $1a, it is fneg
427
|
428
| Inst is ftst.  Check the source operand and set the cc's accordingly.
429
| No write is done, so simply rts.
430
|
431
cu_dtst:
432
        movew   LOCAL_EX(%a0),%d0
433
        bclrl   #15,%d0
434
        sne     LOCAL_SGN(%a0)
435
        beqs    cu_dtpo
436
        orl     #neg_mask,USER_FPSR(%a6) |set N
437
cu_dtpo:
438
        cmpiw   #0x7fff,%d0     |test for inf/nan
439
        bnes    cu_dtcz
440
        tstl    LOCAL_HI(%a0)
441
        bnes    cu_dtn
442
        tstl    LOCAL_LO(%a0)
443
        bnes    cu_dtn
444
        orl     #inf_mask,USER_FPSR(%a6)
445
        rts
446
cu_dtn:
447
        orl     #nan_mask,USER_FPSR(%a6)
448
        movel   ETEMP_EX(%a6),FPTEMP_EX(%a6)    |set up fptemp sign for
449
|                                               ;snan handler
450
        rts
451
cu_dtcz:
452
        tstl    LOCAL_HI(%a0)
453
        bnel    cu_dtsx
454
        tstl    LOCAL_LO(%a0)
455
        bnel    cu_dtsx
456
        orl     #z_mask,USER_FPSR(%a6)
457
cu_dtsx:
458
        rts
459
|
460
| Inst is fabs.  Execute the absolute value function on the input.
461
| Branch to the fmove code.
462
|
463
cu_dabs:
464
        bclrb   #7,LOCAL_EX(%a0)                |do abs
465
        bras    cu_dmove                |fmove code will finish
466
|
467
| Inst is fneg.  Execute the negate value function on the input.
468
| Fall though to the fmove code.
469
|
470
cu_dneg:
471
        bchgb   #7,LOCAL_EX(%a0)                |do neg
472
|
473
| Inst is fmove.  This code also handles all result writes.
474
| If bit 2 is set, round is forced to double.  If it is clear,
475
| and bit 6 is set, round is forced to single.  If both are clear,
476
| the round precision is found in the fpcr.  If the rounding precision
477
| is double or single, the result is zero, and the mode is checked
478
| to determine if the lsb of the result should be set.
479
|
480
cu_dmove:
481
        btstb   #2,CMDREG1B+1(%a6)      |check for rd
482
        bne     cu_dmrd
483
        btstb   #6,CMDREG1B+1(%a6)      |check for rs
484
        bne     cu_dmrs
485
|
486
| The move or operation is not with forced precision.  Use the
487
| FPCR_MODE byte to get rounding.
488
|
489
cu_dmnr:
490
        bfextu  FPCR_MODE(%a6){#0:#2},%d0
491
        tstb    %d0                     |check for extended
492
        beq     cu_wrexd                |if so, just write result
493
        cmpib   #1,%d0                  |check for single
494
        beq     cu_dmrs                 |fall through to double
495
|
496
| The move is fdmove or round precision is double.  Result is zero.
497
| Check rmode for rp or rm and set lsb accordingly.
498
|
499
cu_dmrd:
500
        bfextu  FPCR_MODE(%a6){#2:#2},%d1       |get rmode
501
        tstw    LOCAL_EX(%a0)           |check sign
502
        blts    cu_dmdn
503
        cmpib   #3,%d1                  |check for rp
504
        bne     cu_dpd                  |load double pos zero
505
        bra     cu_dpdr                 |load double pos zero w/lsb
506
cu_dmdn:
507
        cmpib   #2,%d1                  |check for rm
508
        bne     cu_dnd                  |load double neg zero
509
        bra     cu_dndr                 |load double neg zero w/lsb
510
|
511
| The move is fsmove or round precision is single.  Result is zero.
512
| Check for rp or rm and set lsb accordingly.
513
|
514
cu_dmrs:
515
        bfextu  FPCR_MODE(%a6){#2:#2},%d1       |get rmode
516
        tstw    LOCAL_EX(%a0)           |check sign
517
        blts    cu_dmsn
518
        cmpib   #3,%d1                  |check for rp
519
        bne     cu_spd                  |load single pos zero
520
        bra     cu_spdr                 |load single pos zero w/lsb
521
cu_dmsn:
522
        cmpib   #2,%d1                  |check for rm
523
        bne     cu_snd                  |load single neg zero
524
        bra     cu_sndr                 |load single neg zero w/lsb
525
|
526
| The precision is extended, so the result in etemp is correct.
527
| Simply set unfl (not inex2 or aunfl) and write the result to
528
| the correct fp register.
529
cu_wrexd:
530
        orl     #unfl_mask,USER_FPSR(%a6)
531
        tstw    LOCAL_EX(%a0)
532
        beq     wr_etemp
533
        orl     #neg_mask,USER_FPSR(%a6)
534
        bra     wr_etemp
535
|
536
| These routines write +/- zero in double format.  The routines
537
| cu_dpdr and cu_dndr set the double lsb.
538
|
539
cu_dpd:
540
        movel   #0x3c010000,LOCAL_EX(%a0)       |force pos double zero
541
        clrl    LOCAL_HI(%a0)
542
        clrl    LOCAL_LO(%a0)
543
        orl     #z_mask,USER_FPSR(%a6)
544
        orl     #unfinx_mask,USER_FPSR(%a6)
545
        bra     wr_etemp
546
cu_dpdr:
547
        movel   #0x3c010000,LOCAL_EX(%a0)       |force pos double zero
548
        clrl    LOCAL_HI(%a0)
549
        movel   #0x800,LOCAL_LO(%a0)    |with lsb set
550
        orl     #unfinx_mask,USER_FPSR(%a6)
551
        bra     wr_etemp
552
cu_dnd:
553
        movel   #0xbc010000,LOCAL_EX(%a0)       |force pos double zero
554
        clrl    LOCAL_HI(%a0)
555
        clrl    LOCAL_LO(%a0)
556
        orl     #z_mask,USER_FPSR(%a6)
557
        orl     #neg_mask,USER_FPSR(%a6)
558
        orl     #unfinx_mask,USER_FPSR(%a6)
559
        bra     wr_etemp
560
cu_dndr:
561
        movel   #0xbc010000,LOCAL_EX(%a0)       |force pos double zero
562
        clrl    LOCAL_HI(%a0)
563
        movel   #0x800,LOCAL_LO(%a0)    |with lsb set
564
        orl     #neg_mask,USER_FPSR(%a6)
565
        orl     #unfinx_mask,USER_FPSR(%a6)
566
        bra     wr_etemp
567
|
568
| These routines write +/- zero in single format.  The routines
569
| cu_dpdr and cu_dndr set the single lsb.
570
|
571
cu_spd:
572
        movel   #0x3f810000,LOCAL_EX(%a0)       |force pos single zero
573
        clrl    LOCAL_HI(%a0)
574
        clrl    LOCAL_LO(%a0)
575
        orl     #z_mask,USER_FPSR(%a6)
576
        orl     #unfinx_mask,USER_FPSR(%a6)
577
        bra     wr_etemp
578
cu_spdr:
579
        movel   #0x3f810000,LOCAL_EX(%a0)       |force pos single zero
580
        movel   #0x100,LOCAL_HI(%a0)    |with lsb set
581
        clrl    LOCAL_LO(%a0)
582
        orl     #unfinx_mask,USER_FPSR(%a6)
583
        bra     wr_etemp
584
cu_snd:
585
        movel   #0xbf810000,LOCAL_EX(%a0)       |force pos single zero
586
        clrl    LOCAL_HI(%a0)
587
        clrl    LOCAL_LO(%a0)
588
        orl     #z_mask,USER_FPSR(%a6)
589
        orl     #neg_mask,USER_FPSR(%a6)
590
        orl     #unfinx_mask,USER_FPSR(%a6)
591
        bra     wr_etemp
592
cu_sndr:
593
        movel   #0xbf810000,LOCAL_EX(%a0)       |force pos single zero
594
        movel   #0x100,LOCAL_HI(%a0)    |with lsb set
595
        clrl    LOCAL_LO(%a0)
596
        orl     #neg_mask,USER_FPSR(%a6)
597
        orl     #unfinx_mask,USER_FPSR(%a6)
598
        bra     wr_etemp
599
 
600
|
601
| This code checks for 16-bit overflow conditions on dyadic
602
| operations which are not restorable into the floating-point
603
| unit and must be completed in software.  Basically, this
604
| condition exists with a very large norm and a denorm.  One
605
| of the operands must be denormalized to enter this code.
606
|
607
| Flags used:
608
|       DY_MO_FLG contains 0 for monadic op, $ff for dyadic
609
|       DNRM_FLG contains $00 for neither op denormalized
610
|                         $0f for the destination op denormalized
611
|                         $f0 for the source op denormalized
612
|                         $ff for both ops denormalized
613
|
614
| The wrap-around condition occurs for add, sub, div, and cmp
615
| when
616
|
617
|       abs(dest_exp - src_exp) >= $8000
618
|
619
| and for mul when
620
|
621
|       (dest_exp + src_exp) < $0
622
|
623
| we must process the operation here if this case is true.
624
|
625
| The rts following the frcfpn routine is the exit from res_func
626
| for this condition.  The restore flag (RES_FLG) is left clear.
627
| No frestore is done unless an exception is to be reported.
628
|
629
| For fadd:
630
|       if(sign_of(dest) != sign_of(src))
631
|               replace exponent of src with $3fff (keep sign)
632
|               use fpu to perform dest+new_src (user's rmode and X)
633
|               clr sticky
634
|       else
635
|               set sticky
636
|       call round with user's precision and mode
637
|       move result to fpn and wbtemp
638
|
639
| For fsub:
640
|       if(sign_of(dest) == sign_of(src))
641
|               replace exponent of src with $3fff (keep sign)
642
|               use fpu to perform dest+new_src (user's rmode and X)
643
|               clr sticky
644
|       else
645
|               set sticky
646
|       call round with user's precision and mode
647
|       move result to fpn and wbtemp
648
|
649
| For fdiv/fsgldiv:
650
|       if(both operands are denorm)
651
|               restore_to_fpu;
652
|       if(dest is norm)
653
|               force_ovf;
654
|       else(dest is denorm)
655
|               force_unf:
656
|
657
| For fcmp:
658
|       if(dest is norm)
659
|               N = sign_of(dest);
660
|       else(dest is denorm)
661
|               N = sign_of(src);
662
|
663
| For fmul:
664
|       if(both operands are denorm)
665
|               force_unf;
666
|       if((dest_exp + src_exp) < 0)
667
|               force_unf:
668
|       else
669
|               restore_to_fpu;
670
|
671
| local equates:
672
        .set    addcode,0x22
673
        .set    subcode,0x28
674
        .set    mulcode,0x23
675
        .set    divcode,0x20
676
        .set    cmpcode,0x38
677
ck_wrap:
678
        | tstb  DY_MO_FLG(%a6)  ;check for fsqrt
679
        beq     fix_stk         |if zero, it is fsqrt
680
        movew   CMDREG1B(%a6),%d0
681
        andiw   #0x3b,%d0               |strip to command bits
682
        cmpiw   #addcode,%d0
683
        beq     wrap_add
684
        cmpiw   #subcode,%d0
685
        beq     wrap_sub
686
        cmpiw   #mulcode,%d0
687
        beq     wrap_mul
688
        cmpiw   #cmpcode,%d0
689
        beq     wrap_cmp
690
|
691
| Inst is fdiv.
692
|
693
wrap_div:
694
        cmpb    #0xff,DNRM_FLG(%a6) |if both ops denorm,
695
        beq     fix_stk          |restore to fpu
696
|
697
| One of the ops is denormalized.  Test for wrap condition
698
| and force the result.
699
|
700
        cmpb    #0x0f,DNRM_FLG(%a6) |check for dest denorm
701
        bnes    div_srcd
702
div_destd:
703
        bsrl    ckinf_ns
704
        bne     fix_stk
705
        bfextu  ETEMP_EX(%a6){#1:#15},%d0       |get src exp (always pos)
706
        bfexts  FPTEMP_EX(%a6){#1:#15},%d1      |get dest exp (always neg)
707
        subl    %d1,%d0                 |subtract dest from src
708
        cmpl    #0x7fff,%d0
709
        blt     fix_stk                 |if less, not wrap case
710
        clrb    WBTEMP_SGN(%a6)
711
        movew   ETEMP_EX(%a6),%d0               |find the sign of the result
712
        movew   FPTEMP_EX(%a6),%d1
713
        eorw    %d1,%d0
714
        andiw   #0x8000,%d0
715
        beq     force_unf
716
        st      WBTEMP_SGN(%a6)
717
        bra     force_unf
718
 
719
ckinf_ns:
720
        moveb   STAG(%a6),%d0           |check source tag for inf or nan
721
        bra     ck_in_com
722
ckinf_nd:
723
        moveb   DTAG(%a6),%d0           |check destination tag for inf or nan
724
ck_in_com:
725
        andib   #0x60,%d0                       |isolate tag bits
726
        cmpb    #0x40,%d0                       |is it inf?
727
        beq     nan_or_inf              |not wrap case
728
        cmpb    #0x60,%d0                       |is it nan?
729
        beq     nan_or_inf              |yes, not wrap case?
730
        cmpb    #0x20,%d0                       |is it a zero?
731
        beq     nan_or_inf              |yes
732
        clrl    %d0
733
        rts                             |then ; it is either a zero of norm,
734
|                                       ;check wrap case
735
nan_or_inf:
736
        moveql  #-1,%d0
737
        rts
738
 
739
 
740
 
741
div_srcd:
742
        bsrl    ckinf_nd
743
        bne     fix_stk
744
        bfextu  FPTEMP_EX(%a6){#1:#15},%d0      |get dest exp (always pos)
745
        bfexts  ETEMP_EX(%a6){#1:#15},%d1       |get src exp (always neg)
746
        subl    %d1,%d0                 |subtract src from dest
747
        cmpl    #0x8000,%d0
748
        blt     fix_stk                 |if less, not wrap case
749
        clrb    WBTEMP_SGN(%a6)
750
        movew   ETEMP_EX(%a6),%d0               |find the sign of the result
751
        movew   FPTEMP_EX(%a6),%d1
752
        eorw    %d1,%d0
753
        andiw   #0x8000,%d0
754
        beqs    force_ovf
755
        st      WBTEMP_SGN(%a6)
756
|
757
| This code handles the case of the instruction resulting in
758
| an overflow condition.
759
|
760
force_ovf:
761
        bclrb   #E1,E_BYTE(%a6)
762
        orl     #ovfl_inx_mask,USER_FPSR(%a6)
763
        clrw    NMNEXC(%a6)
764
        leal    WBTEMP(%a6),%a0         |point a0 to memory location
765
        movew   CMDREG1B(%a6),%d0
766
        btstl   #6,%d0                  |test for forced precision
767
        beqs    frcovf_fpcr
768
        btstl   #2,%d0                  |check for double
769
        bnes    frcovf_dbl
770
        movel   #0x1,%d0                        |inst is forced single
771
        bras    frcovf_rnd
772
frcovf_dbl:
773
        movel   #0x2,%d0                        |inst is forced double
774
        bras    frcovf_rnd
775
frcovf_fpcr:
776
        bfextu  FPCR_MODE(%a6){#0:#2},%d0       |inst not forced - use fpcr prec
777
frcovf_rnd:
778
 
779
| The 881/882 does not set inex2 for the following case, so the
780
| line is commented out to be compatible with 881/882
781
|       tst.b   %d0
782
|       beq.b   frcovf_x
783
|       or.l    #inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2
784
 
785
|frcovf_x:
786
        bsrl    ovf_res                 |get correct result based on
787
|                                       ;round precision/mode.  This
788
|                                       ;sets FPSR_CC correctly
789
|                                       ;returns in external format
790
        bfclr   WBTEMP_SGN(%a6){#0:#8}
791
        beq     frcfpn
792
        bsetb   #sign_bit,WBTEMP_EX(%a6)
793
        bra     frcfpn
794
|
795
| Inst is fadd.
796
|
797
wrap_add:
798
        cmpb    #0xff,DNRM_FLG(%a6) |if both ops denorm,
799
        beq     fix_stk          |restore to fpu
800
|
801
| One of the ops is denormalized.  Test for wrap condition
802
| and complete the instruction.
803
|
804
        cmpb    #0x0f,DNRM_FLG(%a6) |check for dest denorm
805
        bnes    add_srcd
806
add_destd:
807
        bsrl    ckinf_ns
808
        bne     fix_stk
809
        bfextu  ETEMP_EX(%a6){#1:#15},%d0       |get src exp (always pos)
810
        bfexts  FPTEMP_EX(%a6){#1:#15},%d1      |get dest exp (always neg)
811
        subl    %d1,%d0                 |subtract dest from src
812
        cmpl    #0x8000,%d0
813
        blt     fix_stk                 |if less, not wrap case
814
        bra     add_wrap
815
add_srcd:
816
        bsrl    ckinf_nd
817
        bne     fix_stk
818
        bfextu  FPTEMP_EX(%a6){#1:#15},%d0      |get dest exp (always pos)
819
        bfexts  ETEMP_EX(%a6){#1:#15},%d1       |get src exp (always neg)
820
        subl    %d1,%d0                 |subtract src from dest
821
        cmpl    #0x8000,%d0
822
        blt     fix_stk                 |if less, not wrap case
823
|
824
| Check the signs of the operands.  If they are unlike, the fpu
825
| can be used to add the norm and 1.0 with the sign of the
826
| denorm and it will correctly generate the result in extended
827
| precision.  We can then call round with no sticky and the result
828
| will be correct for the user's rounding mode and precision.  If
829
| the signs are the same, we call round with the sticky bit set
830
| and the result will be correct for the user's rounding mode and
831
| precision.
832
|
833
add_wrap:
834
        movew   ETEMP_EX(%a6),%d0
835
        movew   FPTEMP_EX(%a6),%d1
836
        eorw    %d1,%d0
837
        andiw   #0x8000,%d0
838
        beq     add_same
839
|
840
| The signs are unlike.
841
|
842
        cmpb    #0x0f,DNRM_FLG(%a6) |is dest the denorm?
843
        bnes    add_u_srcd
844
        movew   FPTEMP_EX(%a6),%d0
845
        andiw   #0x8000,%d0
846
        orw     #0x3fff,%d0     |force the exponent to +/- 1
847
        movew   %d0,FPTEMP_EX(%a6) |in the denorm
848
        movel   USER_FPCR(%a6),%d0
849
        andil   #0x30,%d0
850
        fmovel  %d0,%fpcr               |set up users rmode and X
851
        fmovex  ETEMP(%a6),%fp0
852
        faddx   FPTEMP(%a6),%fp0
853
        leal    WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
854
        fmovel  %fpsr,%d1
855
        orl     %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
856
        fmovex  %fp0,WBTEMP(%a6)        |write result to memory
857
        lsrl    #4,%d0          |put rmode in lower 2 bits
858
        movel   USER_FPCR(%a6),%d1
859
        andil   #0xc0,%d1
860
        lsrl    #6,%d1          |put precision in upper word
861
        swap    %d1
862
        orl     %d0,%d1         |set up for round call
863
        clrl    %d0             |force sticky to zero
864
        bclrb   #sign_bit,WBTEMP_EX(%a6)
865
        sne     WBTEMP_SGN(%a6)
866
        bsrl    round           |round result to users rmode & prec
867
        bfclr   WBTEMP_SGN(%a6){#0:#8}  |convert back to IEEE ext format
868
        beq     frcfpnr
869
        bsetb   #sign_bit,WBTEMP_EX(%a6)
870
        bra     frcfpnr
871
add_u_srcd:
872
        movew   ETEMP_EX(%a6),%d0
873
        andiw   #0x8000,%d0
874
        orw     #0x3fff,%d0     |force the exponent to +/- 1
875
        movew   %d0,ETEMP_EX(%a6) |in the denorm
876
        movel   USER_FPCR(%a6),%d0
877
        andil   #0x30,%d0
878
        fmovel  %d0,%fpcr               |set up users rmode and X
879
        fmovex  ETEMP(%a6),%fp0
880
        faddx   FPTEMP(%a6),%fp0
881
        fmovel  %fpsr,%d1
882
        orl     %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
883
        leal    WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
884
        fmovex  %fp0,WBTEMP(%a6)        |write result to memory
885
        lsrl    #4,%d0          |put rmode in lower 2 bits
886
        movel   USER_FPCR(%a6),%d1
887
        andil   #0xc0,%d1
888
        lsrl    #6,%d1          |put precision in upper word
889
        swap    %d1
890
        orl     %d0,%d1         |set up for round call
891
        clrl    %d0             |force sticky to zero
892
        bclrb   #sign_bit,WBTEMP_EX(%a6)
893
        sne     WBTEMP_SGN(%a6) |use internal format for round
894
        bsrl    round           |round result to users rmode & prec
895
        bfclr   WBTEMP_SGN(%a6){#0:#8}  |convert back to IEEE ext format
896
        beq     frcfpnr
897
        bsetb   #sign_bit,WBTEMP_EX(%a6)
898
        bra     frcfpnr
899
|
900
| Signs are alike:
901
|
902
add_same:
903
        cmpb    #0x0f,DNRM_FLG(%a6) |is dest the denorm?
904
        bnes    add_s_srcd
905
add_s_destd:
906
        leal    ETEMP(%a6),%a0
907
        movel   USER_FPCR(%a6),%d0
908
        andil   #0x30,%d0
909
        lsrl    #4,%d0          |put rmode in lower 2 bits
910
        movel   USER_FPCR(%a6),%d1
911
        andil   #0xc0,%d1
912
        lsrl    #6,%d1          |put precision in upper word
913
        swap    %d1
914
        orl     %d0,%d1         |set up for round call
915
        movel   #0x20000000,%d0 |set sticky for round
916
        bclrb   #sign_bit,ETEMP_EX(%a6)
917
        sne     ETEMP_SGN(%a6)
918
        bsrl    round           |round result to users rmode & prec
919
        bfclr   ETEMP_SGN(%a6){#0:#8}   |convert back to IEEE ext format
920
        beqs    add_s_dclr
921
        bsetb   #sign_bit,ETEMP_EX(%a6)
922
add_s_dclr:
923
        leal    WBTEMP(%a6),%a0
924
        movel   ETEMP(%a6),(%a0)        |write result to wbtemp
925
        movel   ETEMP_HI(%a6),4(%a0)
926
        movel   ETEMP_LO(%a6),8(%a0)
927
        tstw    ETEMP_EX(%a6)
928
        bgt     add_ckovf
929
        orl     #neg_mask,USER_FPSR(%a6)
930
        bra     add_ckovf
931
add_s_srcd:
932
        leal    FPTEMP(%a6),%a0
933
        movel   USER_FPCR(%a6),%d0
934
        andil   #0x30,%d0
935
        lsrl    #4,%d0          |put rmode in lower 2 bits
936
        movel   USER_FPCR(%a6),%d1
937
        andil   #0xc0,%d1
938
        lsrl    #6,%d1          |put precision in upper word
939
        swap    %d1
940
        orl     %d0,%d1         |set up for round call
941
        movel   #0x20000000,%d0 |set sticky for round
942
        bclrb   #sign_bit,FPTEMP_EX(%a6)
943
        sne     FPTEMP_SGN(%a6)
944
        bsrl    round           |round result to users rmode & prec
945
        bfclr   FPTEMP_SGN(%a6){#0:#8}  |convert back to IEEE ext format
946
        beqs    add_s_sclr
947
        bsetb   #sign_bit,FPTEMP_EX(%a6)
948
add_s_sclr:
949
        leal    WBTEMP(%a6),%a0
950
        movel   FPTEMP(%a6),(%a0)       |write result to wbtemp
951
        movel   FPTEMP_HI(%a6),4(%a0)
952
        movel   FPTEMP_LO(%a6),8(%a0)
953
        tstw    FPTEMP_EX(%a6)
954
        bgt     add_ckovf
955
        orl     #neg_mask,USER_FPSR(%a6)
956
add_ckovf:
957
        movew   WBTEMP_EX(%a6),%d0
958
        andiw   #0x7fff,%d0
959
        cmpiw   #0x7fff,%d0
960
        bne     frcfpnr
961
|
962
| The result has overflowed to $7fff exponent.  Set I, ovfl,
963
| and aovfl, and clr the mantissa (incorrectly set by the
964
| round routine.)
965
|
966
        orl     #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
967
        clrl    4(%a0)
968
        bra     frcfpnr
969
|
970
| Inst is fsub.
971
|
972
wrap_sub:
973
        cmpb    #0xff,DNRM_FLG(%a6) |if both ops denorm,
974
        beq     fix_stk          |restore to fpu
975
|
976
| One of the ops is denormalized.  Test for wrap condition
977
| and complete the instruction.
978
|
979
        cmpb    #0x0f,DNRM_FLG(%a6) |check for dest denorm
980
        bnes    sub_srcd
981
sub_destd:
982
        bsrl    ckinf_ns
983
        bne     fix_stk
984
        bfextu  ETEMP_EX(%a6){#1:#15},%d0       |get src exp (always pos)
985
        bfexts  FPTEMP_EX(%a6){#1:#15},%d1      |get dest exp (always neg)
986
        subl    %d1,%d0                 |subtract src from dest
987
        cmpl    #0x8000,%d0
988
        blt     fix_stk                 |if less, not wrap case
989
        bra     sub_wrap
990
sub_srcd:
991
        bsrl    ckinf_nd
992
        bne     fix_stk
993
        bfextu  FPTEMP_EX(%a6){#1:#15},%d0      |get dest exp (always pos)
994
        bfexts  ETEMP_EX(%a6){#1:#15},%d1       |get src exp (always neg)
995
        subl    %d1,%d0                 |subtract dest from src
996
        cmpl    #0x8000,%d0
997
        blt     fix_stk                 |if less, not wrap case
998
|
999
| Check the signs of the operands.  If they are alike, the fpu
1000
| can be used to subtract from the norm 1.0 with the sign of the
1001
| denorm and it will correctly generate the result in extended
1002
| precision.  We can then call round with no sticky and the result
1003
| will be correct for the user's rounding mode and precision.  If
1004
| the signs are unlike, we call round with the sticky bit set
1005
| and the result will be correct for the user's rounding mode and
1006
| precision.
1007
|
1008
sub_wrap:
1009
        movew   ETEMP_EX(%a6),%d0
1010
        movew   FPTEMP_EX(%a6),%d1
1011
        eorw    %d1,%d0
1012
        andiw   #0x8000,%d0
1013
        bne     sub_diff
1014
|
1015
| The signs are alike.
1016
|
1017
        cmpb    #0x0f,DNRM_FLG(%a6) |is dest the denorm?
1018
        bnes    sub_u_srcd
1019
        movew   FPTEMP_EX(%a6),%d0
1020
        andiw   #0x8000,%d0
1021
        orw     #0x3fff,%d0     |force the exponent to +/- 1
1022
        movew   %d0,FPTEMP_EX(%a6) |in the denorm
1023
        movel   USER_FPCR(%a6),%d0
1024
        andil   #0x30,%d0
1025
        fmovel  %d0,%fpcr               |set up users rmode and X
1026
        fmovex  FPTEMP(%a6),%fp0
1027
        fsubx   ETEMP(%a6),%fp0
1028
        fmovel  %fpsr,%d1
1029
        orl     %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
1030
        leal    WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
1031
        fmovex  %fp0,WBTEMP(%a6)        |write result to memory
1032
        lsrl    #4,%d0          |put rmode in lower 2 bits
1033
        movel   USER_FPCR(%a6),%d1
1034
        andil   #0xc0,%d1
1035
        lsrl    #6,%d1          |put precision in upper word
1036
        swap    %d1
1037
        orl     %d0,%d1         |set up for round call
1038
        clrl    %d0             |force sticky to zero
1039
        bclrb   #sign_bit,WBTEMP_EX(%a6)
1040
        sne     WBTEMP_SGN(%a6)
1041
        bsrl    round           |round result to users rmode & prec
1042
        bfclr   WBTEMP_SGN(%a6){#0:#8}  |convert back to IEEE ext format
1043
        beq     frcfpnr
1044
        bsetb   #sign_bit,WBTEMP_EX(%a6)
1045
        bra     frcfpnr
1046
sub_u_srcd:
1047
        movew   ETEMP_EX(%a6),%d0
1048
        andiw   #0x8000,%d0
1049
        orw     #0x3fff,%d0     |force the exponent to +/- 1
1050
        movew   %d0,ETEMP_EX(%a6) |in the denorm
1051
        movel   USER_FPCR(%a6),%d0
1052
        andil   #0x30,%d0
1053
        fmovel  %d0,%fpcr               |set up users rmode and X
1054
        fmovex  FPTEMP(%a6),%fp0
1055
        fsubx   ETEMP(%a6),%fp0
1056
        fmovel  %fpsr,%d1
1057
        orl     %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
1058
        leal    WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
1059
        fmovex  %fp0,WBTEMP(%a6)        |write result to memory
1060
        lsrl    #4,%d0          |put rmode in lower 2 bits
1061
        movel   USER_FPCR(%a6),%d1
1062
        andil   #0xc0,%d1
1063
        lsrl    #6,%d1          |put precision in upper word
1064
        swap    %d1
1065
        orl     %d0,%d1         |set up for round call
1066
        clrl    %d0             |force sticky to zero
1067
        bclrb   #sign_bit,WBTEMP_EX(%a6)
1068
        sne     WBTEMP_SGN(%a6)
1069
        bsrl    round           |round result to users rmode & prec
1070
        bfclr   WBTEMP_SGN(%a6){#0:#8}  |convert back to IEEE ext format
1071
        beq     frcfpnr
1072
        bsetb   #sign_bit,WBTEMP_EX(%a6)
1073
        bra     frcfpnr
1074
|
1075
| Signs are unlike:
1076
|
1077
sub_diff:
1078
        cmpb    #0x0f,DNRM_FLG(%a6) |is dest the denorm?
1079
        bnes    sub_s_srcd
1080
sub_s_destd:
1081
        leal    ETEMP(%a6),%a0
1082
        movel   USER_FPCR(%a6),%d0
1083
        andil   #0x30,%d0
1084
        lsrl    #4,%d0          |put rmode in lower 2 bits
1085
        movel   USER_FPCR(%a6),%d1
1086
        andil   #0xc0,%d1
1087
        lsrl    #6,%d1          |put precision in upper word
1088
        swap    %d1
1089
        orl     %d0,%d1         |set up for round call
1090
        movel   #0x20000000,%d0 |set sticky for round
1091
|
1092
| Since the dest is the denorm, the sign is the opposite of the
1093
| norm sign.
1094
|
1095
        eoriw   #0x8000,ETEMP_EX(%a6)   |flip sign on result
1096
        tstw    ETEMP_EX(%a6)
1097
        bgts    sub_s_dwr
1098
        orl     #neg_mask,USER_FPSR(%a6)
1099
sub_s_dwr:
1100
        bclrb   #sign_bit,ETEMP_EX(%a6)
1101
        sne     ETEMP_SGN(%a6)
1102
        bsrl    round           |round result to users rmode & prec
1103
        bfclr   ETEMP_SGN(%a6){#0:#8}   |convert back to IEEE ext format
1104
        beqs    sub_s_dclr
1105
        bsetb   #sign_bit,ETEMP_EX(%a6)
1106
sub_s_dclr:
1107
        leal    WBTEMP(%a6),%a0
1108
        movel   ETEMP(%a6),(%a0)        |write result to wbtemp
1109
        movel   ETEMP_HI(%a6),4(%a0)
1110
        movel   ETEMP_LO(%a6),8(%a0)
1111
        bra     sub_ckovf
1112
sub_s_srcd:
1113
        leal    FPTEMP(%a6),%a0
1114
        movel   USER_FPCR(%a6),%d0
1115
        andil   #0x30,%d0
1116
        lsrl    #4,%d0          |put rmode in lower 2 bits
1117
        movel   USER_FPCR(%a6),%d1
1118
        andil   #0xc0,%d1
1119
        lsrl    #6,%d1          |put precision in upper word
1120
        swap    %d1
1121
        orl     %d0,%d1         |set up for round call
1122
        movel   #0x20000000,%d0 |set sticky for round
1123
        bclrb   #sign_bit,FPTEMP_EX(%a6)
1124
        sne     FPTEMP_SGN(%a6)
1125
        bsrl    round           |round result to users rmode & prec
1126
        bfclr   FPTEMP_SGN(%a6){#0:#8}  |convert back to IEEE ext format
1127
        beqs    sub_s_sclr
1128
        bsetb   #sign_bit,FPTEMP_EX(%a6)
1129
sub_s_sclr:
1130
        leal    WBTEMP(%a6),%a0
1131
        movel   FPTEMP(%a6),(%a0)       |write result to wbtemp
1132
        movel   FPTEMP_HI(%a6),4(%a0)
1133
        movel   FPTEMP_LO(%a6),8(%a0)
1134
        tstw    FPTEMP_EX(%a6)
1135
        bgt     sub_ckovf
1136
        orl     #neg_mask,USER_FPSR(%a6)
1137
sub_ckovf:
1138
        movew   WBTEMP_EX(%a6),%d0
1139
        andiw   #0x7fff,%d0
1140
        cmpiw   #0x7fff,%d0
1141
        bne     frcfpnr
1142
|
1143
| The result has overflowed to $7fff exponent.  Set I, ovfl,
1144
| and aovfl, and clr the mantissa (incorrectly set by the
1145
| round routine.)
1146
|
1147
        orl     #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
1148
        clrl    4(%a0)
1149
        bra     frcfpnr
1150
|
1151
| Inst is fcmp.
1152
|
1153
wrap_cmp:
1154
        cmpb    #0xff,DNRM_FLG(%a6) |if both ops denorm,
1155
        beq     fix_stk          |restore to fpu
1156
|
1157
| One of the ops is denormalized.  Test for wrap condition
1158
| and complete the instruction.
1159
|
1160
        cmpb    #0x0f,DNRM_FLG(%a6) |check for dest denorm
1161
        bnes    cmp_srcd
1162
cmp_destd:
1163
        bsrl    ckinf_ns
1164
        bne     fix_stk
1165
        bfextu  ETEMP_EX(%a6){#1:#15},%d0       |get src exp (always pos)
1166
        bfexts  FPTEMP_EX(%a6){#1:#15},%d1      |get dest exp (always neg)
1167
        subl    %d1,%d0                 |subtract dest from src
1168
        cmpl    #0x8000,%d0
1169
        blt     fix_stk                 |if less, not wrap case
1170
        tstw    ETEMP_EX(%a6)           |set N to ~sign_of(src)
1171
        bge     cmp_setn
1172
        rts
1173
cmp_srcd:
1174
        bsrl    ckinf_nd
1175
        bne     fix_stk
1176
        bfextu  FPTEMP_EX(%a6){#1:#15},%d0      |get dest exp (always pos)
1177
        bfexts  ETEMP_EX(%a6){#1:#15},%d1       |get src exp (always neg)
1178
        subl    %d1,%d0                 |subtract src from dest
1179
        cmpl    #0x8000,%d0
1180
        blt     fix_stk                 |if less, not wrap case
1181
        tstw    FPTEMP_EX(%a6)          |set N to sign_of(dest)
1182
        blt     cmp_setn
1183
        rts
1184
cmp_setn:
1185
        orl     #neg_mask,USER_FPSR(%a6)
1186
        rts
1187
 
1188
|
1189
| Inst is fmul.
1190
|
1191
wrap_mul:
1192
        cmpb    #0xff,DNRM_FLG(%a6) |if both ops denorm,
1193
        beq     force_unf       |force an underflow (really!)
1194
|
1195
| One of the ops is denormalized.  Test for wrap condition
1196
| and complete the instruction.
1197
|
1198
        cmpb    #0x0f,DNRM_FLG(%a6) |check for dest denorm
1199
        bnes    mul_srcd
1200
mul_destd:
1201
        bsrl    ckinf_ns
1202
        bne     fix_stk
1203
        bfextu  ETEMP_EX(%a6){#1:#15},%d0       |get src exp (always pos)
1204
        bfexts  FPTEMP_EX(%a6){#1:#15},%d1      |get dest exp (always neg)
1205
        addl    %d1,%d0                 |subtract dest from src
1206
        bgt     fix_stk
1207
        bra     force_unf
1208
mul_srcd:
1209
        bsrl    ckinf_nd
1210
        bne     fix_stk
1211
        bfextu  FPTEMP_EX(%a6){#1:#15},%d0      |get dest exp (always pos)
1212
        bfexts  ETEMP_EX(%a6){#1:#15},%d1       |get src exp (always neg)
1213
        addl    %d1,%d0                 |subtract src from dest
1214
        bgt     fix_stk
1215
 
1216
|
1217
| This code handles the case of the instruction resulting in
1218
| an underflow condition.
1219
|
1220
force_unf:
1221
        bclrb   #E1,E_BYTE(%a6)
1222
        orl     #unfinx_mask,USER_FPSR(%a6)
1223
        clrw    NMNEXC(%a6)
1224
        clrb    WBTEMP_SGN(%a6)
1225
        movew   ETEMP_EX(%a6),%d0               |find the sign of the result
1226
        movew   FPTEMP_EX(%a6),%d1
1227
        eorw    %d1,%d0
1228
        andiw   #0x8000,%d0
1229
        beqs    frcunfcont
1230
        st      WBTEMP_SGN(%a6)
1231
frcunfcont:
1232
        lea     WBTEMP(%a6),%a0         |point a0 to memory location
1233
        movew   CMDREG1B(%a6),%d0
1234
        btstl   #6,%d0                  |test for forced precision
1235
        beqs    frcunf_fpcr
1236
        btstl   #2,%d0                  |check for double
1237
        bnes    frcunf_dbl
1238
        movel   #0x1,%d0                        |inst is forced single
1239
        bras    frcunf_rnd
1240
frcunf_dbl:
1241
        movel   #0x2,%d0                        |inst is forced double
1242
        bras    frcunf_rnd
1243
frcunf_fpcr:
1244
        bfextu  FPCR_MODE(%a6){#0:#2},%d0       |inst not forced - use fpcr prec
1245
frcunf_rnd:
1246
        bsrl    unf_sub                 |get correct result based on
1247
|                                       ;round precision/mode.  This
1248
|                                       ;sets FPSR_CC correctly
1249
        bfclr   WBTEMP_SGN(%a6){#0:#8}  |convert back to IEEE ext format
1250
        beqs    frcfpn
1251
        bsetb   #sign_bit,WBTEMP_EX(%a6)
1252
        bra     frcfpn
1253
 
1254
|
1255
| Write the result to the user's fpn.  All results must be HUGE to be
1256
| written; otherwise the results would have overflowed or underflowed.
1257
| If the rounding precision is single or double, the ovf_res routine
1258
| is needed to correctly supply the max value.
1259
|
1260
frcfpnr:
1261
        movew   CMDREG1B(%a6),%d0
1262
        btstl   #6,%d0                  |test for forced precision
1263
        beqs    frcfpn_fpcr
1264
        btstl   #2,%d0                  |check for double
1265
        bnes    frcfpn_dbl
1266
        movel   #0x1,%d0                        |inst is forced single
1267
        bras    frcfpn_rnd
1268
frcfpn_dbl:
1269
        movel   #0x2,%d0                        |inst is forced double
1270
        bras    frcfpn_rnd
1271
frcfpn_fpcr:
1272
        bfextu  FPCR_MODE(%a6){#0:#2},%d0       |inst not forced - use fpcr prec
1273
        tstb    %d0
1274
        beqs    frcfpn                  |if extended, write what you got
1275
frcfpn_rnd:
1276
        bclrb   #sign_bit,WBTEMP_EX(%a6)
1277
        sne     WBTEMP_SGN(%a6)
1278
        bsrl    ovf_res                 |get correct result based on
1279
|                                       ;round precision/mode.  This
1280
|                                       ;sets FPSR_CC correctly
1281
        bfclr   WBTEMP_SGN(%a6){#0:#8}  |convert back to IEEE ext format
1282
        beqs    frcfpn_clr
1283
        bsetb   #sign_bit,WBTEMP_EX(%a6)
1284
frcfpn_clr:
1285
        orl     #ovfinx_mask,USER_FPSR(%a6)
1286
|
1287
| Perform the write.
1288
|
1289
frcfpn:
1290
        bfextu  CMDREG1B(%a6){#6:#3},%d0        |extract fp destination register
1291
        cmpib   #3,%d0
1292
        bles    frc0123                 |check if dest is fp0-fp3
1293
        movel   #7,%d1
1294
        subl    %d0,%d1
1295
        clrl    %d0
1296
        bsetl   %d1,%d0
1297
        fmovemx WBTEMP(%a6),%d0
1298
        rts
1299
frc0123:
1300
        cmpib   #0,%d0
1301
        beqs    frc0_dst
1302
        cmpib   #1,%d0
1303
        beqs    frc1_dst
1304
        cmpib   #2,%d0
1305
        beqs    frc2_dst
1306
frc3_dst:
1307
        movel   WBTEMP_EX(%a6),USER_FP3(%a6)
1308
        movel   WBTEMP_HI(%a6),USER_FP3+4(%a6)
1309
        movel   WBTEMP_LO(%a6),USER_FP3+8(%a6)
1310
        rts
1311
frc2_dst:
1312
        movel   WBTEMP_EX(%a6),USER_FP2(%a6)
1313
        movel   WBTEMP_HI(%a6),USER_FP2+4(%a6)
1314
        movel   WBTEMP_LO(%a6),USER_FP2+8(%a6)
1315
        rts
1316
frc1_dst:
1317
        movel   WBTEMP_EX(%a6),USER_FP1(%a6)
1318
        movel   WBTEMP_HI(%a6),USER_FP1+4(%a6)
1319
        movel   WBTEMP_LO(%a6),USER_FP1+8(%a6)
1320
        rts
1321
frc0_dst:
1322
        movel   WBTEMP_EX(%a6),USER_FP0(%a6)
1323
        movel   WBTEMP_HI(%a6),USER_FP0+4(%a6)
1324
        movel   WBTEMP_LO(%a6),USER_FP0+8(%a6)
1325
        rts
1326
 
1327
|
1328
| Write etemp to fpn.
1329
| A check is made on enabled and signalled snan exceptions,
1330
| and the destination is not overwritten if this condition exists.
1331
| This code is designed to make fmoveins of unsupported data types
1332
| faster.
1333
|
1334
wr_etemp:
1335
        btstb   #snan_bit,FPSR_EXCEPT(%a6)      |if snan is set, and
1336
        beqs    fmoveinc                |enabled, force restore
1337
        btstb   #snan_bit,FPCR_ENABLE(%a6) |and don't overwrite
1338
        beqs    fmoveinc                |the dest
1339
        movel   ETEMP_EX(%a6),FPTEMP_EX(%a6)    |set up fptemp sign for
1340
|                                               ;snan handler
1341
        tstb    ETEMP(%a6)              |check for negative
1342
        blts    snan_neg
1343
        rts
1344
snan_neg:
1345
        orl     #neg_bit,USER_FPSR(%a6) |snan is negative; set N
1346
        rts
1347
fmoveinc:
1348
        clrw    NMNEXC(%a6)
1349
        bclrb   #E1,E_BYTE(%a6)
1350
        moveb   STAG(%a6),%d0           |check if stag is inf
1351
        andib   #0xe0,%d0
1352
        cmpib   #0x40,%d0
1353
        bnes    fminc_cnan
1354
        orl     #inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set I
1355
        tstw    LOCAL_EX(%a0)           |check sign
1356
        bges    fminc_con
1357
        orl     #neg_mask,USER_FPSR(%a6)
1358
        bra     fminc_con
1359
fminc_cnan:
1360
        cmpib   #0x60,%d0                       |check if stag is NaN
1361
        bnes    fminc_czero
1362
        orl     #nan_mask,USER_FPSR(%a6) |if nan, nothing yet has set NaN
1363
        movel   ETEMP_EX(%a6),FPTEMP_EX(%a6)    |set up fptemp sign for
1364
|                                               ;snan handler
1365
        tstw    LOCAL_EX(%a0)           |check sign
1366
        bges    fminc_con
1367
        orl     #neg_mask,USER_FPSR(%a6)
1368
        bra     fminc_con
1369
fminc_czero:
1370
        cmpib   #0x20,%d0                       |check if zero
1371
        bnes    fminc_con
1372
        orl     #z_mask,USER_FPSR(%a6)  |if zero, set Z
1373
        tstw    LOCAL_EX(%a0)           |check sign
1374
        bges    fminc_con
1375
        orl     #neg_mask,USER_FPSR(%a6)
1376
fminc_con:
1377
        bfextu  CMDREG1B(%a6){#6:#3},%d0        |extract fp destination register
1378
        cmpib   #3,%d0
1379
        bles    fp0123                  |check if dest is fp0-fp3
1380
        movel   #7,%d1
1381
        subl    %d0,%d1
1382
        clrl    %d0
1383
        bsetl   %d1,%d0
1384
        fmovemx ETEMP(%a6),%d0
1385
        rts
1386
 
1387
fp0123:
1388
        cmpib   #0,%d0
1389
        beqs    fp0_dst
1390
        cmpib   #1,%d0
1391
        beqs    fp1_dst
1392
        cmpib   #2,%d0
1393
        beqs    fp2_dst
1394
fp3_dst:
1395
        movel   ETEMP_EX(%a6),USER_FP3(%a6)
1396
        movel   ETEMP_HI(%a6),USER_FP3+4(%a6)
1397
        movel   ETEMP_LO(%a6),USER_FP3+8(%a6)
1398
        rts
1399
fp2_dst:
1400
        movel   ETEMP_EX(%a6),USER_FP2(%a6)
1401
        movel   ETEMP_HI(%a6),USER_FP2+4(%a6)
1402
        movel   ETEMP_LO(%a6),USER_FP2+8(%a6)
1403
        rts
1404
fp1_dst:
1405
        movel   ETEMP_EX(%a6),USER_FP1(%a6)
1406
        movel   ETEMP_HI(%a6),USER_FP1+4(%a6)
1407
        movel   ETEMP_LO(%a6),USER_FP1+8(%a6)
1408
        rts
1409
fp0_dst:
1410
        movel   ETEMP_EX(%a6),USER_FP0(%a6)
1411
        movel   ETEMP_HI(%a6),USER_FP0+4(%a6)
1412
        movel   ETEMP_LO(%a6),USER_FP0+8(%a6)
1413
        rts
1414
 
1415
opclass3:
1416
        st      CU_ONLY(%a6)
1417
        movew   CMDREG1B(%a6),%d0       |check if packed moveout
1418
        andiw   #0x0c00,%d0     |isolate last 2 bits of size field
1419
        cmpiw   #0x0c00,%d0     |if size is 011 or 111, it is packed
1420
        beq     pack_out        |else it is norm or denorm
1421
        bra     mv_out
1422
 
1423
 
1424
|
1425
|       MOVE OUT
1426
|
1427
 
1428
mv_tbl:
1429
        .long   li
1430
        .long   sgp
1431
        .long   xp
1432
        .long   mvout_end       |should never be taken
1433
        .long   wi
1434
        .long   dp
1435
        .long   bi
1436
        .long   mvout_end       |should never be taken
1437
mv_out:
1438
        bfextu  CMDREG1B(%a6){#3:#3},%d1        |put source specifier in d1
1439
        leal    mv_tbl,%a0
1440
        movel   %a0@(%d1:l:4),%a0
1441
        jmp     (%a0)
1442
 
1443
|
1444
| This exit is for move-out to memory.  The aunfl bit is
1445
| set if the result is inex and unfl is signalled.
1446
|
1447
mvout_end:
1448
        btstb   #inex2_bit,FPSR_EXCEPT(%a6)
1449
        beqs    no_aufl
1450
        btstb   #unfl_bit,FPSR_EXCEPT(%a6)
1451
        beqs    no_aufl
1452
        bsetb   #aunfl_bit,FPSR_AEXCEPT(%a6)
1453
no_aufl:
1454
        clrw    NMNEXC(%a6)
1455
        bclrb   #E1,E_BYTE(%a6)
1456
        fmovel  #0,%FPSR                        |clear any cc bits from res_func
1457
|
1458
| Return ETEMP to extended format from internal extended format so
1459
| that gen_except will have a correctly signed value for ovfl/unfl
1460
| handlers.
1461
|
1462
        bfclr   ETEMP_SGN(%a6){#0:#8}
1463
        beqs    mvout_con
1464
        bsetb   #sign_bit,ETEMP_EX(%a6)
1465
mvout_con:
1466
        rts
1467
|
1468
| This exit is for move-out to int register.  The aunfl bit is
1469
| not set in any case for this move.
1470
|
1471
mvouti_end:
1472
        clrw    NMNEXC(%a6)
1473
        bclrb   #E1,E_BYTE(%a6)
1474
        fmovel  #0,%FPSR                        |clear any cc bits from res_func
1475
|
1476
| Return ETEMP to extended format from internal extended format so
1477
| that gen_except will have a correctly signed value for ovfl/unfl
1478
| handlers.
1479
|
1480
        bfclr   ETEMP_SGN(%a6){#0:#8}
1481
        beqs    mvouti_con
1482
        bsetb   #sign_bit,ETEMP_EX(%a6)
1483
mvouti_con:
1484
        rts
1485
|
1486
| li is used to handle a long integer source specifier
1487
|
1488
 
1489
li:
1490
        moveql  #4,%d0          |set byte count
1491
 
1492
        btstb   #7,STAG(%a6)    |check for extended denorm
1493
        bne     int_dnrm        |if so, branch
1494
 
1495
        fmovemx ETEMP(%a6),%fp0-%fp0
1496
        fcmpd   #0x41dfffffffc00000,%fp0
1497
| 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
1498
        fbge    lo_plrg
1499
        fcmpd   #0xc1e0000000000000,%fp0
1500
| c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
1501
        fble    lo_nlrg
1502
|
1503
| at this point, the answer is between the largest pos and neg values
1504
|
1505
        movel   USER_FPCR(%a6),%d1      |use user's rounding mode
1506
        andil   #0x30,%d1
1507
        fmovel  %d1,%fpcr
1508
        fmovel  %fp0,L_SCR1(%a6)        |let the 040 perform conversion
1509
        fmovel %fpsr,%d1
1510
        orl     %d1,USER_FPSR(%a6)      |capture inex2/ainex if set
1511
        bra     int_wrt
1512
 
1513
 
1514
lo_plrg:
1515
        movel   #0x7fffffff,L_SCR1(%a6) |answer is largest positive int
1516
        fbeq    int_wrt                 |exact answer
1517
        fcmpd   #0x41dfffffffe00000,%fp0
1518
| 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
1519
        fbge    int_operr               |set operr
1520
        bra     int_inx                 |set inexact
1521
 
1522
lo_nlrg:
1523
        movel   #0x80000000,L_SCR1(%a6)
1524
        fbeq    int_wrt                 |exact answer
1525
        fcmpd   #0xc1e0000000100000,%fp0
1526
| c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
1527
        fblt    int_operr               |set operr
1528
        bra     int_inx                 |set inexact
1529
 
1530
|
1531
| wi is used to handle a word integer source specifier
1532
|
1533
 
1534
wi:
1535
        moveql  #2,%d0          |set byte count
1536
 
1537
        btstb   #7,STAG(%a6)    |check for extended denorm
1538
        bne     int_dnrm        |branch if so
1539
 
1540
        fmovemx ETEMP(%a6),%fp0-%fp0
1541
        fcmps   #0x46fffe00,%fp0
1542
| 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
1543
        fbge    wo_plrg
1544
        fcmps   #0xc7000000,%fp0
1545
| c7000000 in sgl prec = c00e00008000000000000000 in ext prec
1546
        fble    wo_nlrg
1547
 
1548
|
1549
| at this point, the answer is between the largest pos and neg values
1550
|
1551
        movel   USER_FPCR(%a6),%d1      |use user's rounding mode
1552
        andil   #0x30,%d1
1553
        fmovel  %d1,%fpcr
1554
        fmovew  %fp0,L_SCR1(%a6)        |let the 040 perform conversion
1555
        fmovel %fpsr,%d1
1556
        orl     %d1,USER_FPSR(%a6)      |capture inex2/ainex if set
1557
        bra     int_wrt
1558
 
1559
wo_plrg:
1560
        movew   #0x7fff,L_SCR1(%a6)     |answer is largest positive int
1561
        fbeq    int_wrt                 |exact answer
1562
        fcmps   #0x46ffff00,%fp0
1563
| 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
1564
        fbge    int_operr               |set operr
1565
        bra     int_inx                 |set inexact
1566
 
1567
wo_nlrg:
1568
        movew   #0x8000,L_SCR1(%a6)
1569
        fbeq    int_wrt                 |exact answer
1570
        fcmps   #0xc7000080,%fp0
1571
| c7000080 in sgl prec = c00e00008000800000000000 in ext prec
1572
        fblt    int_operr               |set operr
1573
        bra     int_inx                 |set inexact
1574
 
1575
|
1576
| bi is used to handle a byte integer source specifier
1577
|
1578
 
1579
bi:
1580
        moveql  #1,%d0          |set byte count
1581
 
1582
        btstb   #7,STAG(%a6)    |check for extended denorm
1583
        bne     int_dnrm        |branch if so
1584
 
1585
        fmovemx ETEMP(%a6),%fp0-%fp0
1586
        fcmps   #0x42fe0000,%fp0
1587
| 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
1588
        fbge    by_plrg
1589
        fcmps   #0xc3000000,%fp0
1590
| c3000000 in sgl prec = c00600008000000000000000 in ext prec
1591
        fble    by_nlrg
1592
 
1593
|
1594
| at this point, the answer is between the largest pos and neg values
1595
|
1596
        movel   USER_FPCR(%a6),%d1      |use user's rounding mode
1597
        andil   #0x30,%d1
1598
        fmovel  %d1,%fpcr
1599
        fmoveb  %fp0,L_SCR1(%a6)        |let the 040 perform conversion
1600
        fmovel %fpsr,%d1
1601
        orl     %d1,USER_FPSR(%a6)      |capture inex2/ainex if set
1602
        bra     int_wrt
1603
 
1604
by_plrg:
1605
        moveb   #0x7f,L_SCR1(%a6)               |answer is largest positive int
1606
        fbeq    int_wrt                 |exact answer
1607
        fcmps   #0x42ff0000,%fp0
1608
| 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
1609
        fbge    int_operr               |set operr
1610
        bra     int_inx                 |set inexact
1611
 
1612
by_nlrg:
1613
        moveb   #0x80,L_SCR1(%a6)
1614
        fbeq    int_wrt                 |exact answer
1615
        fcmps   #0xc3008000,%fp0
1616
| c3008000 in sgl prec = c00600008080000000000000 in ext prec
1617
        fblt    int_operr               |set operr
1618
        bra     int_inx                 |set inexact
1619
 
1620
|
1621
| Common integer routines
1622
|
1623
| int_drnrm---account for possible nonzero result for round up with positive
1624
| operand and round down for negative answer.  In the first case (result = 1)
1625
| byte-width (store in d0) of result must be honored.  In the second case,
1626
| -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).
1627
 
1628
int_dnrm:
1629
        movel   #0,L_SCR1(%a6)  | initialize result to 0
1630
        bfextu  FPCR_MODE(%a6){#2:#2},%d1       | d1 is the rounding mode
1631
        cmpb    #2,%d1
1632
        bmis    int_inx         | if RN or RZ, done
1633
        bnes    int_rp          | if RP, continue below
1634
        tstw    ETEMP(%a6)      | RM: store -1 in L_SCR1 if src is negative
1635
        bpls    int_inx         | otherwise result is 0
1636
        movel   #-1,L_SCR1(%a6)
1637
        bras    int_inx
1638
int_rp:
1639
        tstw    ETEMP(%a6)      | RP: store +1 of proper width in L_SCR1 if
1640
|                               ; source is greater than 0
1641
        bmis    int_inx         | otherwise, result is 0
1642
        lea     L_SCR1(%a6),%a1 | a1 is address of L_SCR1
1643
        addal   %d0,%a1         | offset by destination width -1
1644
        subal   #1,%a1
1645
        bsetb   #0,(%a1)                | set low bit at a1 address
1646
int_inx:
1647
        oril    #inx2a_mask,USER_FPSR(%a6)
1648
        bras    int_wrt
1649
int_operr:
1650
        fmovemx %fp0-%fp0,FPTEMP(%a6)   |FPTEMP must contain the extended
1651
|                               ;precision source that needs to be
1652
|                               ;converted to integer this is required
1653
|                               ;if the operr exception is enabled.
1654
|                               ;set operr/aiop (no inex2 on int ovfl)
1655
 
1656
        oril    #opaop_mask,USER_FPSR(%a6)
1657
|                               ;fall through to perform int_wrt
1658
int_wrt:
1659
        movel   EXC_EA(%a6),%a1 |load destination address
1660
        tstl    %a1             |check to see if it is a dest register
1661
        beqs    wrt_dn          |write data register
1662
        lea     L_SCR1(%a6),%a0 |point to supervisor source address
1663
        bsrl    mem_write
1664
        bra     mvouti_end
1665
 
1666
wrt_dn:
1667
        movel   %d0,-(%sp)      |d0 currently contains the size to write
1668
        bsrl    get_fline       |get_fline returns Dn in d0
1669
        andiw   #0x7,%d0                |isolate register
1670
        movel   (%sp)+,%d1      |get size
1671
        cmpil   #4,%d1          |most frequent case
1672
        beqs    sz_long
1673
        cmpil   #2,%d1
1674
        bnes    sz_con
1675
        orl     #8,%d0          |add 'word' size to register#
1676
        bras    sz_con
1677
sz_long:
1678
        orl     #0x10,%d0               |add 'long' size to register#
1679
sz_con:
1680
        movel   %d0,%d1         |reg_dest expects size:reg in d1
1681
        bsrl    reg_dest        |load proper data register
1682
        bra     mvouti_end
1683
xp:
1684
        lea     ETEMP(%a6),%a0
1685
        bclrb   #sign_bit,LOCAL_EX(%a0)
1686
        sne     LOCAL_SGN(%a0)
1687
        btstb   #7,STAG(%a6)    |check for extended denorm
1688
        bne     xdnrm
1689
        clrl    %d0
1690
        bras    do_fp           |do normal case
1691
sgp:
1692
        lea     ETEMP(%a6),%a0
1693
        bclrb   #sign_bit,LOCAL_EX(%a0)
1694
        sne     LOCAL_SGN(%a0)
1695
        btstb   #7,STAG(%a6)    |check for extended denorm
1696
        bne     sp_catas        |branch if so
1697
        movew   LOCAL_EX(%a0),%d0
1698
        lea     sp_bnds,%a1
1699
        cmpw    (%a1),%d0
1700
        blt     sp_under
1701
        cmpw    2(%a1),%d0
1702
        bgt     sp_over
1703
        movel   #1,%d0          |set destination format to single
1704
        bras    do_fp           |do normal case
1705
dp:
1706
        lea     ETEMP(%a6),%a0
1707
        bclrb   #sign_bit,LOCAL_EX(%a0)
1708
        sne     LOCAL_SGN(%a0)
1709
 
1710
        btstb   #7,STAG(%a6)    |check for extended denorm
1711
        bne     dp_catas        |branch if so
1712
 
1713
        movew   LOCAL_EX(%a0),%d0
1714
        lea     dp_bnds,%a1
1715
 
1716
        cmpw    (%a1),%d0
1717
        blt     dp_under
1718
        cmpw    2(%a1),%d0
1719
        bgt     dp_over
1720
 
1721
        movel   #2,%d0          |set destination format to double
1722
|                               ;fall through to do_fp
1723
|
1724
do_fp:
1725
        bfextu  FPCR_MODE(%a6){#2:#2},%d1       |rnd mode in d1
1726
        swap    %d0                     |rnd prec in upper word
1727
        addl    %d0,%d1                 |d1 has PREC/MODE info
1728
 
1729
        clrl    %d0                     |clear g,r,s
1730
 
1731
        bsrl    round                   |round
1732
 
1733
        movel   %a0,%a1
1734
        movel   EXC_EA(%a6),%a0
1735
 
1736
        bfextu  CMDREG1B(%a6){#3:#3},%d1        |extract destination format
1737
|                                       ;at this point only the dest
1738
|                                       ;formats sgl, dbl, ext are
1739
|                                       ;possible
1740
        cmpb    #2,%d1
1741
        bgts    ddbl                    |double=5, extended=2, single=1
1742
        bnes    dsgl
1743
|                                       ;fall through to dext
1744
dext:
1745
        bsrl    dest_ext
1746
        bra     mvout_end
1747
dsgl:
1748
        bsrl    dest_sgl
1749
        bra     mvout_end
1750
ddbl:
1751
        bsrl    dest_dbl
1752
        bra     mvout_end
1753
 
1754
|
1755
| Handle possible denorm or catastrophic underflow cases here
1756
|
1757
xdnrm:
1758
        bsr     set_xop         |initialize WBTEMP
1759
        bsetb   #wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15
1760
 
1761
        movel   %a0,%a1
1762
        movel   EXC_EA(%a6),%a0 |a0 has the destination pointer
1763
        bsrl    dest_ext        |store to memory
1764
        bsetb   #unfl_bit,FPSR_EXCEPT(%a6)
1765
        bra     mvout_end
1766
 
1767
sp_under:
1768
        bsetb   #etemp15_bit,STAG(%a6)
1769
 
1770
        cmpw    4(%a1),%d0
1771
        blts    sp_catas        |catastrophic underflow case
1772
 
1773
        movel   #1,%d0          |load in round precision
1774
        movel   #sgl_thresh,%d1 |load in single denorm threshold
1775
        bsrl    dpspdnrm        |expects d1 to have the proper
1776
|                               ;denorm threshold
1777
        bsrl    dest_sgl        |stores value to destination
1778
        bsetb   #unfl_bit,FPSR_EXCEPT(%a6)
1779
        bra     mvout_end       |exit
1780
 
1781
dp_under:
1782
        bsetb   #etemp15_bit,STAG(%a6)
1783
 
1784
        cmpw    4(%a1),%d0
1785
        blts    dp_catas        |catastrophic underflow case
1786
 
1787
        movel   #dbl_thresh,%d1 |load in double precision threshold
1788
        movel   #2,%d0
1789
        bsrl    dpspdnrm        |expects d1 to have proper
1790
|                               ;denorm threshold
1791
|                               ;expects d0 to have round precision
1792
        bsrl    dest_dbl        |store value to destination
1793
        bsetb   #unfl_bit,FPSR_EXCEPT(%a6)
1794
        bra     mvout_end       |exit
1795
 
1796
|
1797
| Handle catastrophic underflow cases here
1798
|
1799
sp_catas:
1800
| Temp fix for z bit set in unf_sub
1801
        movel   USER_FPSR(%a6),-(%a7)
1802
 
1803
        movel   #1,%d0          |set round precision to sgl
1804
 
1805
        bsrl    unf_sub         |a0 points to result
1806
 
1807
        movel   (%a7)+,USER_FPSR(%a6)
1808
 
1809
        movel   #1,%d0
1810
        subw    %d0,LOCAL_EX(%a0) |account for difference between
1811
|                               ;denorm/norm bias
1812
 
1813
        movel   %a0,%a1         |a1 has the operand input
1814
        movel   EXC_EA(%a6),%a0 |a0 has the destination pointer
1815
 
1816
        bsrl    dest_sgl        |store the result
1817
        oril    #unfinx_mask,USER_FPSR(%a6)
1818
        bra     mvout_end
1819
 
1820
dp_catas:
1821
| Temp fix for z bit set in unf_sub
1822
        movel   USER_FPSR(%a6),-(%a7)
1823
 
1824
        movel   #2,%d0          |set round precision to dbl
1825
        bsrl    unf_sub         |a0 points to result
1826
 
1827
        movel   (%a7)+,USER_FPSR(%a6)
1828
 
1829
        movel   #1,%d0
1830
        subw    %d0,LOCAL_EX(%a0) |account for difference between
1831
|                               ;denorm/norm bias
1832
 
1833
        movel   %a0,%a1         |a1 has the operand input
1834
        movel   EXC_EA(%a6),%a0 |a0 has the destination pointer
1835
 
1836
        bsrl    dest_dbl        |store the result
1837
        oril    #unfinx_mask,USER_FPSR(%a6)
1838
        bra     mvout_end
1839
 
1840
|
1841
| Handle catastrophic overflow cases here
1842
|
1843
sp_over:
1844
| Temp fix for z bit set in unf_sub
1845
        movel   USER_FPSR(%a6),-(%a7)
1846
 
1847
        movel   #1,%d0
1848
        leal    FP_SCR1(%a6),%a0        |use FP_SCR1 for creating result
1849
        movel   ETEMP_EX(%a6),(%a0)
1850
        movel   ETEMP_HI(%a6),4(%a0)
1851
        movel   ETEMP_LO(%a6),8(%a0)
1852
        bsrl    ovf_res
1853
 
1854
        movel   (%a7)+,USER_FPSR(%a6)
1855
 
1856
        movel   %a0,%a1
1857
        movel   EXC_EA(%a6),%a0
1858
        bsrl    dest_sgl
1859
        orl     #ovfinx_mask,USER_FPSR(%a6)
1860
        bra     mvout_end
1861
 
1862
dp_over:
1863
| Temp fix for z bit set in ovf_res
1864
        movel   USER_FPSR(%a6),-(%a7)
1865
 
1866
        movel   #2,%d0
1867
        leal    FP_SCR1(%a6),%a0        |use FP_SCR1 for creating result
1868
        movel   ETEMP_EX(%a6),(%a0)
1869
        movel   ETEMP_HI(%a6),4(%a0)
1870
        movel   ETEMP_LO(%a6),8(%a0)
1871
        bsrl    ovf_res
1872
 
1873
        movel   (%a7)+,USER_FPSR(%a6)
1874
 
1875
        movel   %a0,%a1
1876
        movel   EXC_EA(%a6),%a0
1877
        bsrl    dest_dbl
1878
        orl     #ovfinx_mask,USER_FPSR(%a6)
1879
        bra     mvout_end
1880
 
1881
|
1882
|       DPSPDNRM
1883
|
1884
| This subroutine takes an extended normalized number and denormalizes
1885
| it to the given round precision. This subroutine also decrements
1886
| the input operand's exponent by 1 to account for the fact that
1887
| dest_sgl or dest_dbl expects a normalized number's bias.
1888
|
1889
| Input: a0  points to a normalized number in internal extended format
1890
|        d0  is the round precision (=1 for sgl; =2 for dbl)
1891
|        d1  is the single precision or double precision
1892
|            denorm threshold
1893
|
1894
| Output: (In the format for dest_sgl or dest_dbl)
1895
|        a0   points to the destination
1896
|        a1   points to the operand
1897
|
1898
| Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
1899
|
1900
dpspdnrm:
1901
        movel   %d0,-(%a7)      |save round precision
1902
        clrl    %d0             |clear initial g,r,s
1903
        bsrl    dnrm_lp         |careful with d0, it's needed by round
1904
 
1905
        bfextu  FPCR_MODE(%a6){#2:#2},%d1 |get rounding mode
1906
        swap    %d1
1907
        movew   2(%a7),%d1      |set rounding precision
1908
        swap    %d1             |at this point d1 has PREC/MODE info
1909
        bsrl    round           |round result, sets the inex bit in
1910
|                               ;USER_FPSR if needed
1911
 
1912
        movew   #1,%d0
1913
        subw    %d0,LOCAL_EX(%a0) |account for difference in denorm
1914
|                               ;vs norm bias
1915
 
1916
        movel   %a0,%a1         |a1 has the operand input
1917
        movel   EXC_EA(%a6),%a0 |a0 has the destination pointer
1918
        addw    #4,%a7          |pop stack
1919
        rts
1920
|
1921
| SET_XOP initialized WBTEMP with the value pointed to by a0
1922
| input: a0 points to input operand in the internal extended format
1923
|
1924
set_xop:
1925
        movel   LOCAL_EX(%a0),WBTEMP_EX(%a6)
1926
        movel   LOCAL_HI(%a0),WBTEMP_HI(%a6)
1927
        movel   LOCAL_LO(%a0),WBTEMP_LO(%a6)
1928
        bfclr   WBTEMP_SGN(%a6){#0:#8}
1929
        beqs    sxop
1930
        bsetb   #sign_bit,WBTEMP_EX(%a6)
1931
sxop:
1932
        bfclr   STAG(%a6){#5:#4}        |clear wbtm66,wbtm1,wbtm0,sbit
1933
        rts
1934
|
1935
|       P_MOVE
1936
|
1937
p_movet:
1938
        .long   p_move
1939
        .long   p_movez
1940
        .long   p_movei
1941
        .long   p_moven
1942
        .long   p_move
1943
p_regd:
1944
        .long   p_dyd0
1945
        .long   p_dyd1
1946
        .long   p_dyd2
1947
        .long   p_dyd3
1948
        .long   p_dyd4
1949
        .long   p_dyd5
1950
        .long   p_dyd6
1951
        .long   p_dyd7
1952
 
1953
pack_out:
1954
        leal    p_movet,%a0     |load jmp table address
1955
        movew   STAG(%a6),%d0   |get source tag
1956
        bfextu  %d0{#16:#3},%d0 |isolate source bits
1957
        movel   (%a0,%d0.w*4),%a0       |load a0 with routine label for tag
1958
        jmp     (%a0)           |go to the routine
1959
 
1960
p_write:
1961
        movel   #0x0c,%d0       |get byte count
1962
        movel   EXC_EA(%a6),%a1 |get the destination address
1963
        bsr     mem_write       |write the user's destination
1964
        moveb   #0,CU_SAVEPC(%a6) |set the cu save pc to all 0's
1965
 
1966
|
1967
| Also note that the dtag must be set to norm here - this is because
1968
| the 040 uses the dtag to execute the correct microcode.
1969
|
1970
        bfclr    DTAG(%a6){#0:#3}  |set dtag to norm
1971
 
1972
        rts
1973
 
1974
| Notes on handling of special case (zero, inf, and nan) inputs:
1975
|       1. Operr is not signalled if the k-factor is greater than 18.
1976
|       2. Per the manual, status bits are not set.
1977
|
1978
 
1979
p_move:
1980
        movew   CMDREG1B(%a6),%d0
1981
        btstl   #kfact_bit,%d0  |test for dynamic k-factor
1982
        beqs    statick         |if clear, k-factor is static
1983
dynamick:
1984
        bfextu  %d0{#25:#3},%d0 |isolate register for dynamic k-factor
1985
        lea     p_regd,%a0
1986
        movel   %a0@(%d0:l:4),%a0
1987
        jmp     (%a0)
1988
statick:
1989
        andiw   #0x007f,%d0     |get k-factor
1990
        bfexts  %d0{#25:#7},%d0 |sign extend d0 for bindec
1991
        leal    ETEMP(%a6),%a0  |a0 will point to the packed decimal
1992
        bsrl    bindec          |perform the convert; data at a6
1993
        leal    FP_SCR1(%a6),%a0        |load a0 with result address
1994
        bral    p_write
1995
p_movez:
1996
        leal    ETEMP(%a6),%a0  |a0 will point to the packed decimal
1997
        clrw    2(%a0)          |clear lower word of exp
1998
        clrl    4(%a0)          |load second lword of ZERO
1999
        clrl    8(%a0)          |load third lword of ZERO
2000
        bra     p_write         |go write results
2001
p_movei:
2002
        fmovel  #0,%FPSR                |clear aiop
2003
        leal    ETEMP(%a6),%a0  |a0 will point to the packed decimal
2004
        clrw    2(%a0)          |clear lower word of exp
2005
        bra     p_write         |go write the result
2006
p_moven:
2007
        leal    ETEMP(%a6),%a0  |a0 will point to the packed decimal
2008
        clrw    2(%a0)          |clear lower word of exp
2009
        bra     p_write         |go write the result
2010
 
2011
|
2012
| Routines to read the dynamic k-factor from Dn.
2013
|
2014
p_dyd0:
2015
        movel   USER_D0(%a6),%d0
2016
        bras    statick
2017
p_dyd1:
2018
        movel   USER_D1(%a6),%d0
2019
        bras    statick
2020
p_dyd2:
2021
        movel   %d2,%d0
2022
        bras    statick
2023
p_dyd3:
2024
        movel   %d3,%d0
2025
        bras    statick
2026
p_dyd4:
2027
        movel   %d4,%d0
2028
        bras    statick
2029
p_dyd5:
2030
        movel   %d5,%d0
2031
        bras    statick
2032
p_dyd6:
2033
        movel   %d6,%d0
2034
        bra     statick
2035
p_dyd7:
2036
        movel   %d7,%d0
2037
        bra     statick
2038
 
2039
        |end

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.