Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/m68k/fpsp040/res_func.S
10817 views
1
|
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,<ea>) 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
2040
2041