blob: 0c997c436bebe0040352b6a1b7980438a37a1880 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
3M68000 Hi-Performance Microprocessor Division
4M68060 Software Package
5Production Release P1.00 -- October 10, 1994
6
7M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved.
8
9THE SOFTWARE is provided on an "AS IS" basis and without warranty.
10To the maximum extent permitted by applicable law,
11MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
12INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
13and any warranty against infringement with regard to the SOFTWARE
14(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
15
16To the maximum extent permitted by applicable law,
17IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
18(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
19BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
20ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
21Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
22
23You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
24so long as this entire notice is retained without alteration in any modified and/or
25redistributed versions, and that such modified versions are clearly identified as such.
26No licenses are granted by implication, estoppel or otherwise under any patents
27or trademarks of Motorola, Inc.
28~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29# freal.s:
30# This file is appended to the top of the 060FPSP package
31# and contains the entry points into the package. The user, in
32# effect, branches to one of the branch table entries located
33# after _060FPSP_TABLE.
34# Also, subroutine stubs exist in this file (_fpsp_done for
35# example) that are referenced by the FPSP package itself in order
36# to call a given routine. The stub routine actually performs the
37# callout. The FPSP code does a "bsr" to the stub routine. This
38# extra layer of hierarchy adds a slight performance penalty but
39# it makes the FPSP code easier to read and more mainatinable.
40#
41
42set _off_bsun, 0x00
43set _off_snan, 0x04
44set _off_operr, 0x08
45set _off_ovfl, 0x0c
46set _off_unfl, 0x10
47set _off_dz, 0x14
48set _off_inex, 0x18
49set _off_fline, 0x1c
50set _off_fpu_dis, 0x20
51set _off_trap, 0x24
52set _off_trace, 0x28
53set _off_access, 0x2c
54set _off_done, 0x30
55
56set _off_imr, 0x40
57set _off_dmr, 0x44
58set _off_dmw, 0x48
59set _off_irw, 0x4c
60set _off_irl, 0x50
61set _off_drb, 0x54
62set _off_drw, 0x58
63set _off_drl, 0x5c
64set _off_dwb, 0x60
65set _off_dww, 0x64
66set _off_dwl, 0x68
67
68_060FPSP_TABLE:
69
70###############################################################
71
72# Here's the table of ENTRY POINTS for those linking the package.
73 bra.l _fpsp_snan
74 short 0x0000
75 bra.l _fpsp_operr
76 short 0x0000
77 bra.l _fpsp_ovfl
78 short 0x0000
79 bra.l _fpsp_unfl
80 short 0x0000
81 bra.l _fpsp_dz
82 short 0x0000
83 bra.l _fpsp_inex
84 short 0x0000
85 bra.l _fpsp_fline
86 short 0x0000
87 bra.l _fpsp_unsupp
88 short 0x0000
89 bra.l _fpsp_effadd
90 short 0x0000
91
92 space 56
93
94###############################################################
95 global _fpsp_done
96_fpsp_done:
97 mov.l %d0,-(%sp)
98 mov.l (_060FPSP_TABLE-0x80+_off_done,%pc),%d0
99 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
100 mov.l 0x4(%sp),%d0
101 rtd &0x4
102
103 global _real_ovfl
104_real_ovfl:
105 mov.l %d0,-(%sp)
106 mov.l (_060FPSP_TABLE-0x80+_off_ovfl,%pc),%d0
107 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
108 mov.l 0x4(%sp),%d0
109 rtd &0x4
110
111 global _real_unfl
112_real_unfl:
113 mov.l %d0,-(%sp)
114 mov.l (_060FPSP_TABLE-0x80+_off_unfl,%pc),%d0
115 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
116 mov.l 0x4(%sp),%d0
117 rtd &0x4
118
119 global _real_inex
120_real_inex:
121 mov.l %d0,-(%sp)
122 mov.l (_060FPSP_TABLE-0x80+_off_inex,%pc),%d0
123 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
124 mov.l 0x4(%sp),%d0
125 rtd &0x4
126
127 global _real_bsun
128_real_bsun:
129 mov.l %d0,-(%sp)
130 mov.l (_060FPSP_TABLE-0x80+_off_bsun,%pc),%d0
131 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
132 mov.l 0x4(%sp),%d0
133 rtd &0x4
134
135 global _real_operr
136_real_operr:
137 mov.l %d0,-(%sp)
138 mov.l (_060FPSP_TABLE-0x80+_off_operr,%pc),%d0
139 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
140 mov.l 0x4(%sp),%d0
141 rtd &0x4
142
143 global _real_snan
144_real_snan:
145 mov.l %d0,-(%sp)
146 mov.l (_060FPSP_TABLE-0x80+_off_snan,%pc),%d0
147 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
148 mov.l 0x4(%sp),%d0
149 rtd &0x4
150
151 global _real_dz
152_real_dz:
153 mov.l %d0,-(%sp)
154 mov.l (_060FPSP_TABLE-0x80+_off_dz,%pc),%d0
155 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
156 mov.l 0x4(%sp),%d0
157 rtd &0x4
158
159 global _real_fline
160_real_fline:
161 mov.l %d0,-(%sp)
162 mov.l (_060FPSP_TABLE-0x80+_off_fline,%pc),%d0
163 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
164 mov.l 0x4(%sp),%d0
165 rtd &0x4
166
167 global _real_fpu_disabled
168_real_fpu_disabled:
169 mov.l %d0,-(%sp)
170 mov.l (_060FPSP_TABLE-0x80+_off_fpu_dis,%pc),%d0
171 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
172 mov.l 0x4(%sp),%d0
173 rtd &0x4
174
175 global _real_trap
176_real_trap:
177 mov.l %d0,-(%sp)
178 mov.l (_060FPSP_TABLE-0x80+_off_trap,%pc),%d0
179 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
180 mov.l 0x4(%sp),%d0
181 rtd &0x4
182
183 global _real_trace
184_real_trace:
185 mov.l %d0,-(%sp)
186 mov.l (_060FPSP_TABLE-0x80+_off_trace,%pc),%d0
187 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
188 mov.l 0x4(%sp),%d0
189 rtd &0x4
190
191 global _real_access
192_real_access:
193 mov.l %d0,-(%sp)
194 mov.l (_060FPSP_TABLE-0x80+_off_access,%pc),%d0
195 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
196 mov.l 0x4(%sp),%d0
197 rtd &0x4
198
199#######################################
200
201 global _imem_read
202_imem_read:
203 mov.l %d0,-(%sp)
204 mov.l (_060FPSP_TABLE-0x80+_off_imr,%pc),%d0
205 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
206 mov.l 0x4(%sp),%d0
207 rtd &0x4
208
209 global _dmem_read
210_dmem_read:
211 mov.l %d0,-(%sp)
212 mov.l (_060FPSP_TABLE-0x80+_off_dmr,%pc),%d0
213 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
214 mov.l 0x4(%sp),%d0
215 rtd &0x4
216
217 global _dmem_write
218_dmem_write:
219 mov.l %d0,-(%sp)
220 mov.l (_060FPSP_TABLE-0x80+_off_dmw,%pc),%d0
221 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
222 mov.l 0x4(%sp),%d0
223 rtd &0x4
224
225 global _imem_read_word
226_imem_read_word:
227 mov.l %d0,-(%sp)
228 mov.l (_060FPSP_TABLE-0x80+_off_irw,%pc),%d0
229 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
230 mov.l 0x4(%sp),%d0
231 rtd &0x4
232
233 global _imem_read_long
234_imem_read_long:
235 mov.l %d0,-(%sp)
236 mov.l (_060FPSP_TABLE-0x80+_off_irl,%pc),%d0
237 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
238 mov.l 0x4(%sp),%d0
239 rtd &0x4
240
241 global _dmem_read_byte
242_dmem_read_byte:
243 mov.l %d0,-(%sp)
244 mov.l (_060FPSP_TABLE-0x80+_off_drb,%pc),%d0
245 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
246 mov.l 0x4(%sp),%d0
247 rtd &0x4
248
249 global _dmem_read_word
250_dmem_read_word:
251 mov.l %d0,-(%sp)
252 mov.l (_060FPSP_TABLE-0x80+_off_drw,%pc),%d0
253 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
254 mov.l 0x4(%sp),%d0
255 rtd &0x4
256
257 global _dmem_read_long
258_dmem_read_long:
259 mov.l %d0,-(%sp)
260 mov.l (_060FPSP_TABLE-0x80+_off_drl,%pc),%d0
261 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
262 mov.l 0x4(%sp),%d0
263 rtd &0x4
264
265 global _dmem_write_byte
266_dmem_write_byte:
267 mov.l %d0,-(%sp)
268 mov.l (_060FPSP_TABLE-0x80+_off_dwb,%pc),%d0
269 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
270 mov.l 0x4(%sp),%d0
271 rtd &0x4
272
273 global _dmem_write_word
274_dmem_write_word:
275 mov.l %d0,-(%sp)
276 mov.l (_060FPSP_TABLE-0x80+_off_dww,%pc),%d0
277 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
278 mov.l 0x4(%sp),%d0
279 rtd &0x4
280
281 global _dmem_write_long
282_dmem_write_long:
283 mov.l %d0,-(%sp)
284 mov.l (_060FPSP_TABLE-0x80+_off_dwl,%pc),%d0
285 pea.l (_060FPSP_TABLE-0x80,%pc,%d0)
286 mov.l 0x4(%sp),%d0
287 rtd &0x4
288
289#
290# This file contains a set of define statements for constants
291# in order to promote readability within the corecode itself.
292#
293
294set LOCAL_SIZE, 192 # stack frame size(bytes)
295set LV, -LOCAL_SIZE # stack offset
296
297set EXC_SR, 0x4 # stack status register
298set EXC_PC, 0x6 # stack pc
299set EXC_VOFF, 0xa # stacked vector offset
300set EXC_EA, 0xc # stacked <ea>
301
302set EXC_FP, 0x0 # frame pointer
303
304set EXC_AREGS, -68 # offset of all address regs
305set EXC_DREGS, -100 # offset of all data regs
306set EXC_FPREGS, -36 # offset of all fp regs
307
308set EXC_A7, EXC_AREGS+(7*4) # offset of saved a7
309set OLD_A7, EXC_AREGS+(6*4) # extra copy of saved a7
310set EXC_A6, EXC_AREGS+(6*4) # offset of saved a6
311set EXC_A5, EXC_AREGS+(5*4)
312set EXC_A4, EXC_AREGS+(4*4)
313set EXC_A3, EXC_AREGS+(3*4)
314set EXC_A2, EXC_AREGS+(2*4)
315set EXC_A1, EXC_AREGS+(1*4)
316set EXC_A0, EXC_AREGS+(0*4)
317set EXC_D7, EXC_DREGS+(7*4)
318set EXC_D6, EXC_DREGS+(6*4)
319set EXC_D5, EXC_DREGS+(5*4)
320set EXC_D4, EXC_DREGS+(4*4)
321set EXC_D3, EXC_DREGS+(3*4)
322set EXC_D2, EXC_DREGS+(2*4)
323set EXC_D1, EXC_DREGS+(1*4)
324set EXC_D0, EXC_DREGS+(0*4)
325
326set EXC_FP0, EXC_FPREGS+(0*12) # offset of saved fp0
327set EXC_FP1, EXC_FPREGS+(1*12) # offset of saved fp1
328set EXC_FP2, EXC_FPREGS+(2*12) # offset of saved fp2 (not used)
329
330set FP_SCR1, LV+80 # fp scratch 1
331set FP_SCR1_EX, FP_SCR1+0
332set FP_SCR1_SGN, FP_SCR1+2
333set FP_SCR1_HI, FP_SCR1+4
334set FP_SCR1_LO, FP_SCR1+8
335
336set FP_SCR0, LV+68 # fp scratch 0
337set FP_SCR0_EX, FP_SCR0+0
338set FP_SCR0_SGN, FP_SCR0+2
339set FP_SCR0_HI, FP_SCR0+4
340set FP_SCR0_LO, FP_SCR0+8
341
342set FP_DST, LV+56 # fp destination operand
343set FP_DST_EX, FP_DST+0
344set FP_DST_SGN, FP_DST+2
345set FP_DST_HI, FP_DST+4
346set FP_DST_LO, FP_DST+8
347
348set FP_SRC, LV+44 # fp source operand
349set FP_SRC_EX, FP_SRC+0
350set FP_SRC_SGN, FP_SRC+2
351set FP_SRC_HI, FP_SRC+4
352set FP_SRC_LO, FP_SRC+8
353
354set USER_FPIAR, LV+40 # FP instr address register
355
356set USER_FPSR, LV+36 # FP status register
357set FPSR_CC, USER_FPSR+0 # FPSR condition codes
358set FPSR_QBYTE, USER_FPSR+1 # FPSR qoutient byte
359set FPSR_EXCEPT, USER_FPSR+2 # FPSR exception status byte
360set FPSR_AEXCEPT, USER_FPSR+3 # FPSR accrued exception byte
361
362set USER_FPCR, LV+32 # FP control register
363set FPCR_ENABLE, USER_FPCR+2 # FPCR exception enable
364set FPCR_MODE, USER_FPCR+3 # FPCR rounding mode control
365
366set L_SCR3, LV+28 # integer scratch 3
367set L_SCR2, LV+24 # integer scratch 2
368set L_SCR1, LV+20 # integer scratch 1
369
370set STORE_FLG, LV+19 # flag: operand store (ie. not fcmp/ftst)
371
372set EXC_TEMP2, LV+24 # temporary space
373set EXC_TEMP, LV+16 # temporary space
374
375set DTAG, LV+15 # destination operand type
376set STAG, LV+14 # source operand type
377
378set SPCOND_FLG, LV+10 # flag: special case (see below)
379
380set EXC_CC, LV+8 # saved condition codes
381set EXC_EXTWPTR, LV+4 # saved current PC (active)
382set EXC_EXTWORD, LV+2 # saved extension word
383set EXC_CMDREG, LV+2 # saved extension word
384set EXC_OPWORD, LV+0 # saved operation word
385
386################################
387
388# Helpful macros
389
390set FTEMP, 0 # offsets within an
391set FTEMP_EX, 0 # extended precision
392set FTEMP_SGN, 2 # value saved in memory.
393set FTEMP_HI, 4
394set FTEMP_LO, 8
395set FTEMP_GRS, 12
396
397set LOCAL, 0 # offsets within an
398set LOCAL_EX, 0 # extended precision
399set LOCAL_SGN, 2 # value saved in memory.
400set LOCAL_HI, 4
401set LOCAL_LO, 8
402set LOCAL_GRS, 12
403
404set DST, 0 # offsets within an
405set DST_EX, 0 # extended precision
406set DST_HI, 4 # value saved in memory.
407set DST_LO, 8
408
409set SRC, 0 # offsets within an
410set SRC_EX, 0 # extended precision
411set SRC_HI, 4 # value saved in memory.
412set SRC_LO, 8
413
414set SGL_LO, 0x3f81 # min sgl prec exponent
415set SGL_HI, 0x407e # max sgl prec exponent
416set DBL_LO, 0x3c01 # min dbl prec exponent
417set DBL_HI, 0x43fe # max dbl prec exponent
418set EXT_LO, 0x0 # min ext prec exponent
419set EXT_HI, 0x7ffe # max ext prec exponent
420
421set EXT_BIAS, 0x3fff # extended precision bias
422set SGL_BIAS, 0x007f # single precision bias
423set DBL_BIAS, 0x03ff # double precision bias
424
425set NORM, 0x00 # operand type for STAG/DTAG
426set ZERO, 0x01 # operand type for STAG/DTAG
427set INF, 0x02 # operand type for STAG/DTAG
428set QNAN, 0x03 # operand type for STAG/DTAG
429set DENORM, 0x04 # operand type for STAG/DTAG
430set SNAN, 0x05 # operand type for STAG/DTAG
431set UNNORM, 0x06 # operand type for STAG/DTAG
432
433##################
434# FPSR/FPCR bits #
435##################
436set neg_bit, 0x3 # negative result
437set z_bit, 0x2 # zero result
438set inf_bit, 0x1 # infinite result
439set nan_bit, 0x0 # NAN result
440
441set q_sn_bit, 0x7 # sign bit of quotient byte
442
443set bsun_bit, 7 # branch on unordered
444set snan_bit, 6 # signalling NAN
445set operr_bit, 5 # operand error
446set ovfl_bit, 4 # overflow
447set unfl_bit, 3 # underflow
448set dz_bit, 2 # divide by zero
449set inex2_bit, 1 # inexact result 2
450set inex1_bit, 0 # inexact result 1
451
452set aiop_bit, 7 # accrued inexact operation bit
453set aovfl_bit, 6 # accrued overflow bit
454set aunfl_bit, 5 # accrued underflow bit
455set adz_bit, 4 # accrued dz bit
456set ainex_bit, 3 # accrued inexact bit
457
458#############################
459# FPSR individual bit masks #
460#############################
461set neg_mask, 0x08000000 # negative bit mask (lw)
462set inf_mask, 0x02000000 # infinity bit mask (lw)
463set z_mask, 0x04000000 # zero bit mask (lw)
464set nan_mask, 0x01000000 # nan bit mask (lw)
465
466set neg_bmask, 0x08 # negative bit mask (byte)
467set inf_bmask, 0x02 # infinity bit mask (byte)
468set z_bmask, 0x04 # zero bit mask (byte)
469set nan_bmask, 0x01 # nan bit mask (byte)
470
471set bsun_mask, 0x00008000 # bsun exception mask
472set snan_mask, 0x00004000 # snan exception mask
473set operr_mask, 0x00002000 # operr exception mask
474set ovfl_mask, 0x00001000 # overflow exception mask
475set unfl_mask, 0x00000800 # underflow exception mask
476set dz_mask, 0x00000400 # dz exception mask
477set inex2_mask, 0x00000200 # inex2 exception mask
478set inex1_mask, 0x00000100 # inex1 exception mask
479
480set aiop_mask, 0x00000080 # accrued illegal operation
481set aovfl_mask, 0x00000040 # accrued overflow
482set aunfl_mask, 0x00000020 # accrued underflow
483set adz_mask, 0x00000010 # accrued divide by zero
484set ainex_mask, 0x00000008 # accrued inexact
485
486######################################
487# FPSR combinations used in the FPSP #
488######################################
489set dzinf_mask, inf_mask+dz_mask+adz_mask
490set opnan_mask, nan_mask+operr_mask+aiop_mask
491set nzi_mask, 0x01ffffff #clears N, Z, and I
492set unfinx_mask, unfl_mask+inex2_mask+aunfl_mask+ainex_mask
493set unf2inx_mask, unfl_mask+inex2_mask+ainex_mask
494set ovfinx_mask, ovfl_mask+inex2_mask+aovfl_mask+ainex_mask
495set inx1a_mask, inex1_mask+ainex_mask
496set inx2a_mask, inex2_mask+ainex_mask
497set snaniop_mask, nan_mask+snan_mask+aiop_mask
498set snaniop2_mask, snan_mask+aiop_mask
499set naniop_mask, nan_mask+aiop_mask
500set neginf_mask, neg_mask+inf_mask
501set infaiop_mask, inf_mask+aiop_mask
502set negz_mask, neg_mask+z_mask
503set opaop_mask, operr_mask+aiop_mask
504set unfl_inx_mask, unfl_mask+aunfl_mask+ainex_mask
505set ovfl_inx_mask, ovfl_mask+aovfl_mask+ainex_mask
506
507#########
508# misc. #
509#########
510set rnd_stky_bit, 29 # stky bit pos in longword
511
512set sign_bit, 0x7 # sign bit
513set signan_bit, 0x6 # signalling nan bit
514
515set sgl_thresh, 0x3f81 # minimum sgl exponent
516set dbl_thresh, 0x3c01 # minimum dbl exponent
517
518set x_mode, 0x0 # extended precision
519set s_mode, 0x4 # single precision
520set d_mode, 0x8 # double precision
521
522set rn_mode, 0x0 # round-to-nearest
523set rz_mode, 0x1 # round-to-zero
524set rm_mode, 0x2 # round-tp-minus-infinity
525set rp_mode, 0x3 # round-to-plus-infinity
526
527set mantissalen, 64 # length of mantissa in bits
528
529set BYTE, 1 # len(byte) == 1 byte
530set WORD, 2 # len(word) == 2 bytes
531set LONG, 4 # len(longword) == 2 bytes
532
533set BSUN_VEC, 0xc0 # bsun vector offset
534set INEX_VEC, 0xc4 # inexact vector offset
535set DZ_VEC, 0xc8 # dz vector offset
536set UNFL_VEC, 0xcc # unfl vector offset
537set OPERR_VEC, 0xd0 # operr vector offset
538set OVFL_VEC, 0xd4 # ovfl vector offset
539set SNAN_VEC, 0xd8 # snan vector offset
540
541###########################
542# SPecial CONDition FLaGs #
543###########################
544set ftrapcc_flg, 0x01 # flag bit: ftrapcc exception
545set fbsun_flg, 0x02 # flag bit: bsun exception
546set mia7_flg, 0x04 # flag bit: (a7)+ <ea>
547set mda7_flg, 0x08 # flag bit: -(a7) <ea>
548set fmovm_flg, 0x40 # flag bit: fmovm instruction
549set immed_flg, 0x80 # flag bit: &<data> <ea>
550
551set ftrapcc_bit, 0x0
552set fbsun_bit, 0x1
553set mia7_bit, 0x2
554set mda7_bit, 0x3
555set immed_bit, 0x7
556
557##################################
558# TRANSCENDENTAL "LAST-OP" FLAGS #
559##################################
560set FMUL_OP, 0x0 # fmul instr performed last
561set FDIV_OP, 0x1 # fdiv performed last
562set FADD_OP, 0x2 # fadd performed last
563set FMOV_OP, 0x3 # fmov performed last
564
565#############
566# CONSTANTS #
567#############
568T1: long 0x40C62D38,0xD3D64634 # 16381 LOG2 LEAD
569T2: long 0x3D6F90AE,0xB1E75CC7 # 16381 LOG2 TRAIL
570
571PI: long 0x40000000,0xC90FDAA2,0x2168C235,0x00000000
572PIBY2: long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000
573
574TWOBYPI:
575 long 0x3FE45F30,0x6DC9C883
576
577#########################################################################
578# XDEF **************************************************************** #
579# _fpsp_ovfl(): 060FPSP entry point for FP Overflow exception. #
580# #
581# This handler should be the first code executed upon taking the #
582# FP Overflow exception in an operating system. #
583# #
584# XREF **************************************************************** #
585# _imem_read_long() - read instruction longword #
586# fix_skewed_ops() - adjust src operand in fsave frame #
587# set_tag_x() - determine optype of src/dst operands #
588# store_fpreg() - store opclass 0 or 2 result to FP regfile #
589# unnorm_fix() - change UNNORM operands to NORM or ZERO #
590# load_fpn2() - load dst operand from FP regfile #
591# fout() - emulate an opclass 3 instruction #
592# tbl_unsupp - add of table of emulation routines for opclass 0,2 #
593# _fpsp_done() - "callout" for 060FPSP exit (all work done!) #
594# _real_ovfl() - "callout" for Overflow exception enabled code #
595# _real_inex() - "callout" for Inexact exception enabled code #
596# _real_trace() - "callout" for Trace exception code #
597# #
598# INPUT *************************************************************** #
599# - The system stack contains the FP Ovfl exception stack frame #
600# - The fsave frame contains the source operand #
601# #
602# OUTPUT ************************************************************** #
603# Overflow Exception enabled: #
604# - The system stack is unchanged #
605# - The fsave frame contains the adjusted src op for opclass 0,2 #
606# Overflow Exception disabled: #
607# - The system stack is unchanged #
608# - The "exception present" flag in the fsave frame is cleared #
609# #
610# ALGORITHM *********************************************************** #
611# On the 060, if an FP overflow is present as the result of any #
612# instruction, the 060 will take an overflow exception whether the #
613# exception is enabled or disabled in the FPCR. For the disabled case, #
614# This handler emulates the instruction to determine what the correct #
615# default result should be for the operation. This default result is #
616# then stored in either the FP regfile, data regfile, or memory. #
617# Finally, the handler exits through the "callout" _fpsp_done() #
618# denoting that no exceptional conditions exist within the machine. #
619# If the exception is enabled, then this handler must create the #
620# exceptional operand and plave it in the fsave state frame, and store #
621# the default result (only if the instruction is opclass 3). For #
622# exceptions enabled, this handler must exit through the "callout" #
623# _real_ovfl() so that the operating system enabled overflow handler #
624# can handle this case. #
625# Two other conditions exist. First, if overflow was disabled #
626# but the inexact exception was enabled, this handler must exit #
627# through the "callout" _real_inex() regardless of whether the result #
628# was inexact. #
629# Also, in the case of an opclass three instruction where #
630# overflow was disabled and the trace exception was enabled, this #
631# handler must exit through the "callout" _real_trace(). #
632# #
633#########################################################################
634
635 global _fpsp_ovfl
636_fpsp_ovfl:
637
638#$# sub.l &24,%sp # make room for src/dst
639
640 link.w %a6,&-LOCAL_SIZE # init stack frame
641
642 fsave FP_SRC(%a6) # grab the "busy" frame
643
644 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
645 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
646 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack
647
648# the FPIAR holds the "current PC" of the faulting instruction
649 mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
650 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
651 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
652 bsr.l _imem_read_long # fetch the instruction words
653 mov.l %d0,EXC_OPWORD(%a6)
654
655##############################################################################
656
657 btst &0x5,EXC_CMDREG(%a6) # is instr an fmove out?
658 bne.w fovfl_out
659
660
661 lea FP_SRC(%a6),%a0 # pass: ptr to src op
662 bsr.l fix_skewed_ops # fix src op
663
664# since, I believe, only NORMs and DENORMs can come through here,
665# maybe we can avoid the subroutine call.
666 lea FP_SRC(%a6),%a0 # pass: ptr to src op
667 bsr.l set_tag_x # tag the operand type
668 mov.b %d0,STAG(%a6) # maybe NORM,DENORM
669
670# bit five of the fp extension word separates the monadic and dyadic operations
671# that can pass through fpsp_ovfl(). remember that fcmp, ftst, and fsincos
672# will never take this exception.
673 btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic?
674 beq.b fovfl_extract # monadic
675
676 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
677 bsr.l load_fpn2 # load dst into FP_DST
678
679 lea FP_DST(%a6),%a0 # pass: ptr to dst op
680 bsr.l set_tag_x # tag the operand type
681 cmpi.b %d0,&UNNORM # is operand an UNNORM?
682 bne.b fovfl_op2_done # no
683 bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO
684fovfl_op2_done:
685 mov.b %d0,DTAG(%a6) # save dst optype tag
686
687fovfl_extract:
688
689#$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
690#$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
691#$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
692#$# mov.l FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6)
693#$# mov.l FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6)
694#$# mov.l FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6)
695
696 clr.l %d0
697 mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode
698
699 mov.b 1+EXC_CMDREG(%a6),%d1
700 andi.w &0x007f,%d1 # extract extension
701
702 andi.l &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field
703
704 fmov.l &0x0,%fpcr # zero current control regs
705 fmov.l &0x0,%fpsr
706
707 lea FP_SRC(%a6),%a0
708 lea FP_DST(%a6),%a1
709
710# maybe we can make these entry points ONLY the OVFL entry points of each routine.
711 mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
712 jsr (tbl_unsupp.l,%pc,%d1.l*1)
713
714# the operation has been emulated. the result is in fp0.
715# the EXOP, if an exception occurred, is in fp1.
716# we must save the default result regardless of whether
717# traps are enabled or disabled.
718 bfextu EXC_CMDREG(%a6){&6:&3},%d0
719 bsr.l store_fpreg
720
721# the exceptional possibilities we have left ourselves with are ONLY overflow
722# and inexact. and, the inexact is such that overflow occurred and was disabled
723# but inexact was enabled.
724 btst &ovfl_bit,FPCR_ENABLE(%a6)
725 bne.b fovfl_ovfl_on
726
727 btst &inex2_bit,FPCR_ENABLE(%a6)
728 bne.b fovfl_inex_on
729
730 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
731 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
732 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
733
734 unlk %a6
735#$# add.l &24,%sp
736 bra.l _fpsp_done
737
738# overflow is enabled AND overflow, of course, occurred. so, we have the EXOP
739# in fp1. now, simply jump to _real_ovfl()!
740fovfl_ovfl_on:
741 fmovm.x &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack
742
743 mov.w &0xe005,2+FP_SRC(%a6) # save exc status
744
745 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
746 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
747 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
748
749 frestore FP_SRC(%a6) # do this after fmovm,other f<op>s!
750
751 unlk %a6
752
753 bra.l _real_ovfl
754
755# overflow occurred but is disabled. meanwhile, inexact is enabled. therefore,
756# we must jump to real_inex().
757fovfl_inex_on:
758
759 fmovm.x &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack
760
761 mov.b &0xc4,1+EXC_VOFF(%a6) # vector offset = 0xc4
762 mov.w &0xe001,2+FP_SRC(%a6) # save exc status
763
764 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
765 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
766 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
767
768 frestore FP_SRC(%a6) # do this after fmovm,other f<op>s!
769
770 unlk %a6
771
772 bra.l _real_inex
773
774########################################################################
775fovfl_out:
776
777
778#$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
779#$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
780#$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
781
782# the src operand is definitely a NORM(!), so tag it as such
783 mov.b &NORM,STAG(%a6) # set src optype tag
784
785 clr.l %d0
786 mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode
787
788 and.l &0xffff00ff,USER_FPSR(%a6) # zero all but accured field
789
790 fmov.l &0x0,%fpcr # zero current control regs
791 fmov.l &0x0,%fpsr
792
793 lea FP_SRC(%a6),%a0 # pass ptr to src operand
794
795 bsr.l fout
796
797 btst &ovfl_bit,FPCR_ENABLE(%a6)
798 bne.w fovfl_ovfl_on
799
800 btst &inex2_bit,FPCR_ENABLE(%a6)
801 bne.w fovfl_inex_on
802
803 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
804 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
805 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
806
807 unlk %a6
808#$# add.l &24,%sp
809
810 btst &0x7,(%sp) # is trace on?
811 beq.l _fpsp_done # no
812
813 fmov.l %fpiar,0x8(%sp) # "Current PC" is in FPIAR
814 mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024
815 bra.l _real_trace
816
817#########################################################################
818# XDEF **************************************************************** #
819# _fpsp_unfl(): 060FPSP entry point for FP Underflow exception. #
820# #
821# This handler should be the first code executed upon taking the #
822# FP Underflow exception in an operating system. #
823# #
824# XREF **************************************************************** #
825# _imem_read_long() - read instruction longword #
826# fix_skewed_ops() - adjust src operand in fsave frame #
827# set_tag_x() - determine optype of src/dst operands #
828# store_fpreg() - store opclass 0 or 2 result to FP regfile #
829# unnorm_fix() - change UNNORM operands to NORM or ZERO #
830# load_fpn2() - load dst operand from FP regfile #
831# fout() - emulate an opclass 3 instruction #
832# tbl_unsupp - add of table of emulation routines for opclass 0,2 #
833# _fpsp_done() - "callout" for 060FPSP exit (all work done!) #
834# _real_ovfl() - "callout" for Overflow exception enabled code #
835# _real_inex() - "callout" for Inexact exception enabled code #
836# _real_trace() - "callout" for Trace exception code #
837# #
838# INPUT *************************************************************** #
839# - The system stack contains the FP Unfl exception stack frame #
840# - The fsave frame contains the source operand #
841# #
842# OUTPUT ************************************************************** #
843# Underflow Exception enabled: #
844# - The system stack is unchanged #
845# - The fsave frame contains the adjusted src op for opclass 0,2 #
846# Underflow Exception disabled: #
847# - The system stack is unchanged #
848# - The "exception present" flag in the fsave frame is cleared #
849# #
850# ALGORITHM *********************************************************** #
851# On the 060, if an FP underflow is present as the result of any #
852# instruction, the 060 will take an underflow exception whether the #
853# exception is enabled or disabled in the FPCR. For the disabled case, #
854# This handler emulates the instruction to determine what the correct #
855# default result should be for the operation. This default result is #
856# then stored in either the FP regfile, data regfile, or memory. #
857# Finally, the handler exits through the "callout" _fpsp_done() #
858# denoting that no exceptional conditions exist within the machine. #
859# If the exception is enabled, then this handler must create the #
860# exceptional operand and plave it in the fsave state frame, and store #
861# the default result (only if the instruction is opclass 3). For #
862# exceptions enabled, this handler must exit through the "callout" #
863# _real_unfl() so that the operating system enabled overflow handler #
864# can handle this case. #
865# Two other conditions exist. First, if underflow was disabled #
866# but the inexact exception was enabled and the result was inexact, #
867# this handler must exit through the "callout" _real_inex(). #
868# was inexact. #
869# Also, in the case of an opclass three instruction where #
870# underflow was disabled and the trace exception was enabled, this #
871# handler must exit through the "callout" _real_trace(). #
872# #
873#########################################################################
874
875 global _fpsp_unfl
876_fpsp_unfl:
877
878#$# sub.l &24,%sp # make room for src/dst
879
880 link.w %a6,&-LOCAL_SIZE # init stack frame
881
882 fsave FP_SRC(%a6) # grab the "busy" frame
883
884 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
885 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
886 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack
887
888# the FPIAR holds the "current PC" of the faulting instruction
889 mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
890 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
891 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
892 bsr.l _imem_read_long # fetch the instruction words
893 mov.l %d0,EXC_OPWORD(%a6)
894
895##############################################################################
896
897 btst &0x5,EXC_CMDREG(%a6) # is instr an fmove out?
898 bne.w funfl_out
899
900
901 lea FP_SRC(%a6),%a0 # pass: ptr to src op
902 bsr.l fix_skewed_ops # fix src op
903
904 lea FP_SRC(%a6),%a0 # pass: ptr to src op
905 bsr.l set_tag_x # tag the operand type
906 mov.b %d0,STAG(%a6) # maybe NORM,DENORM
907
908# bit five of the fp ext word separates the monadic and dyadic operations
909# that can pass through fpsp_unfl(). remember that fcmp, and ftst
910# will never take this exception.
911 btst &0x5,1+EXC_CMDREG(%a6) # is op monadic or dyadic?
912 beq.b funfl_extract # monadic
913
914# now, what's left that's not dyadic is fsincos. we can distinguish it
915# from all dyadics by the '0110xxx pattern
916 btst &0x4,1+EXC_CMDREG(%a6) # is op an fsincos?
917 bne.b funfl_extract # yes
918
919 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
920 bsr.l load_fpn2 # load dst into FP_DST
921
922 lea FP_DST(%a6),%a0 # pass: ptr to dst op
923 bsr.l set_tag_x # tag the operand type
924 cmpi.b %d0,&UNNORM # is operand an UNNORM?
925 bne.b funfl_op2_done # no
926 bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO
927funfl_op2_done:
928 mov.b %d0,DTAG(%a6) # save dst optype tag
929
930funfl_extract:
931
932#$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
933#$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
934#$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
935#$# mov.l FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6)
936#$# mov.l FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6)
937#$# mov.l FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6)
938
939 clr.l %d0
940 mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode
941
942 mov.b 1+EXC_CMDREG(%a6),%d1
943 andi.w &0x007f,%d1 # extract extension
944
945 andi.l &0x00ff01ff,USER_FPSR(%a6)
946
947 fmov.l &0x0,%fpcr # zero current control regs
948 fmov.l &0x0,%fpsr
949
950 lea FP_SRC(%a6),%a0
951 lea FP_DST(%a6),%a1
952
953# maybe we can make these entry points ONLY the OVFL entry points of each routine.
954 mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
955 jsr (tbl_unsupp.l,%pc,%d1.l*1)
956
957 bfextu EXC_CMDREG(%a6){&6:&3},%d0
958 bsr.l store_fpreg
959
960# The `060 FPU multiplier hardware is such that if the result of a
961# multiply operation is the smallest possible normalized number
962# (0x00000000_80000000_00000000), then the machine will take an
963# underflow exception. Since this is incorrect, we need to check
964# if our emulation, after re-doing the operation, decided that
965# no underflow was called for. We do these checks only in
966# funfl_{unfl,inex}_on() because w/ both exceptions disabled, this
967# special case will simply exit gracefully with the correct result.
968
969# the exceptional possibilities we have left ourselves with are ONLY overflow
970# and inexact. and, the inexact is such that overflow occurred and was disabled
971# but inexact was enabled.
972 btst &unfl_bit,FPCR_ENABLE(%a6)
973 bne.b funfl_unfl_on
974
975funfl_chkinex:
976 btst &inex2_bit,FPCR_ENABLE(%a6)
977 bne.b funfl_inex_on
978
979funfl_exit:
980 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
981 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
982 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
983
984 unlk %a6
985#$# add.l &24,%sp
986 bra.l _fpsp_done
987
988# overflow is enabled AND overflow, of course, occurred. so, we have the EXOP
989# in fp1 (don't forget to save fp0). what to do now?
990# well, we simply have to get to go to _real_unfl()!
991funfl_unfl_on:
992
993# The `060 FPU multiplier hardware is such that if the result of a
994# multiply operation is the smallest possible normalized number
995# (0x00000000_80000000_00000000), then the machine will take an
996# underflow exception. Since this is incorrect, we check here to see
997# if our emulation, after re-doing the operation, decided that
998# no underflow was called for.
999 btst &unfl_bit,FPSR_EXCEPT(%a6)
1000 beq.w funfl_chkinex
1001
1002funfl_unfl_on2:
1003 fmovm.x &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack
1004
1005 mov.w &0xe003,2+FP_SRC(%a6) # save exc status
1006
1007 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
1008 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1009 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1010
1011 frestore FP_SRC(%a6) # do this after fmovm,other f<op>s!
1012
1013 unlk %a6
1014
1015 bra.l _real_unfl
1016
1017# undeflow occurred but is disabled. meanwhile, inexact is enabled. therefore,
1018# we must jump to real_inex().
1019funfl_inex_on:
1020
1021# The `060 FPU multiplier hardware is such that if the result of a
1022# multiply operation is the smallest possible normalized number
1023# (0x00000000_80000000_00000000), then the machine will take an
1024# underflow exception.
1025# But, whether bogus or not, if inexact is enabled AND it occurred,
1026# then we have to branch to real_inex.
1027
1028 btst &inex2_bit,FPSR_EXCEPT(%a6)
1029 beq.w funfl_exit
1030
1031funfl_inex_on2:
1032
1033 fmovm.x &0x40,FP_SRC(%a6) # save EXOP to stack
1034
1035 mov.b &0xc4,1+EXC_VOFF(%a6) # vector offset = 0xc4
1036 mov.w &0xe001,2+FP_SRC(%a6) # save exc status
1037
1038 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
1039 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1040 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1041
1042 frestore FP_SRC(%a6) # do this after fmovm,other f<op>s!
1043
1044 unlk %a6
1045
1046 bra.l _real_inex
1047
1048#######################################################################
1049funfl_out:
1050
1051
1052#$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6)
1053#$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6)
1054#$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6)
1055
1056# the src operand is definitely a NORM(!), so tag it as such
1057 mov.b &NORM,STAG(%a6) # set src optype tag
1058
1059 clr.l %d0
1060 mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode
1061
1062 and.l &0xffff00ff,USER_FPSR(%a6) # zero all but accured field
1063
1064 fmov.l &0x0,%fpcr # zero current control regs
1065 fmov.l &0x0,%fpsr
1066
1067 lea FP_SRC(%a6),%a0 # pass ptr to src operand
1068
1069 bsr.l fout
1070
1071 btst &unfl_bit,FPCR_ENABLE(%a6)
1072 bne.w funfl_unfl_on2
1073
1074 btst &inex2_bit,FPCR_ENABLE(%a6)
1075 bne.w funfl_inex_on2
1076
1077 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
1078 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1079 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1080
1081 unlk %a6
1082#$# add.l &24,%sp
1083
1084 btst &0x7,(%sp) # is trace on?
1085 beq.l _fpsp_done # no
1086
1087 fmov.l %fpiar,0x8(%sp) # "Current PC" is in FPIAR
1088 mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024
1089 bra.l _real_trace
1090
1091#########################################################################
1092# XDEF **************************************************************** #
1093# _fpsp_unsupp(): 060FPSP entry point for FP "Unimplemented #
1094# Data Type" exception. #
1095# #
1096# This handler should be the first code executed upon taking the #
1097# FP Unimplemented Data Type exception in an operating system. #
1098# #
1099# XREF **************************************************************** #
1100# _imem_read_{word,long}() - read instruction word/longword #
1101# fix_skewed_ops() - adjust src operand in fsave frame #
1102# set_tag_x() - determine optype of src/dst operands #
1103# store_fpreg() - store opclass 0 or 2 result to FP regfile #
1104# unnorm_fix() - change UNNORM operands to NORM or ZERO #
1105# load_fpn2() - load dst operand from FP regfile #
1106# load_fpn1() - load src operand from FP regfile #
1107# fout() - emulate an opclass 3 instruction #
1108# tbl_unsupp - add of table of emulation routines for opclass 0,2 #
1109# _real_inex() - "callout" to operating system inexact handler #
1110# _fpsp_done() - "callout" for exit; work all done #
1111# _real_trace() - "callout" for Trace enabled exception #
1112# funimp_skew() - adjust fsave src ops to "incorrect" value #
1113# _real_snan() - "callout" for SNAN exception #
1114# _real_operr() - "callout" for OPERR exception #
1115# _real_ovfl() - "callout" for OVFL exception #
1116# _real_unfl() - "callout" for UNFL exception #
1117# get_packed() - fetch packed operand from memory #
1118# #
1119# INPUT *************************************************************** #
1120# - The system stack contains the "Unimp Data Type" stk frame #
1121# - The fsave frame contains the ssrc op (for UNNORM/DENORM) #
1122# #
1123# OUTPUT ************************************************************** #
1124# If Inexact exception (opclass 3): #
1125# - The system stack is changed to an Inexact exception stk frame #
1126# If SNAN exception (opclass 3): #
1127# - The system stack is changed to an SNAN exception stk frame #
1128# If OPERR exception (opclass 3): #
1129# - The system stack is changed to an OPERR exception stk frame #
1130# If OVFL exception (opclass 3): #
1131# - The system stack is changed to an OVFL exception stk frame #
1132# If UNFL exception (opclass 3): #
1133# - The system stack is changed to an UNFL exception stack frame #
1134# If Trace exception enabled: #
1135# - The system stack is changed to a Trace exception stack frame #
1136# Else: (normal case) #
1137# - Correct result has been stored as appropriate #
1138# #
1139# ALGORITHM *********************************************************** #
1140# Two main instruction types can enter here: (1) DENORM or UNNORM #
1141# unimplemented data types. These can be either opclass 0,2 or 3 #
1142# instructions, and (2) PACKED unimplemented data format instructions #
1143# also of opclasses 0,2, or 3. #
1144# For UNNORM/DENORM opclass 0 and 2, the handler fetches the src #
1145# operand from the fsave state frame and the dst operand (if dyadic) #
1146# from the FP register file. The instruction is then emulated by #
1147# choosing an emulation routine from a table of routines indexed by #
1148# instruction type. Once the instruction has been emulated and result #
1149# saved, then we check to see if any enabled exceptions resulted from #
1150# instruction emulation. If none, then we exit through the "callout" #
1151# _fpsp_done(). If there is an enabled FP exception, then we insert #
1152# this exception into the FPU in the fsave state frame and then exit #
1153# through _fpsp_done(). #
1154# PACKED opclass 0 and 2 is similar in how the instruction is #
1155# emulated and exceptions handled. The differences occur in how the #
1156# handler loads the packed op (by calling get_packed() routine) and #
1157# by the fact that a Trace exception could be pending for PACKED ops. #
1158# If a Trace exception is pending, then the current exception stack #
1159# frame is changed to a Trace exception stack frame and an exit is #
1160# made through _real_trace(). #
1161# For UNNORM/DENORM opclass 3, the actual move out to memory is #
1162# performed by calling the routine fout(). If no exception should occur #
1163# as the result of emulation, then an exit either occurs through #
1164# _fpsp_done() or through _real_trace() if a Trace exception is pending #
1165# (a Trace stack frame must be created here, too). If an FP exception #
1166# should occur, then we must create an exception stack frame of that #
1167# type and jump to either _real_snan(), _real_operr(), _real_inex(), #
1168# _real_unfl(), or _real_ovfl() as appropriate. PACKED opclass 3 #
1169# emulation is performed in a similar manner. #
1170# #
1171#########################################################################
1172
1173#
1174# (1) DENORM and UNNORM (unimplemented) data types:
1175#
1176# post-instruction
1177# *****************
1178# * EA *
1179# pre-instruction * *
1180# ***************** *****************
1181# * 0x0 * 0x0dc * * 0x3 * 0x0dc *
1182# ***************** *****************
1183# * Next * * Next *
1184# * PC * * PC *
1185# ***************** *****************
1186# * SR * * SR *
1187# ***************** *****************
1188#
1189# (2) PACKED format (unsupported) opclasses two and three:
1190# *****************
1191# * EA *
1192# * *
1193# *****************
1194# * 0x2 * 0x0dc *
1195# *****************
1196# * Next *
1197# * PC *
1198# *****************
1199# * SR *
1200# *****************
1201#
1202 global _fpsp_unsupp
1203_fpsp_unsupp:
1204
1205 link.w %a6,&-LOCAL_SIZE # init stack frame
1206
1207 fsave FP_SRC(%a6) # save fp state
1208
1209 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
1210 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
1211 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack
1212
1213 btst &0x5,EXC_SR(%a6) # user or supervisor mode?
1214 bne.b fu_s
1215fu_u:
1216 mov.l %usp,%a0 # fetch user stack pointer
1217 mov.l %a0,EXC_A7(%a6) # save on stack
1218 bra.b fu_cont
1219# if the exception is an opclass zero or two unimplemented data type
1220# exception, then the a7' calculated here is wrong since it doesn't
1221# stack an ea. however, we don't need an a7' for this case anyways.
1222fu_s:
1223 lea 0x4+EXC_EA(%a6),%a0 # load old a7'
1224 mov.l %a0,EXC_A7(%a6) # save on stack
1225
1226fu_cont:
1227
1228# the FPIAR holds the "current PC" of the faulting instruction
1229# the FPIAR should be set correctly for ALL exceptions passing through
1230# this point.
1231 mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
1232 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
1233 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
1234 bsr.l _imem_read_long # fetch the instruction words
1235 mov.l %d0,EXC_OPWORD(%a6) # store OPWORD and EXTWORD
1236
1237############################
1238
1239 clr.b SPCOND_FLG(%a6) # clear special condition flag
1240
1241# Separate opclass three (fpn-to-mem) ops since they have a different
1242# stack frame and protocol.
1243 btst &0x5,EXC_CMDREG(%a6) # is it an fmove out?
1244 bne.w fu_out # yes
1245
1246# Separate packed opclass two instructions.
1247 bfextu EXC_CMDREG(%a6){&0:&6},%d0
1248 cmpi.b %d0,&0x13
1249 beq.w fu_in_pack
1250
1251
1252# I'm not sure at this point what FPSR bits are valid for this instruction.
1253# so, since the emulation routines re-create them anyways, zero exception field
1254 andi.l &0x00ff00ff,USER_FPSR(%a6) # zero exception field
1255
1256 fmov.l &0x0,%fpcr # zero current control regs
1257 fmov.l &0x0,%fpsr
1258
1259# Opclass two w/ memory-to-fpn operation will have an incorrect extended
1260# precision format if the src format was single or double and the
1261# source data type was an INF, NAN, DENORM, or UNNORM
1262 lea FP_SRC(%a6),%a0 # pass ptr to input
1263 bsr.l fix_skewed_ops
1264
1265# we don't know whether the src operand or the dst operand (or both) is the
1266# UNNORM or DENORM. call the function that tags the operand type. if the
1267# input is an UNNORM, then convert it to a NORM, DENORM, or ZERO.
1268 lea FP_SRC(%a6),%a0 # pass: ptr to src op
1269 bsr.l set_tag_x # tag the operand type
1270 cmpi.b %d0,&UNNORM # is operand an UNNORM?
1271 bne.b fu_op2 # no
1272 bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO
1273
1274fu_op2:
1275 mov.b %d0,STAG(%a6) # save src optype tag
1276
1277 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1278
1279# bit five of the fp extension word separates the monadic and dyadic operations
1280# at this point
1281 btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic?
1282 beq.b fu_extract # monadic
1283 cmpi.b 1+EXC_CMDREG(%a6),&0x3a # is operation an ftst?
1284 beq.b fu_extract # yes, so it's monadic, too
1285
1286 bsr.l load_fpn2 # load dst into FP_DST
1287
1288 lea FP_DST(%a6),%a0 # pass: ptr to dst op
1289 bsr.l set_tag_x # tag the operand type
1290 cmpi.b %d0,&UNNORM # is operand an UNNORM?
1291 bne.b fu_op2_done # no
1292 bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO
1293fu_op2_done:
1294 mov.b %d0,DTAG(%a6) # save dst optype tag
1295
1296fu_extract:
1297 clr.l %d0
1298 mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec
1299
1300 bfextu 1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension
1301
1302 lea FP_SRC(%a6),%a0
1303 lea FP_DST(%a6),%a1
1304
1305 mov.l (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr
1306 jsr (tbl_unsupp.l,%pc,%d1.l*1)
1307
1308#
1309# Exceptions in order of precedence:
1310# BSUN : none
1311# SNAN : all dyadic ops
1312# OPERR : fsqrt(-NORM)
1313# OVFL : all except ftst,fcmp
1314# UNFL : all except ftst,fcmp
1315# DZ : fdiv
1316# INEX2 : all except ftst,fcmp
1317# INEX1 : none (packed doesn't go through here)
1318#
1319
1320# we determine the highest priority exception(if any) set by the
1321# emulation routine that has also been enabled by the user.
1322 mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions set
1323 bne.b fu_in_ena # some are enabled
1324
1325fu_in_cont:
1326# fcmp and ftst do not store any result.
1327 mov.b 1+EXC_CMDREG(%a6),%d0 # fetch extension
1328 andi.b &0x38,%d0 # extract bits 3-5
1329 cmpi.b %d0,&0x38 # is instr fcmp or ftst?
1330 beq.b fu_in_exit # yes
1331
1332 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1333 bsr.l store_fpreg # store the result
1334
1335fu_in_exit:
1336
1337 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1338 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1339 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1340
1341 unlk %a6
1342
1343 bra.l _fpsp_done
1344
1345fu_in_ena:
1346 and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled
1347 bfffo %d0{&24:&8},%d0 # find highest priority exception
1348 bne.b fu_in_exc # there is at least one set
1349
1350#
1351# No exceptions occurred that were also enabled. Now:
1352#
1353# if (OVFL && ovfl_disabled && inexact_enabled) {
1354# branch to _real_inex() (even if the result was exact!);
1355# } else {
1356# save the result in the proper fp reg (unless the op is fcmp or ftst);
1357# return;
1358# }
1359#
1360 btst &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
1361 beq.b fu_in_cont # no
1362
1363fu_in_ovflchk:
1364 btst &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
1365 beq.b fu_in_cont # no
1366 bra.w fu_in_exc_ovfl # go insert overflow frame
1367
1368#
1369# An exception occurred and that exception was enabled:
1370#
1371# shift enabled exception field into lo byte of d0;
1372# if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) ||
1373# ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) {
1374# /*
1375# * this is the case where we must call _real_inex() now or else
1376# * there will be no other way to pass it the exceptional operand
1377# */
1378# call _real_inex();
1379# } else {
1380# restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU;
1381# }
1382#
1383fu_in_exc:
1384 subi.l &24,%d0 # fix offset to be 0-8
1385 cmpi.b %d0,&0x6 # is exception INEX? (6)
1386 bne.b fu_in_exc_exit # no
1387
1388# the enabled exception was inexact
1389 btst &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur?
1390 bne.w fu_in_exc_unfl # yes
1391 btst &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur?
1392 bne.w fu_in_exc_ovfl # yes
1393
1394# here, we insert the correct fsave status value into the fsave frame for the
1395# corresponding exception. the operand in the fsave frame should be the original
1396# src operand.
1397fu_in_exc_exit:
1398 mov.l %d0,-(%sp) # save d0
1399 bsr.l funimp_skew # skew sgl or dbl inputs
1400 mov.l (%sp)+,%d0 # restore d0
1401
1402 mov.w (tbl_except.b,%pc,%d0.w*2),2+FP_SRC(%a6) # create exc status
1403
1404 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1405 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1406 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1407
1408 frestore FP_SRC(%a6) # restore src op
1409
1410 unlk %a6
1411
1412 bra.l _fpsp_done
1413
1414tbl_except:
1415 short 0xe000,0xe006,0xe004,0xe005
1416 short 0xe003,0xe002,0xe001,0xe001
1417
1418fu_in_exc_unfl:
1419 mov.w &0x4,%d0
1420 bra.b fu_in_exc_exit
1421fu_in_exc_ovfl:
1422 mov.w &0x03,%d0
1423 bra.b fu_in_exc_exit
1424
1425# If the input operand to this operation was opclass two and a single
1426# or double precision denorm, inf, or nan, the operand needs to be
1427# "corrected" in order to have the proper equivalent extended precision
1428# number.
1429 global fix_skewed_ops
1430fix_skewed_ops:
1431 bfextu EXC_CMDREG(%a6){&0:&6},%d0 # extract opclass,src fmt
1432 cmpi.b %d0,&0x11 # is class = 2 & fmt = sgl?
1433 beq.b fso_sgl # yes
1434 cmpi.b %d0,&0x15 # is class = 2 & fmt = dbl?
1435 beq.b fso_dbl # yes
1436 rts # no
1437
1438fso_sgl:
1439 mov.w LOCAL_EX(%a0),%d0 # fetch src exponent
1440 andi.w &0x7fff,%d0 # strip sign
1441 cmpi.w %d0,&0x3f80 # is |exp| == $3f80?
1442 beq.b fso_sgl_dnrm_zero # yes
1443 cmpi.w %d0,&0x407f # no; is |exp| == $407f?
1444 beq.b fso_infnan # yes
1445 rts # no
1446
1447fso_sgl_dnrm_zero:
1448 andi.l &0x7fffffff,LOCAL_HI(%a0) # clear j-bit
1449 beq.b fso_zero # it's a skewed zero
1450fso_sgl_dnrm:
1451# here, we count on norm not to alter a0...
1452 bsr.l norm # normalize mantissa
1453 neg.w %d0 # -shft amt
1454 addi.w &0x3f81,%d0 # adjust new exponent
1455 andi.w &0x8000,LOCAL_EX(%a0) # clear old exponent
1456 or.w %d0,LOCAL_EX(%a0) # insert new exponent
1457 rts
1458
1459fso_zero:
1460 andi.w &0x8000,LOCAL_EX(%a0) # clear bogus exponent
1461 rts
1462
1463fso_infnan:
1464 andi.b &0x7f,LOCAL_HI(%a0) # clear j-bit
1465 ori.w &0x7fff,LOCAL_EX(%a0) # make exponent = $7fff
1466 rts
1467
1468fso_dbl:
1469 mov.w LOCAL_EX(%a0),%d0 # fetch src exponent
1470 andi.w &0x7fff,%d0 # strip sign
1471 cmpi.w %d0,&0x3c00 # is |exp| == $3c00?
1472 beq.b fso_dbl_dnrm_zero # yes
1473 cmpi.w %d0,&0x43ff # no; is |exp| == $43ff?
1474 beq.b fso_infnan # yes
1475 rts # no
1476
1477fso_dbl_dnrm_zero:
1478 andi.l &0x7fffffff,LOCAL_HI(%a0) # clear j-bit
1479 bne.b fso_dbl_dnrm # it's a skewed denorm
1480 tst.l LOCAL_LO(%a0) # is it a zero?
1481 beq.b fso_zero # yes
1482fso_dbl_dnrm:
1483# here, we count on norm not to alter a0...
1484 bsr.l norm # normalize mantissa
1485 neg.w %d0 # -shft amt
1486 addi.w &0x3c01,%d0 # adjust new exponent
1487 andi.w &0x8000,LOCAL_EX(%a0) # clear old exponent
1488 or.w %d0,LOCAL_EX(%a0) # insert new exponent
1489 rts
1490
1491#################################################################
1492
1493# fmove out took an unimplemented data type exception.
1494# the src operand is in FP_SRC. Call _fout() to write out the result and
1495# to determine which exceptions, if any, to take.
1496fu_out:
1497
1498# Separate packed move outs from the UNNORM and DENORM move outs.
1499 bfextu EXC_CMDREG(%a6){&3:&3},%d0
1500 cmpi.b %d0,&0x3
1501 beq.w fu_out_pack
1502 cmpi.b %d0,&0x7
1503 beq.w fu_out_pack
1504
1505
1506# I'm not sure at this point what FPSR bits are valid for this instruction.
1507# so, since the emulation routines re-create them anyways, zero exception field.
1508# fmove out doesn't affect ccodes.
1509 and.l &0xffff00ff,USER_FPSR(%a6) # zero exception field
1510
1511 fmov.l &0x0,%fpcr # zero current control regs
1512 fmov.l &0x0,%fpsr
1513
1514# the src can ONLY be a DENORM or an UNNORM! so, don't make any big subroutine
1515# call here. just figure out what it is...
1516 mov.w FP_SRC_EX(%a6),%d0 # get exponent
1517 andi.w &0x7fff,%d0 # strip sign
1518 beq.b fu_out_denorm # it's a DENORM
1519
1520 lea FP_SRC(%a6),%a0
1521 bsr.l unnorm_fix # yes; fix it
1522
1523 mov.b %d0,STAG(%a6)
1524
1525 bra.b fu_out_cont
1526fu_out_denorm:
1527 mov.b &DENORM,STAG(%a6)
1528fu_out_cont:
1529
1530 clr.l %d0
1531 mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec
1532
1533 lea FP_SRC(%a6),%a0 # pass ptr to src operand
1534
1535 mov.l (%a6),EXC_A6(%a6) # in case a6 changes
1536 bsr.l fout # call fmove out routine
1537
1538# Exceptions in order of precedence:
1539# BSUN : none
1540# SNAN : none
1541# OPERR : fmove.{b,w,l} out of large UNNORM
1542# OVFL : fmove.{s,d}
1543# UNFL : fmove.{s,d,x}
1544# DZ : none
1545# INEX2 : all
1546# INEX1 : none (packed doesn't travel through here)
1547
1548# determine the highest priority exception(if any) set by the
1549# emulation routine that has also been enabled by the user.
1550 mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled
1551 bne.w fu_out_ena # some are enabled
1552
1553fu_out_done:
1554
1555 mov.l EXC_A6(%a6),(%a6) # in case a6 changed
1556
1557# on extended precision opclass three instructions using pre-decrement or
1558# post-increment addressing mode, the address register is not updated. is the
1559# address register was the stack pointer used from user mode, then let's update
1560# it here. if it was used from supervisor mode, then we have to handle this
1561# as a special case.
1562 btst &0x5,EXC_SR(%a6)
1563 bne.b fu_out_done_s
1564
1565 mov.l EXC_A7(%a6),%a0 # restore a7
1566 mov.l %a0,%usp
1567
1568fu_out_done_cont:
1569 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1570 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1571 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1572
1573 unlk %a6
1574
1575 btst &0x7,(%sp) # is trace on?
1576 bne.b fu_out_trace # yes
1577
1578 bra.l _fpsp_done
1579
1580# is the ea mode pre-decrement of the stack pointer from supervisor mode?
1581# ("fmov.x fpm,-(a7)") if so,
1582fu_out_done_s:
1583 cmpi.b SPCOND_FLG(%a6),&mda7_flg
1584 bne.b fu_out_done_cont
1585
1586# the extended precision result is still in fp0. but, we need to save it
1587# somewhere on the stack until we can copy it to its final resting place.
1588# here, we're counting on the top of the stack to be the old place-holders
1589# for fp0/fp1 which have already been restored. that way, we can write
1590# over those destinations with the shifted stack frame.
1591 fmovm.x &0x80,FP_SRC(%a6) # put answer on stack
1592
1593 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1594 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1595 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1596
1597 mov.l (%a6),%a6 # restore frame pointer
1598
1599 mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
1600 mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
1601
1602# now, copy the result to the proper place on the stack
1603 mov.l LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
1604 mov.l LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
1605 mov.l LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
1606
1607 add.l &LOCAL_SIZE-0x8,%sp
1608
1609 btst &0x7,(%sp)
1610 bne.b fu_out_trace
1611
1612 bra.l _fpsp_done
1613
1614fu_out_ena:
1615 and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled
1616 bfffo %d0{&24:&8},%d0 # find highest priority exception
1617 bne.b fu_out_exc # there is at least one set
1618
1619# no exceptions were set.
1620# if a disabled overflow occurred and inexact was enabled but the result
1621# was exact, then a branch to _real_inex() is made.
1622 btst &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
1623 beq.w fu_out_done # no
1624
1625fu_out_ovflchk:
1626 btst &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
1627 beq.w fu_out_done # no
1628 bra.w fu_inex # yes
1629
1630#
1631# The fp move out that took the "Unimplemented Data Type" exception was
1632# being traced. Since the stack frames are similar, get the "current" PC
1633# from FPIAR and put it in the trace stack frame then jump to _real_trace().
1634#
1635# UNSUPP FRAME TRACE FRAME
1636# ***************** *****************
1637# * EA * * Current *
1638# * * * PC *
1639# ***************** *****************
1640# * 0x3 * 0x0dc * * 0x2 * 0x024 *
1641# ***************** *****************
1642# * Next * * Next *
1643# * PC * * PC *
1644# ***************** *****************
1645# * SR * * SR *
1646# ***************** *****************
1647#
1648fu_out_trace:
1649 mov.w &0x2024,0x6(%sp)
1650 fmov.l %fpiar,0x8(%sp)
1651 bra.l _real_trace
1652
1653# an exception occurred and that exception was enabled.
1654fu_out_exc:
1655 subi.l &24,%d0 # fix offset to be 0-8
1656
1657# we don't mess with the existing fsave frame. just re-insert it and
1658# jump to the "_real_{}()" handler...
1659 mov.w (tbl_fu_out.b,%pc,%d0.w*2),%d0
1660 jmp (tbl_fu_out.b,%pc,%d0.w*1)
1661
1662 swbeg &0x8
1663tbl_fu_out:
1664 short tbl_fu_out - tbl_fu_out # BSUN can't happen
1665 short tbl_fu_out - tbl_fu_out # SNAN can't happen
1666 short fu_operr - tbl_fu_out # OPERR
1667 short fu_ovfl - tbl_fu_out # OVFL
1668 short fu_unfl - tbl_fu_out # UNFL
1669 short tbl_fu_out - tbl_fu_out # DZ can't happen
1670 short fu_inex - tbl_fu_out # INEX2
1671 short tbl_fu_out - tbl_fu_out # INEX1 won't make it here
1672
1673# for snan,operr,ovfl,unfl, src op is still in FP_SRC so just
1674# frestore it.
1675fu_snan:
1676 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1677 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1678 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1679
1680 mov.w &0x30d8,EXC_VOFF(%a6) # vector offset = 0xd8
1681 mov.w &0xe006,2+FP_SRC(%a6)
1682
1683 frestore FP_SRC(%a6)
1684
1685 unlk %a6
1686
1687
1688 bra.l _real_snan
1689
1690fu_operr:
1691 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1692 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1693 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1694
1695 mov.w &0x30d0,EXC_VOFF(%a6) # vector offset = 0xd0
1696 mov.w &0xe004,2+FP_SRC(%a6)
1697
1698 frestore FP_SRC(%a6)
1699
1700 unlk %a6
1701
1702
1703 bra.l _real_operr
1704
1705fu_ovfl:
1706 fmovm.x &0x40,FP_SRC(%a6) # save EXOP to the stack
1707
1708 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1709 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1710 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1711
1712 mov.w &0x30d4,EXC_VOFF(%a6) # vector offset = 0xd4
1713 mov.w &0xe005,2+FP_SRC(%a6)
1714
1715 frestore FP_SRC(%a6) # restore EXOP
1716
1717 unlk %a6
1718
1719 bra.l _real_ovfl
1720
1721# underflow can happen for extended precision. extended precision opclass
1722# three instruction exceptions don't update the stack pointer. so, if the
1723# exception occurred from user mode, then simply update a7 and exit normally.
1724# if the exception occurred from supervisor mode, check if
1725fu_unfl:
1726 mov.l EXC_A6(%a6),(%a6) # restore a6
1727
1728 btst &0x5,EXC_SR(%a6)
1729 bne.w fu_unfl_s
1730
1731 mov.l EXC_A7(%a6),%a0 # restore a7 whether we need
1732 mov.l %a0,%usp # to or not...
1733
1734fu_unfl_cont:
1735 fmovm.x &0x40,FP_SRC(%a6) # save EXOP to the stack
1736
1737 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1738 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1739 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1740
1741 mov.w &0x30cc,EXC_VOFF(%a6) # vector offset = 0xcc
1742 mov.w &0xe003,2+FP_SRC(%a6)
1743
1744 frestore FP_SRC(%a6) # restore EXOP
1745
1746 unlk %a6
1747
1748 bra.l _real_unfl
1749
1750fu_unfl_s:
1751 cmpi.b SPCOND_FLG(%a6),&mda7_flg # was the <ea> mode -(sp)?
1752 bne.b fu_unfl_cont
1753
1754# the extended precision result is still in fp0. but, we need to save it
1755# somewhere on the stack until we can copy it to its final resting place
1756# (where the exc frame is currently). make sure it's not at the top of the
1757# frame or it will get overwritten when the exc stack frame is shifted "down".
1758 fmovm.x &0x80,FP_SRC(%a6) # put answer on stack
1759 fmovm.x &0x40,FP_DST(%a6) # put EXOP on stack
1760
1761 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1762 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1763 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1764
1765 mov.w &0x30cc,EXC_VOFF(%a6) # vector offset = 0xcc
1766 mov.w &0xe003,2+FP_DST(%a6)
1767
1768 frestore FP_DST(%a6) # restore EXOP
1769
1770 mov.l (%a6),%a6 # restore frame pointer
1771
1772 mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
1773 mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
1774 mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
1775
1776# now, copy the result to the proper place on the stack
1777 mov.l LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
1778 mov.l LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
1779 mov.l LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
1780
1781 add.l &LOCAL_SIZE-0x8,%sp
1782
1783 bra.l _real_unfl
1784
1785# fmove in and out enter here.
1786fu_inex:
1787 fmovm.x &0x40,FP_SRC(%a6) # save EXOP to the stack
1788
1789 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1790 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1791 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1792
1793 mov.w &0x30c4,EXC_VOFF(%a6) # vector offset = 0xc4
1794 mov.w &0xe001,2+FP_SRC(%a6)
1795
1796 frestore FP_SRC(%a6) # restore EXOP
1797
1798 unlk %a6
1799
1800
1801 bra.l _real_inex
1802
1803#########################################################################
1804#########################################################################
1805fu_in_pack:
1806
1807
1808# I'm not sure at this point what FPSR bits are valid for this instruction.
1809# so, since the emulation routines re-create them anyways, zero exception field
1810 andi.l &0x0ff00ff,USER_FPSR(%a6) # zero exception field
1811
1812 fmov.l &0x0,%fpcr # zero current control regs
1813 fmov.l &0x0,%fpsr
1814
1815 bsr.l get_packed # fetch packed src operand
1816
1817 lea FP_SRC(%a6),%a0 # pass ptr to src
1818 bsr.l set_tag_x # set src optype tag
1819
1820 mov.b %d0,STAG(%a6) # save src optype tag
1821
1822 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1823
1824# bit five of the fp extension word separates the monadic and dyadic operations
1825# at this point
1826 btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic?
1827 beq.b fu_extract_p # monadic
1828 cmpi.b 1+EXC_CMDREG(%a6),&0x3a # is operation an ftst?
1829 beq.b fu_extract_p # yes, so it's monadic, too
1830
1831 bsr.l load_fpn2 # load dst into FP_DST
1832
1833 lea FP_DST(%a6),%a0 # pass: ptr to dst op
1834 bsr.l set_tag_x # tag the operand type
1835 cmpi.b %d0,&UNNORM # is operand an UNNORM?
1836 bne.b fu_op2_done_p # no
1837 bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO
1838fu_op2_done_p:
1839 mov.b %d0,DTAG(%a6) # save dst optype tag
1840
1841fu_extract_p:
1842 clr.l %d0
1843 mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec
1844
1845 bfextu 1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension
1846
1847 lea FP_SRC(%a6),%a0
1848 lea FP_DST(%a6),%a1
1849
1850 mov.l (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr
1851 jsr (tbl_unsupp.l,%pc,%d1.l*1)
1852
1853#
1854# Exceptions in order of precedence:
1855# BSUN : none
1856# SNAN : all dyadic ops
1857# OPERR : fsqrt(-NORM)
1858# OVFL : all except ftst,fcmp
1859# UNFL : all except ftst,fcmp
1860# DZ : fdiv
1861# INEX2 : all except ftst,fcmp
1862# INEX1 : all
1863#
1864
1865# we determine the highest priority exception(if any) set by the
1866# emulation routine that has also been enabled by the user.
1867 mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled
1868 bne.w fu_in_ena_p # some are enabled
1869
1870fu_in_cont_p:
1871# fcmp and ftst do not store any result.
1872 mov.b 1+EXC_CMDREG(%a6),%d0 # fetch extension
1873 andi.b &0x38,%d0 # extract bits 3-5
1874 cmpi.b %d0,&0x38 # is instr fcmp or ftst?
1875 beq.b fu_in_exit_p # yes
1876
1877 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
1878 bsr.l store_fpreg # store the result
1879
1880fu_in_exit_p:
1881
1882 btst &0x5,EXC_SR(%a6) # user or supervisor?
1883 bne.w fu_in_exit_s_p # supervisor
1884
1885 mov.l EXC_A7(%a6),%a0 # update user a7
1886 mov.l %a0,%usp
1887
1888fu_in_exit_cont_p:
1889 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1890 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1891 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1892
1893 unlk %a6 # unravel stack frame
1894
1895 btst &0x7,(%sp) # is trace on?
1896 bne.w fu_trace_p # yes
1897
1898 bra.l _fpsp_done # exit to os
1899
1900# the exception occurred in supervisor mode. check to see if the
1901# addressing mode was (a7)+. if so, we'll need to shift the
1902# stack frame "up".
1903fu_in_exit_s_p:
1904 btst &mia7_bit,SPCOND_FLG(%a6) # was ea mode (a7)+
1905 beq.b fu_in_exit_cont_p # no
1906
1907 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1908 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1909 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1910
1911 unlk %a6 # unravel stack frame
1912
1913# shift the stack frame "up". we don't really care about the <ea> field.
1914 mov.l 0x4(%sp),0x10(%sp)
1915 mov.l 0x0(%sp),0xc(%sp)
1916 add.l &0xc,%sp
1917
1918 btst &0x7,(%sp) # is trace on?
1919 bne.w fu_trace_p # yes
1920
1921 bra.l _fpsp_done # exit to os
1922
1923fu_in_ena_p:
1924 and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled & set
1925 bfffo %d0{&24:&8},%d0 # find highest priority exception
1926 bne.b fu_in_exc_p # at least one was set
1927
1928#
1929# No exceptions occurred that were also enabled. Now:
1930#
1931# if (OVFL && ovfl_disabled && inexact_enabled) {
1932# branch to _real_inex() (even if the result was exact!);
1933# } else {
1934# save the result in the proper fp reg (unless the op is fcmp or ftst);
1935# return;
1936# }
1937#
1938 btst &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set?
1939 beq.w fu_in_cont_p # no
1940
1941fu_in_ovflchk_p:
1942 btst &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled?
1943 beq.w fu_in_cont_p # no
1944 bra.w fu_in_exc_ovfl_p # do _real_inex() now
1945
1946#
1947# An exception occurred and that exception was enabled:
1948#
1949# shift enabled exception field into lo byte of d0;
1950# if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) ||
1951# ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) {
1952# /*
1953# * this is the case where we must call _real_inex() now or else
1954# * there will be no other way to pass it the exceptional operand
1955# */
1956# call _real_inex();
1957# } else {
1958# restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU;
1959# }
1960#
1961fu_in_exc_p:
1962 subi.l &24,%d0 # fix offset to be 0-8
1963 cmpi.b %d0,&0x6 # is exception INEX? (6 or 7)
1964 blt.b fu_in_exc_exit_p # no
1965
1966# the enabled exception was inexact
1967 btst &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur?
1968 bne.w fu_in_exc_unfl_p # yes
1969 btst &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur?
1970 bne.w fu_in_exc_ovfl_p # yes
1971
1972# here, we insert the correct fsave status value into the fsave frame for the
1973# corresponding exception. the operand in the fsave frame should be the original
1974# src operand.
1975# as a reminder for future predicted pain and agony, we are passing in fsave the
1976# "non-skewed" operand for cases of sgl and dbl src INFs,NANs, and DENORMs.
1977# this is INCORRECT for enabled SNAN which would give to the user the skewed SNAN!!!
1978fu_in_exc_exit_p:
1979 btst &0x5,EXC_SR(%a6) # user or supervisor?
1980 bne.w fu_in_exc_exit_s_p # supervisor
1981
1982 mov.l EXC_A7(%a6),%a0 # update user a7
1983 mov.l %a0,%usp
1984
1985fu_in_exc_exit_cont_p:
1986 mov.w (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6)
1987
1988 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
1989 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
1990 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
1991
1992 frestore FP_SRC(%a6) # restore src op
1993
1994 unlk %a6
1995
1996 btst &0x7,(%sp) # is trace enabled?
1997 bne.w fu_trace_p # yes
1998
1999 bra.l _fpsp_done
2000
2001tbl_except_p:
2002 short 0xe000,0xe006,0xe004,0xe005
2003 short 0xe003,0xe002,0xe001,0xe001
2004
2005fu_in_exc_ovfl_p:
2006 mov.w &0x3,%d0
2007 bra.w fu_in_exc_exit_p
2008
2009fu_in_exc_unfl_p:
2010 mov.w &0x4,%d0
2011 bra.w fu_in_exc_exit_p
2012
2013fu_in_exc_exit_s_p:
2014 btst &mia7_bit,SPCOND_FLG(%a6)
2015 beq.b fu_in_exc_exit_cont_p
2016
2017 mov.w (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6)
2018
2019 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
2020 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2021 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2022
2023 frestore FP_SRC(%a6) # restore src op
2024
2025 unlk %a6 # unravel stack frame
2026
2027# shift stack frame "up". who cares about <ea> field.
2028 mov.l 0x4(%sp),0x10(%sp)
2029 mov.l 0x0(%sp),0xc(%sp)
2030 add.l &0xc,%sp
2031
2032 btst &0x7,(%sp) # is trace on?
2033 bne.b fu_trace_p # yes
2034
2035 bra.l _fpsp_done # exit to os
2036
2037#
2038# The opclass two PACKED instruction that took an "Unimplemented Data Type"
2039# exception was being traced. Make the "current" PC the FPIAR and put it in the
2040# trace stack frame then jump to _real_trace().
2041#
2042# UNSUPP FRAME TRACE FRAME
2043# ***************** *****************
2044# * EA * * Current *
2045# * * * PC *
2046# ***************** *****************
2047# * 0x2 * 0x0dc * * 0x2 * 0x024 *
2048# ***************** *****************
2049# * Next * * Next *
2050# * PC * * PC *
2051# ***************** *****************
2052# * SR * * SR *
2053# ***************** *****************
2054fu_trace_p:
2055 mov.w &0x2024,0x6(%sp)
2056 fmov.l %fpiar,0x8(%sp)
2057
2058 bra.l _real_trace
2059
2060#########################################################
2061#########################################################
2062fu_out_pack:
2063
2064
2065# I'm not sure at this point what FPSR bits are valid for this instruction.
2066# so, since the emulation routines re-create them anyways, zero exception field.
2067# fmove out doesn't affect ccodes.
2068 and.l &0xffff00ff,USER_FPSR(%a6) # zero exception field
2069
2070 fmov.l &0x0,%fpcr # zero current control regs
2071 fmov.l &0x0,%fpsr
2072
2073 bfextu EXC_CMDREG(%a6){&6:&3},%d0
2074 bsr.l load_fpn1
2075
2076# unlike other opclass 3, unimplemented data type exceptions, packed must be
2077# able to detect all operand types.
2078 lea FP_SRC(%a6),%a0
2079 bsr.l set_tag_x # tag the operand type
2080 cmpi.b %d0,&UNNORM # is operand an UNNORM?
2081 bne.b fu_op2_p # no
2082 bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO
2083
2084fu_op2_p:
2085 mov.b %d0,STAG(%a6) # save src optype tag
2086
2087 clr.l %d0
2088 mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec
2089
2090 lea FP_SRC(%a6),%a0 # pass ptr to src operand
2091
2092 mov.l (%a6),EXC_A6(%a6) # in case a6 changes
2093 bsr.l fout # call fmove out routine
2094
2095# Exceptions in order of precedence:
2096# BSUN : no
2097# SNAN : yes
2098# OPERR : if ((k_factor > +17) || (dec. exp exceeds 3 digits))
2099# OVFL : no
2100# UNFL : no
2101# DZ : no
2102# INEX2 : yes
2103# INEX1 : no
2104
2105# determine the highest priority exception(if any) set by the
2106# emulation routine that has also been enabled by the user.
2107 mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled
2108 bne.w fu_out_ena_p # some are enabled
2109
2110fu_out_exit_p:
2111 mov.l EXC_A6(%a6),(%a6) # restore a6
2112
2113 btst &0x5,EXC_SR(%a6) # user or supervisor?
2114 bne.b fu_out_exit_s_p # supervisor
2115
2116 mov.l EXC_A7(%a6),%a0 # update user a7
2117 mov.l %a0,%usp
2118
2119fu_out_exit_cont_p:
2120 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
2121 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2122 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2123
2124 unlk %a6 # unravel stack frame
2125
2126 btst &0x7,(%sp) # is trace on?
2127 bne.w fu_trace_p # yes
2128
2129 bra.l _fpsp_done # exit to os
2130
2131# the exception occurred in supervisor mode. check to see if the
2132# addressing mode was -(a7). if so, we'll need to shift the
2133# stack frame "down".
2134fu_out_exit_s_p:
2135 btst &mda7_bit,SPCOND_FLG(%a6) # was ea mode -(a7)
2136 beq.b fu_out_exit_cont_p # no
2137
2138 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
2139 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2140 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2141
2142 mov.l (%a6),%a6 # restore frame pointer
2143
2144 mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2145 mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2146
2147# now, copy the result to the proper place on the stack
2148 mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp)
2149 mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp)
2150 mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp)
2151
2152 add.l &LOCAL_SIZE-0x8,%sp
2153
2154 btst &0x7,(%sp)
2155 bne.w fu_trace_p
2156
2157 bra.l _fpsp_done
2158
2159fu_out_ena_p:
2160 and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled
2161 bfffo %d0{&24:&8},%d0 # find highest priority exception
2162 beq.w fu_out_exit_p
2163
2164 mov.l EXC_A6(%a6),(%a6) # restore a6
2165
2166# an exception occurred and that exception was enabled.
2167# the only exception possible on packed move out are INEX, OPERR, and SNAN.
2168fu_out_exc_p:
2169 cmpi.b %d0,&0x1a
2170 bgt.w fu_inex_p2
2171 beq.w fu_operr_p
2172
2173fu_snan_p:
2174 btst &0x5,EXC_SR(%a6)
2175 bne.b fu_snan_s_p
2176
2177 mov.l EXC_A7(%a6),%a0
2178 mov.l %a0,%usp
2179 bra.w fu_snan
2180
2181fu_snan_s_p:
2182 cmpi.b SPCOND_FLG(%a6),&mda7_flg
2183 bne.w fu_snan
2184
2185# the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
2186# the strategy is to move the exception frame "down" 12 bytes. then, we
2187# can store the default result where the exception frame was.
2188 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
2189 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2190 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2191
2192 mov.w &0x30d8,EXC_VOFF(%a6) # vector offset = 0xd0
2193 mov.w &0xe006,2+FP_SRC(%a6) # set fsave status
2194
2195 frestore FP_SRC(%a6) # restore src operand
2196
2197 mov.l (%a6),%a6 # restore frame pointer
2198
2199 mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2200 mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2201 mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
2202
2203# now, we copy the default result to its proper location
2204 mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
2205 mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
2206 mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
2207
2208 add.l &LOCAL_SIZE-0x8,%sp
2209
2210
2211 bra.l _real_snan
2212
2213fu_operr_p:
2214 btst &0x5,EXC_SR(%a6)
2215 bne.w fu_operr_p_s
2216
2217 mov.l EXC_A7(%a6),%a0
2218 mov.l %a0,%usp
2219 bra.w fu_operr
2220
2221fu_operr_p_s:
2222 cmpi.b SPCOND_FLG(%a6),&mda7_flg
2223 bne.w fu_operr
2224
2225# the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
2226# the strategy is to move the exception frame "down" 12 bytes. then, we
2227# can store the default result where the exception frame was.
2228 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
2229 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2230 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2231
2232 mov.w &0x30d0,EXC_VOFF(%a6) # vector offset = 0xd0
2233 mov.w &0xe004,2+FP_SRC(%a6) # set fsave status
2234
2235 frestore FP_SRC(%a6) # restore src operand
2236
2237 mov.l (%a6),%a6 # restore frame pointer
2238
2239 mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2240 mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2241 mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
2242
2243# now, we copy the default result to its proper location
2244 mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
2245 mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
2246 mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
2247
2248 add.l &LOCAL_SIZE-0x8,%sp
2249
2250
2251 bra.l _real_operr
2252
2253fu_inex_p2:
2254 btst &0x5,EXC_SR(%a6)
2255 bne.w fu_inex_s_p2
2256
2257 mov.l EXC_A7(%a6),%a0
2258 mov.l %a0,%usp
2259 bra.w fu_inex
2260
2261fu_inex_s_p2:
2262 cmpi.b SPCOND_FLG(%a6),&mda7_flg
2263 bne.w fu_inex
2264
2265# the instruction was "fmove.p fpn,-(a7)" from supervisor mode.
2266# the strategy is to move the exception frame "down" 12 bytes. then, we
2267# can store the default result where the exception frame was.
2268 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1
2269 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2270 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2271
2272 mov.w &0x30c4,EXC_VOFF(%a6) # vector offset = 0xc4
2273 mov.w &0xe001,2+FP_SRC(%a6) # set fsave status
2274
2275 frestore FP_SRC(%a6) # restore src operand
2276
2277 mov.l (%a6),%a6 # restore frame pointer
2278
2279 mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
2280 mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp)
2281 mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
2282
2283# now, we copy the default result to its proper location
2284 mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp)
2285 mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp)
2286 mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp)
2287
2288 add.l &LOCAL_SIZE-0x8,%sp
2289
2290
2291 bra.l _real_inex
2292
2293#########################################################################
2294
2295#
2296# if we're stuffing a source operand back into an fsave frame then we
2297# have to make sure that for single or double source operands that the
2298# format stuffed is as weird as the hardware usually makes it.
2299#
2300 global funimp_skew
2301funimp_skew:
2302 bfextu EXC_EXTWORD(%a6){&3:&3},%d0 # extract src specifier
2303 cmpi.b %d0,&0x1 # was src sgl?
2304 beq.b funimp_skew_sgl # yes
2305 cmpi.b %d0,&0x5 # was src dbl?
2306 beq.b funimp_skew_dbl # yes
2307 rts
2308
2309funimp_skew_sgl:
2310 mov.w FP_SRC_EX(%a6),%d0 # fetch DENORM exponent
2311 andi.w &0x7fff,%d0 # strip sign
2312 beq.b funimp_skew_sgl_not
2313 cmpi.w %d0,&0x3f80
2314 bgt.b funimp_skew_sgl_not
2315 neg.w %d0 # make exponent negative
2316 addi.w &0x3f81,%d0 # find amt to shift
2317 mov.l FP_SRC_HI(%a6),%d1 # fetch DENORM hi(man)
2318 lsr.l %d0,%d1 # shift it
2319 bset &31,%d1 # set j-bit
2320 mov.l %d1,FP_SRC_HI(%a6) # insert new hi(man)
2321 andi.w &0x8000,FP_SRC_EX(%a6) # clear old exponent
2322 ori.w &0x3f80,FP_SRC_EX(%a6) # insert new "skewed" exponent
2323funimp_skew_sgl_not:
2324 rts
2325
2326funimp_skew_dbl:
2327 mov.w FP_SRC_EX(%a6),%d0 # fetch DENORM exponent
2328 andi.w &0x7fff,%d0 # strip sign
2329 beq.b funimp_skew_dbl_not
2330 cmpi.w %d0,&0x3c00
2331 bgt.b funimp_skew_dbl_not
2332
2333 tst.b FP_SRC_EX(%a6) # make "internal format"
2334 smi.b 0x2+FP_SRC(%a6)
2335 mov.w %d0,FP_SRC_EX(%a6) # insert exponent with cleared sign
2336 clr.l %d0 # clear g,r,s
2337 lea FP_SRC(%a6),%a0 # pass ptr to src op
2338 mov.w &0x3c01,%d1 # pass denorm threshold
2339 bsr.l dnrm_lp # denorm it
2340 mov.w &0x3c00,%d0 # new exponent
2341 tst.b 0x2+FP_SRC(%a6) # is sign set?
2342 beq.b fss_dbl_denorm_done # no
2343 bset &15,%d0 # set sign
2344fss_dbl_denorm_done:
2345 bset &0x7,FP_SRC_HI(%a6) # set j-bit
2346 mov.w %d0,FP_SRC_EX(%a6) # insert new exponent
2347funimp_skew_dbl_not:
2348 rts
2349
2350#########################################################################
2351 global _mem_write2
2352_mem_write2:
2353 btst &0x5,EXC_SR(%a6)
2354 beq.l _dmem_write
2355 mov.l 0x0(%a0),FP_DST_EX(%a6)
2356 mov.l 0x4(%a0),FP_DST_HI(%a6)
2357 mov.l 0x8(%a0),FP_DST_LO(%a6)
2358 clr.l %d1
2359 rts
2360
2361#########################################################################
2362# XDEF **************************************************************** #
2363# _fpsp_effadd(): 060FPSP entry point for FP "Unimplemented #
2364# effective address" exception. #
2365# #
2366# This handler should be the first code executed upon taking the #
2367# FP Unimplemented Effective Address exception in an operating #
2368# system. #
2369# #
2370# XREF **************************************************************** #
2371# _imem_read_long() - read instruction longword #
2372# fix_skewed_ops() - adjust src operand in fsave frame #
2373# set_tag_x() - determine optype of src/dst operands #
2374# store_fpreg() - store opclass 0 or 2 result to FP regfile #
2375# unnorm_fix() - change UNNORM operands to NORM or ZERO #
2376# load_fpn2() - load dst operand from FP regfile #
2377# tbl_unsupp - add of table of emulation routines for opclass 0,2 #
2378# decbin() - convert packed data to FP binary data #
2379# _real_fpu_disabled() - "callout" for "FPU disabled" exception #
2380# _real_access() - "callout" for access error exception #
2381# _mem_read() - read extended immediate operand from memory #
2382# _fpsp_done() - "callout" for exit; work all done #
2383# _real_trace() - "callout" for Trace enabled exception #
2384# fmovm_dynamic() - emulate dynamic fmovm instruction #
2385# fmovm_ctrl() - emulate fmovm control instruction #
2386# #
2387# INPUT *************************************************************** #
2388# - The system stack contains the "Unimplemented <ea>" stk frame #
2389# #
2390# OUTPUT ************************************************************** #
2391# If access error: #
2392# - The system stack is changed to an access error stack frame #
2393# If FPU disabled: #
2394# - The system stack is changed to an FPU disabled stack frame #
2395# If Trace exception enabled: #
2396# - The system stack is changed to a Trace exception stack frame #
2397# Else: (normal case) #
2398# - None (correct result has been stored as appropriate) #
2399# #
2400# ALGORITHM *********************************************************** #
2401# This exception handles 3 types of operations: #
2402# (1) FP Instructions using extended precision or packed immediate #
2403# addressing mode. #
2404# (2) The "fmovm.x" instruction w/ dynamic register specification. #
2405# (3) The "fmovm.l" instruction w/ 2 or 3 control registers. #
2406# #
2407# For immediate data operations, the data is read in w/ a #
2408# _mem_read() "callout", converted to FP binary (if packed), and used #
2409# as the source operand to the instruction specified by the instruction #
2410# word. If no FP exception should be reported ads a result of the #
2411# emulation, then the result is stored to the destination register and #
2412# the handler exits through _fpsp_done(). If an enabled exc has been #
2413# signalled as a result of emulation, then an fsave state frame #
2414# corresponding to the FP exception type must be entered into the 060 #
2415# FPU before exiting. In either the enabled or disabled cases, we #
2416# must also check if a Trace exception is pending, in which case, we #
2417# must create a Trace exception stack frame from the current exception #
2418# stack frame. If no Trace is pending, we simply exit through #
2419# _fpsp_done(). #
2420# For "fmovm.x", call the routine fmovm_dynamic() which will #
2421# decode and emulate the instruction. No FP exceptions can be pending #
2422# as a result of this operation emulation. A Trace exception can be #
2423# pending, though, which means the current stack frame must be changed #
2424# to a Trace stack frame and an exit made through _real_trace(). #
2425# For the case of "fmovm.x Dn,-(a7)", where the offending instruction #
2426# was executed from supervisor mode, this handler must store the FP #
2427# register file values to the system stack by itself since #
2428# fmovm_dynamic() can't handle this. A normal exit is made through #
2429# fpsp_done(). #
2430# For "fmovm.l", fmovm_ctrl() is used to emulate the instruction. #
2431# Again, a Trace exception may be pending and an exit made through #
2432# _real_trace(). Else, a normal exit is made through _fpsp_done(). #
2433# #
2434# Before any of the above is attempted, it must be checked to #
2435# see if the FPU is disabled. Since the "Unimp <ea>" exception is taken #
2436# before the "FPU disabled" exception, but the "FPU disabled" exception #
2437# has higher priority, we check the disabled bit in the PCR. If set, #
2438# then we must create an 8 word "FPU disabled" exception stack frame #
2439# from the current 4 word exception stack frame. This includes #
2440# reproducing the effective address of the instruction to put on the #
2441# new stack frame. #
2442# #
2443# In the process of all emulation work, if a _mem_read() #
2444# "callout" returns a failing result indicating an access error, then #
2445# we must create an access error stack frame from the current stack #
2446# frame. This information includes a faulting address and a fault- #
2447# status-longword. These are created within this handler. #
2448# #
2449#########################################################################
2450
2451 global _fpsp_effadd
2452_fpsp_effadd:
2453
2454# This exception type takes priority over the "Line F Emulator"
2455# exception. Therefore, the FPU could be disabled when entering here.
2456# So, we must check to see if it's disabled and handle that case separately.
2457 mov.l %d0,-(%sp) # save d0
2458 movc %pcr,%d0 # load proc cr
2459 btst &0x1,%d0 # is FPU disabled?
2460 bne.w iea_disabled # yes
2461 mov.l (%sp)+,%d0 # restore d0
2462
2463 link %a6,&-LOCAL_SIZE # init stack frame
2464
2465 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
2466 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
2467 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack
2468
2469# PC of instruction that took the exception is the PC in the frame
2470 mov.l EXC_PC(%a6),EXC_EXTWPTR(%a6)
2471
2472 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
2473 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
2474 bsr.l _imem_read_long # fetch the instruction words
2475 mov.l %d0,EXC_OPWORD(%a6) # store OPWORD and EXTWORD
2476
2477#########################################################################
2478
2479 tst.w %d0 # is operation fmovem?
2480 bmi.w iea_fmovm # yes
2481
2482#
2483# here, we will have:
2484# fabs fdabs fsabs facos fmod
2485# fadd fdadd fsadd fasin frem
2486# fcmp fatan fscale
2487# fdiv fddiv fsdiv fatanh fsin
2488# fint fcos fsincos
2489# fintrz fcosh fsinh
2490# fmove fdmove fsmove fetox ftan
2491# fmul fdmul fsmul fetoxm1 ftanh
2492# fneg fdneg fsneg fgetexp ftentox
2493# fsgldiv fgetman ftwotox
2494# fsglmul flog10
2495# fsqrt flog2
2496# fsub fdsub fssub flogn
2497# ftst flognp1
2498# which can all use f<op>.{x,p}
2499# so, now it's immediate data extended precision AND PACKED FORMAT!
2500#
2501iea_op:
2502 andi.l &0x00ff00ff,USER_FPSR(%a6)
2503
2504 btst &0xa,%d0 # is src fmt x or p?
2505 bne.b iea_op_pack # packed
2506
2507
2508 mov.l EXC_EXTWPTR(%a6),%a0 # pass: ptr to #<data>
2509 lea FP_SRC(%a6),%a1 # pass: ptr to super addr
2510 mov.l &0xc,%d0 # pass: 12 bytes
2511 bsr.l _imem_read # read extended immediate
2512
2513 tst.l %d1 # did ifetch fail?
2514 bne.w iea_iacc # yes
2515
2516 bra.b iea_op_setsrc
2517
2518iea_op_pack:
2519
2520 mov.l EXC_EXTWPTR(%a6),%a0 # pass: ptr to #<data>
2521 lea FP_SRC(%a6),%a1 # pass: ptr to super dst
2522 mov.l &0xc,%d0 # pass: 12 bytes
2523 bsr.l _imem_read # read packed operand
2524
2525 tst.l %d1 # did ifetch fail?
2526 bne.w iea_iacc # yes
2527
2528# The packed operand is an INF or a NAN if the exponent field is all ones.
2529 bfextu FP_SRC(%a6){&1:&15},%d0 # get exp
2530 cmpi.w %d0,&0x7fff # INF or NAN?
2531 beq.b iea_op_setsrc # operand is an INF or NAN
2532
2533# The packed operand is a zero if the mantissa is all zero, else it's
2534# a normal packed op.
2535 mov.b 3+FP_SRC(%a6),%d0 # get byte 4
2536 andi.b &0x0f,%d0 # clear all but last nybble
2537 bne.b iea_op_gp_not_spec # not a zero
2538 tst.l FP_SRC_HI(%a6) # is lw 2 zero?
2539 bne.b iea_op_gp_not_spec # not a zero
2540 tst.l FP_SRC_LO(%a6) # is lw 3 zero?
2541 beq.b iea_op_setsrc # operand is a ZERO
2542iea_op_gp_not_spec:
2543 lea FP_SRC(%a6),%a0 # pass: ptr to packed op
2544 bsr.l decbin # convert to extended
2545 fmovm.x &0x80,FP_SRC(%a6) # make this the srcop
2546
2547iea_op_setsrc:
2548 addi.l &0xc,EXC_EXTWPTR(%a6) # update extension word pointer
2549
2550# FP_SRC now holds the src operand.
2551 lea FP_SRC(%a6),%a0 # pass: ptr to src op
2552 bsr.l set_tag_x # tag the operand type
2553 mov.b %d0,STAG(%a6) # could be ANYTHING!!!
2554 cmpi.b %d0,&UNNORM # is operand an UNNORM?
2555 bne.b iea_op_getdst # no
2556 bsr.l unnorm_fix # yes; convert to NORM/DENORM/ZERO
2557 mov.b %d0,STAG(%a6) # set new optype tag
2558iea_op_getdst:
2559 clr.b STORE_FLG(%a6) # clear "store result" boolean
2560
2561 btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic?
2562 beq.b iea_op_extract # monadic
2563 btst &0x4,1+EXC_CMDREG(%a6) # is operation fsincos,ftst,fcmp?
2564 bne.b iea_op_spec # yes
2565
2566iea_op_loaddst:
2567 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno
2568 bsr.l load_fpn2 # load dst operand
2569
2570 lea FP_DST(%a6),%a0 # pass: ptr to dst op
2571 bsr.l set_tag_x # tag the operand type
2572 mov.b %d0,DTAG(%a6) # could be ANYTHING!!!
2573 cmpi.b %d0,&UNNORM # is operand an UNNORM?
2574 bne.b iea_op_extract # no
2575 bsr.l unnorm_fix # yes; convert to NORM/DENORM/ZERO
2576 mov.b %d0,DTAG(%a6) # set new optype tag
2577 bra.b iea_op_extract
2578
2579# the operation is fsincos, ftst, or fcmp. only fcmp is dyadic
2580iea_op_spec:
2581 btst &0x3,1+EXC_CMDREG(%a6) # is operation fsincos?
2582 beq.b iea_op_extract # yes
2583# now, we're left with ftst and fcmp. so, first let's tag them so that they don't
2584# store a result. then, only fcmp will branch back and pick up a dst operand.
2585 st STORE_FLG(%a6) # don't store a final result
2586 btst &0x1,1+EXC_CMDREG(%a6) # is operation fcmp?
2587 beq.b iea_op_loaddst # yes
2588
2589iea_op_extract:
2590 clr.l %d0
2591 mov.b FPCR_MODE(%a6),%d0 # pass: rnd mode,prec
2592
2593 mov.b 1+EXC_CMDREG(%a6),%d1
2594 andi.w &0x007f,%d1 # extract extension
2595
2596 fmov.l &0x0,%fpcr
2597 fmov.l &0x0,%fpsr
2598
2599 lea FP_SRC(%a6),%a0
2600 lea FP_DST(%a6),%a1
2601
2602 mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
2603 jsr (tbl_unsupp.l,%pc,%d1.l*1)
2604
2605#
2606# Exceptions in order of precedence:
2607# BSUN : none
2608# SNAN : all operations
2609# OPERR : all reg-reg or mem-reg operations that can normally operr
2610# OVFL : same as OPERR
2611# UNFL : same as OPERR
2612# DZ : same as OPERR
2613# INEX2 : same as OPERR
2614# INEX1 : all packed immediate operations
2615#
2616
2617# we determine the highest priority exception(if any) set by the
2618# emulation routine that has also been enabled by the user.
2619 mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled
2620 bne.b iea_op_ena # some are enabled
2621
2622# now, we save the result, unless, of course, the operation was ftst or fcmp.
2623# these don't save results.
2624iea_op_save:
2625 tst.b STORE_FLG(%a6) # does this op store a result?
2626 bne.b iea_op_exit1 # exit with no frestore
2627
2628iea_op_store:
2629 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno
2630 bsr.l store_fpreg # store the result
2631
2632iea_op_exit1:
2633 mov.l EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC"
2634 mov.l EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame
2635
2636 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
2637 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2638 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2639
2640 unlk %a6 # unravel the frame
2641
2642 btst &0x7,(%sp) # is trace on?
2643 bne.w iea_op_trace # yes
2644
2645 bra.l _fpsp_done # exit to os
2646
2647iea_op_ena:
2648 and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enable and set
2649 bfffo %d0{&24:&8},%d0 # find highest priority exception
2650 bne.b iea_op_exc # at least one was set
2651
2652# no exception occurred. now, did a disabled, exact overflow occur with inexact
2653# enabled? if so, then we have to stuff an overflow frame into the FPU.
2654 btst &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur?
2655 beq.b iea_op_save
2656
2657iea_op_ovfl:
2658 btst &inex2_bit,FPCR_ENABLE(%a6) # is inexact enabled?
2659 beq.b iea_op_store # no
2660 bra.b iea_op_exc_ovfl # yes
2661
2662# an enabled exception occurred. we have to insert the exception type back into
2663# the machine.
2664iea_op_exc:
2665 subi.l &24,%d0 # fix offset to be 0-8
2666 cmpi.b %d0,&0x6 # is exception INEX?
2667 bne.b iea_op_exc_force # no
2668
2669# the enabled exception was inexact. so, if it occurs with an overflow
2670# or underflow that was disabled, then we have to force an overflow or
2671# underflow frame.
2672 btst &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur?
2673 bne.b iea_op_exc_ovfl # yes
2674 btst &unfl_bit,FPSR_EXCEPT(%a6) # did underflow occur?
2675 bne.b iea_op_exc_unfl # yes
2676
2677iea_op_exc_force:
2678 mov.w (tbl_iea_except.b,%pc,%d0.w*2),2+FP_SRC(%a6)
2679 bra.b iea_op_exit2 # exit with frestore
2680
2681tbl_iea_except:
2682 short 0xe002, 0xe006, 0xe004, 0xe005
2683 short 0xe003, 0xe002, 0xe001, 0xe001
2684
2685iea_op_exc_ovfl:
2686 mov.w &0xe005,2+FP_SRC(%a6)
2687 bra.b iea_op_exit2
2688
2689iea_op_exc_unfl:
2690 mov.w &0xe003,2+FP_SRC(%a6)
2691
2692iea_op_exit2:
2693 mov.l EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC"
2694 mov.l EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame
2695
2696 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
2697 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2698 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2699
2700 frestore FP_SRC(%a6) # restore exceptional state
2701
2702 unlk %a6 # unravel the frame
2703
2704 btst &0x7,(%sp) # is trace on?
2705 bne.b iea_op_trace # yes
2706
2707 bra.l _fpsp_done # exit to os
2708
2709#
2710# The opclass two instruction that took an "Unimplemented Effective Address"
2711# exception was being traced. Make the "current" PC the FPIAR and put it in
2712# the trace stack frame then jump to _real_trace().
2713#
2714# UNIMP EA FRAME TRACE FRAME
2715# ***************** *****************
2716# * 0x0 * 0x0f0 * * Current *
2717# ***************** * PC *
2718# * Current * *****************
2719# * PC * * 0x2 * 0x024 *
2720# ***************** *****************
2721# * SR * * Next *
2722# ***************** * PC *
2723# *****************
2724# * SR *
2725# *****************
2726iea_op_trace:
2727 mov.l (%sp),-(%sp) # shift stack frame "down"
2728 mov.w 0x8(%sp),0x4(%sp)
2729 mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024
2730 fmov.l %fpiar,0x8(%sp) # "Current PC" is in FPIAR
2731
2732 bra.l _real_trace
2733
2734#########################################################################
2735iea_fmovm:
2736 btst &14,%d0 # ctrl or data reg
2737 beq.w iea_fmovm_ctrl
2738
2739iea_fmovm_data:
2740
2741 btst &0x5,EXC_SR(%a6) # user or supervisor mode
2742 bne.b iea_fmovm_data_s
2743
2744iea_fmovm_data_u:
2745 mov.l %usp,%a0
2746 mov.l %a0,EXC_A7(%a6) # store current a7
2747 bsr.l fmovm_dynamic # do dynamic fmovm
2748 mov.l EXC_A7(%a6),%a0 # load possibly new a7
2749 mov.l %a0,%usp # update usp
2750 bra.w iea_fmovm_exit
2751
2752iea_fmovm_data_s:
2753 clr.b SPCOND_FLG(%a6)
2754 lea 0x2+EXC_VOFF(%a6),%a0
2755 mov.l %a0,EXC_A7(%a6)
2756 bsr.l fmovm_dynamic # do dynamic fmovm
2757
2758 cmpi.b SPCOND_FLG(%a6),&mda7_flg
2759 beq.w iea_fmovm_data_predec
2760 cmpi.b SPCOND_FLG(%a6),&mia7_flg
2761 bne.w iea_fmovm_exit
2762
2763# right now, d0 = the size.
2764# the data has been fetched from the supervisor stack, but we have not
2765# incremented the stack pointer by the appropriate number of bytes.
2766# do it here.
2767iea_fmovm_data_postinc:
2768 btst &0x7,EXC_SR(%a6)
2769 bne.b iea_fmovm_data_pi_trace
2770
2771 mov.w EXC_SR(%a6),(EXC_SR,%a6,%d0)
2772 mov.l EXC_EXTWPTR(%a6),(EXC_PC,%a6,%d0)
2773 mov.w &0x00f0,(EXC_VOFF,%a6,%d0)
2774
2775 lea (EXC_SR,%a6,%d0),%a0
2776 mov.l %a0,EXC_SR(%a6)
2777
2778 fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1
2779 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2780 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2781
2782 unlk %a6
2783 mov.l (%sp)+,%sp
2784 bra.l _fpsp_done
2785
2786iea_fmovm_data_pi_trace:
2787 mov.w EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0)
2788 mov.l EXC_EXTWPTR(%a6),(EXC_PC-0x4,%a6,%d0)
2789 mov.w &0x2024,(EXC_VOFF-0x4,%a6,%d0)
2790 mov.l EXC_PC(%a6),(EXC_VOFF+0x2-0x4,%a6,%d0)
2791
2792 lea (EXC_SR-0x4,%a6,%d0),%a0
2793 mov.l %a0,EXC_SR(%a6)
2794
2795 fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1
2796 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2797 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2798
2799 unlk %a6
2800 mov.l (%sp)+,%sp
2801 bra.l _real_trace
2802
2803# right now, d1 = size and d0 = the strg.
2804iea_fmovm_data_predec:
2805 mov.b %d1,EXC_VOFF(%a6) # store strg
2806 mov.b %d0,0x1+EXC_VOFF(%a6) # store size
2807
2808 fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1
2809 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2810 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2811
2812 mov.l (%a6),-(%sp) # make a copy of a6
2813 mov.l %d0,-(%sp) # save d0
2814 mov.l %d1,-(%sp) # save d1
2815 mov.l EXC_EXTWPTR(%a6),-(%sp) # make a copy of Next PC
2816
2817 clr.l %d0
2818 mov.b 0x1+EXC_VOFF(%a6),%d0 # fetch size
2819 neg.l %d0 # get negative of size
2820
2821 btst &0x7,EXC_SR(%a6) # is trace enabled?
2822 beq.b iea_fmovm_data_p2
2823
2824 mov.w EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0)
2825 mov.l EXC_PC(%a6),(EXC_VOFF-0x2,%a6,%d0)
2826 mov.l (%sp)+,(EXC_PC-0x4,%a6,%d0)
2827 mov.w &0x2024,(EXC_VOFF-0x4,%a6,%d0)
2828
2829 pea (%a6,%d0) # create final sp
2830 bra.b iea_fmovm_data_p3
2831
2832iea_fmovm_data_p2:
2833 mov.w EXC_SR(%a6),(EXC_SR,%a6,%d0)
2834 mov.l (%sp)+,(EXC_PC,%a6,%d0)
2835 mov.w &0x00f0,(EXC_VOFF,%a6,%d0)
2836
2837 pea (0x4,%a6,%d0) # create final sp
2838
2839iea_fmovm_data_p3:
2840 clr.l %d1
2841 mov.b EXC_VOFF(%a6),%d1 # fetch strg
2842
2843 tst.b %d1
2844 bpl.b fm_1
2845 fmovm.x &0x80,(0x4+0x8,%a6,%d0)
2846 addi.l &0xc,%d0
2847fm_1:
2848 lsl.b &0x1,%d1
2849 bpl.b fm_2
2850 fmovm.x &0x40,(0x4+0x8,%a6,%d0)
2851 addi.l &0xc,%d0
2852fm_2:
2853 lsl.b &0x1,%d1
2854 bpl.b fm_3
2855 fmovm.x &0x20,(0x4+0x8,%a6,%d0)
2856 addi.l &0xc,%d0
2857fm_3:
2858 lsl.b &0x1,%d1
2859 bpl.b fm_4
2860 fmovm.x &0x10,(0x4+0x8,%a6,%d0)
2861 addi.l &0xc,%d0
2862fm_4:
2863 lsl.b &0x1,%d1
2864 bpl.b fm_5
2865 fmovm.x &0x08,(0x4+0x8,%a6,%d0)
2866 addi.l &0xc,%d0
2867fm_5:
2868 lsl.b &0x1,%d1
2869 bpl.b fm_6
2870 fmovm.x &0x04,(0x4+0x8,%a6,%d0)
2871 addi.l &0xc,%d0
2872fm_6:
2873 lsl.b &0x1,%d1
2874 bpl.b fm_7
2875 fmovm.x &0x02,(0x4+0x8,%a6,%d0)
2876 addi.l &0xc,%d0
2877fm_7:
2878 lsl.b &0x1,%d1
2879 bpl.b fm_end
2880 fmovm.x &0x01,(0x4+0x8,%a6,%d0)
2881fm_end:
2882 mov.l 0x4(%sp),%d1
2883 mov.l 0x8(%sp),%d0
2884 mov.l 0xc(%sp),%a6
2885 mov.l (%sp)+,%sp
2886
2887 btst &0x7,(%sp) # is trace enabled?
2888 beq.l _fpsp_done
2889 bra.l _real_trace
2890
2891#########################################################################
2892iea_fmovm_ctrl:
2893
2894 bsr.l fmovm_ctrl # load ctrl regs
2895
2896iea_fmovm_exit:
2897 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
2898 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
2899 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2900
2901 btst &0x7,EXC_SR(%a6) # is trace on?
2902 bne.b iea_fmovm_trace # yes
2903
2904 mov.l EXC_EXTWPTR(%a6),EXC_PC(%a6) # set Next PC
2905
2906 unlk %a6 # unravel the frame
2907
2908 bra.l _fpsp_done # exit to os
2909
2910#
2911# The control reg instruction that took an "Unimplemented Effective Address"
2912# exception was being traced. The "Current PC" for the trace frame is the
2913# PC stacked for Unimp EA. The "Next PC" is in EXC_EXTWPTR.
2914# After fixing the stack frame, jump to _real_trace().
2915#
2916# UNIMP EA FRAME TRACE FRAME
2917# ***************** *****************
2918# * 0x0 * 0x0f0 * * Current *
2919# ***************** * PC *
2920# * Current * *****************
2921# * PC * * 0x2 * 0x024 *
2922# ***************** *****************
2923# * SR * * Next *
2924# ***************** * PC *
2925# *****************
2926# * SR *
2927# *****************
2928# this ain't a pretty solution, but it works:
2929# -restore a6 (not with unlk)
2930# -shift stack frame down over where old a6 used to be
2931# -add LOCAL_SIZE to stack pointer
2932iea_fmovm_trace:
2933 mov.l (%a6),%a6 # restore frame pointer
2934 mov.w EXC_SR+LOCAL_SIZE(%sp),0x0+LOCAL_SIZE(%sp)
2935 mov.l EXC_PC+LOCAL_SIZE(%sp),0x8+LOCAL_SIZE(%sp)
2936 mov.l EXC_EXTWPTR+LOCAL_SIZE(%sp),0x2+LOCAL_SIZE(%sp)
2937 mov.w &0x2024,0x6+LOCAL_SIZE(%sp) # stk fmt = 0x2; voff = 0x024
2938 add.l &LOCAL_SIZE,%sp # clear stack frame
2939
2940 bra.l _real_trace
2941
2942#########################################################################
2943# The FPU is disabled and so we should really have taken the "Line
2944# F Emulator" exception. So, here we create an 8-word stack frame
2945# from our 4-word stack frame. This means we must calculate the length
2946# the faulting instruction to get the "next PC". This is trivial for
2947# immediate operands but requires some extra work for fmovm dynamic
2948# which can use most addressing modes.
2949iea_disabled:
2950 mov.l (%sp)+,%d0 # restore d0
2951
2952 link %a6,&-LOCAL_SIZE # init stack frame
2953
2954 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
2955
2956# PC of instruction that took the exception is the PC in the frame
2957 mov.l EXC_PC(%a6),EXC_EXTWPTR(%a6)
2958 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
2959 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
2960 bsr.l _imem_read_long # fetch the instruction words
2961 mov.l %d0,EXC_OPWORD(%a6) # store OPWORD and EXTWORD
2962
2963 tst.w %d0 # is instr fmovm?
2964 bmi.b iea_dis_fmovm # yes
2965# instruction is using an extended precision immediate operand. therefore,
2966# the total instruction length is 16 bytes.
2967iea_dis_immed:
2968 mov.l &0x10,%d0 # 16 bytes of instruction
2969 bra.b iea_dis_cont
2970iea_dis_fmovm:
2971 btst &0xe,%d0 # is instr fmovm ctrl
2972 bne.b iea_dis_fmovm_data # no
2973# the instruction is a fmovm.l with 2 or 3 registers.
2974 bfextu %d0{&19:&3},%d1
2975 mov.l &0xc,%d0
2976 cmpi.b %d1,&0x7 # move all regs?
2977 bne.b iea_dis_cont
2978 addq.l &0x4,%d0
2979 bra.b iea_dis_cont
2980# the instruction is an fmovm.x dynamic which can use many addressing
2981# modes and thus can have several different total instruction lengths.
2982# call fmovm_calc_ea which will go through the ea calc process and,
2983# as a by-product, will tell us how long the instruction is.
2984iea_dis_fmovm_data:
2985 clr.l %d0
2986 bsr.l fmovm_calc_ea
2987 mov.l EXC_EXTWPTR(%a6),%d0
2988 sub.l EXC_PC(%a6),%d0
2989iea_dis_cont:
2990 mov.w %d0,EXC_VOFF(%a6) # store stack shift value
2991
2992 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
2993
2994 unlk %a6
2995
2996# here, we actually create the 8-word frame from the 4-word frame,
2997# with the "next PC" as additional info.
2998# the <ea> field is let as undefined.
2999 subq.l &0x8,%sp # make room for new stack
3000 mov.l %d0,-(%sp) # save d0
3001 mov.w 0xc(%sp),0x4(%sp) # move SR
3002 mov.l 0xe(%sp),0x6(%sp) # move Current PC
3003 clr.l %d0
3004 mov.w 0x12(%sp),%d0
3005 mov.l 0x6(%sp),0x10(%sp) # move Current PC
3006 add.l %d0,0x6(%sp) # make Next PC
3007 mov.w &0x402c,0xa(%sp) # insert offset,frame format
3008 mov.l (%sp)+,%d0 # restore d0
3009
3010 bra.l _real_fpu_disabled
3011
3012##########
3013
3014iea_iacc:
3015 movc %pcr,%d0
3016 btst &0x1,%d0
3017 bne.b iea_iacc_cont
3018 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3019 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 on stack
3020iea_iacc_cont:
3021 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
3022
3023 unlk %a6
3024
3025 subq.w &0x8,%sp # make stack frame bigger
3026 mov.l 0x8(%sp),(%sp) # store SR,hi(PC)
3027 mov.w 0xc(%sp),0x4(%sp) # store lo(PC)
3028 mov.w &0x4008,0x6(%sp) # store voff
3029 mov.l 0x2(%sp),0x8(%sp) # store ea
3030 mov.l &0x09428001,0xc(%sp) # store fslw
3031
3032iea_acc_done:
3033 btst &0x5,(%sp) # user or supervisor mode?
3034 beq.b iea_acc_done2 # user
3035 bset &0x2,0xd(%sp) # set supervisor TM bit
3036
3037iea_acc_done2:
3038 bra.l _real_access
3039
3040iea_dacc:
3041 lea -LOCAL_SIZE(%a6),%sp
3042
3043 movc %pcr,%d1
3044 btst &0x1,%d1
3045 bne.b iea_dacc_cont
3046 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 on stack
3047 fmovm.l LOCAL_SIZE+USER_FPCR(%sp),%fpcr,%fpsr,%fpiar # restore ctrl regs
3048iea_dacc_cont:
3049 mov.l (%a6),%a6
3050
3051 mov.l 0x4+LOCAL_SIZE(%sp),-0x8+0x4+LOCAL_SIZE(%sp)
3052 mov.w 0x8+LOCAL_SIZE(%sp),-0x8+0x8+LOCAL_SIZE(%sp)
3053 mov.w &0x4008,-0x8+0xa+LOCAL_SIZE(%sp)
3054 mov.l %a0,-0x8+0xc+LOCAL_SIZE(%sp)
3055 mov.w %d0,-0x8+0x10+LOCAL_SIZE(%sp)
3056 mov.w &0x0001,-0x8+0x12+LOCAL_SIZE(%sp)
3057
3058 movm.l LOCAL_SIZE+EXC_DREGS(%sp),&0x0303 # restore d0-d1/a0-a1
3059 add.w &LOCAL_SIZE-0x4,%sp
3060
3061 bra.b iea_acc_done
3062
3063#########################################################################
3064# XDEF **************************************************************** #
3065# _fpsp_operr(): 060FPSP entry point for FP Operr exception. #
3066# #
3067# This handler should be the first code executed upon taking the #
3068# FP Operand Error exception in an operating system. #
3069# #
3070# XREF **************************************************************** #
3071# _imem_read_long() - read instruction longword #
3072# fix_skewed_ops() - adjust src operand in fsave frame #
3073# _real_operr() - "callout" to operating system operr handler #
3074# _dmem_write_{byte,word,long}() - store data to mem (opclass 3) #
3075# store_dreg_{b,w,l}() - store data to data regfile (opclass 3) #
3076# facc_out_{b,w,l}() - store to memory took access error (opcl 3) #
3077# #
3078# INPUT *************************************************************** #
3079# - The system stack contains the FP Operr exception frame #
3080# - The fsave frame contains the source operand #
3081# #
3082# OUTPUT ************************************************************** #
3083# No access error: #
3084# - The system stack is unchanged #
3085# - The fsave frame contains the adjusted src op for opclass 0,2 #
3086# #
3087# ALGORITHM *********************************************************** #
3088# In a system where the FP Operr exception is enabled, the goal #
3089# is to get to the handler specified at _real_operr(). But, on the 060, #
3090# for opclass zero and two instruction taking this exception, the #
3091# input operand in the fsave frame may be incorrect for some cases #
3092# and needs to be corrected. This handler calls fix_skewed_ops() to #
3093# do just this and then exits through _real_operr(). #
3094# For opclass 3 instructions, the 060 doesn't store the default #
3095# operr result out to memory or data register file as it should. #
3096# This code must emulate the move out before finally exiting through #
3097# _real_inex(). The move out, if to memory, is performed using #
3098# _mem_write() "callout" routines that may return a failing result. #
3099# In this special case, the handler must exit through facc_out() #
3100# which creates an access error stack frame from the current operr #
3101# stack frame. #
3102# #
3103#########################################################################
3104
3105 global _fpsp_operr
3106_fpsp_operr:
3107
3108 link.w %a6,&-LOCAL_SIZE # init stack frame
3109
3110 fsave FP_SRC(%a6) # grab the "busy" frame
3111
3112 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
3113 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3114 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack
3115
3116# the FPIAR holds the "current PC" of the faulting instruction
3117 mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3118
3119 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
3120 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
3121 bsr.l _imem_read_long # fetch the instruction words
3122 mov.l %d0,EXC_OPWORD(%a6)
3123
3124##############################################################################
3125
3126 btst &13,%d0 # is instr an fmove out?
3127 bne.b foperr_out # fmove out
3128
3129
3130# here, we simply see if the operand in the fsave frame needs to be "unskewed".
3131# this would be the case for opclass two operations with a source infinity or
3132# denorm operand in the sgl or dbl format. NANs also become skewed, but can't
3133# cause an operr so we don't need to check for them here.
3134 lea FP_SRC(%a6),%a0 # pass: ptr to src op
3135 bsr.l fix_skewed_ops # fix src op
3136
3137foperr_exit:
3138 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
3139 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3140 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
3141
3142 frestore FP_SRC(%a6)
3143
3144 unlk %a6
3145 bra.l _real_operr
3146
3147########################################################################
3148
3149#
3150# the hardware does not save the default result to memory on enabled
3151# operand error exceptions. we do this here before passing control to
3152# the user operand error handler.
3153#
3154# byte, word, and long destination format operations can pass
3155# through here. we simply need to test the sign of the src
3156# operand and save the appropriate minimum or maximum integer value
3157# to the effective address as pointed to by the stacked effective address.
3158#
3159# although packed opclass three operations can take operand error
3160# exceptions, they won't pass through here since they are caught
3161# first by the unsupported data format exception handler. that handler
3162# sends them directly to _real_operr() if necessary.
3163#
3164foperr_out:
3165
3166 mov.w FP_SRC_EX(%a6),%d1 # fetch exponent
3167 andi.w &0x7fff,%d1
3168 cmpi.w %d1,&0x7fff
3169 bne.b foperr_out_not_qnan
3170# the operand is either an infinity or a QNAN.
3171 tst.l FP_SRC_LO(%a6)
3172 bne.b foperr_out_qnan
3173 mov.l FP_SRC_HI(%a6),%d1
3174 andi.l &0x7fffffff,%d1
3175 beq.b foperr_out_not_qnan
3176foperr_out_qnan:
3177 mov.l FP_SRC_HI(%a6),L_SCR1(%a6)
3178 bra.b foperr_out_jmp
3179
3180foperr_out_not_qnan:
3181 mov.l &0x7fffffff,%d1
3182 tst.b FP_SRC_EX(%a6)
3183 bpl.b foperr_out_not_qnan2
3184 addq.l &0x1,%d1
3185foperr_out_not_qnan2:
3186 mov.l %d1,L_SCR1(%a6)
3187
3188foperr_out_jmp:
3189 bfextu %d0{&19:&3},%d0 # extract dst format field
3190 mov.b 1+EXC_OPWORD(%a6),%d1 # extract <ea> mode,reg
3191 mov.w (tbl_operr.b,%pc,%d0.w*2),%a0
3192 jmp (tbl_operr.b,%pc,%a0)
3193
3194tbl_operr:
3195 short foperr_out_l - tbl_operr # long word integer
3196 short tbl_operr - tbl_operr # sgl prec shouldn't happen
3197 short tbl_operr - tbl_operr # ext prec shouldn't happen
3198 short foperr_exit - tbl_operr # packed won't enter here
3199 short foperr_out_w - tbl_operr # word integer
3200 short tbl_operr - tbl_operr # dbl prec shouldn't happen
3201 short foperr_out_b - tbl_operr # byte integer
3202 short tbl_operr - tbl_operr # packed won't enter here
3203
3204foperr_out_b:
3205 mov.b L_SCR1(%a6),%d0 # load positive default result
3206 cmpi.b %d1,&0x7 # is <ea> mode a data reg?
3207 ble.b foperr_out_b_save_dn # yes
3208 mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result
3209 bsr.l _dmem_write_byte # write the default result
3210
3211 tst.l %d1 # did dstore fail?
3212 bne.l facc_out_b # yes
3213
3214 bra.w foperr_exit
3215foperr_out_b_save_dn:
3216 andi.w &0x0007,%d1
3217 bsr.l store_dreg_b # store result to regfile
3218 bra.w foperr_exit
3219
3220foperr_out_w:
3221 mov.w L_SCR1(%a6),%d0 # load positive default result
3222 cmpi.b %d1,&0x7 # is <ea> mode a data reg?
3223 ble.b foperr_out_w_save_dn # yes
3224 mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result
3225 bsr.l _dmem_write_word # write the default result
3226
3227 tst.l %d1 # did dstore fail?
3228 bne.l facc_out_w # yes
3229
3230 bra.w foperr_exit
3231foperr_out_w_save_dn:
3232 andi.w &0x0007,%d1
3233 bsr.l store_dreg_w # store result to regfile
3234 bra.w foperr_exit
3235
3236foperr_out_l:
3237 mov.l L_SCR1(%a6),%d0 # load positive default result
3238 cmpi.b %d1,&0x7 # is <ea> mode a data reg?
3239 ble.b foperr_out_l_save_dn # yes
3240 mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result
3241 bsr.l _dmem_write_long # write the default result
3242
3243 tst.l %d1 # did dstore fail?
3244 bne.l facc_out_l # yes
3245
3246 bra.w foperr_exit
3247foperr_out_l_save_dn:
3248 andi.w &0x0007,%d1
3249 bsr.l store_dreg_l # store result to regfile
3250 bra.w foperr_exit
3251
3252#########################################################################
3253# XDEF **************************************************************** #
3254# _fpsp_snan(): 060FPSP entry point for FP SNAN exception. #
3255# #
3256# This handler should be the first code executed upon taking the #
3257# FP Signalling NAN exception in an operating system. #
3258# #
3259# XREF **************************************************************** #
3260# _imem_read_long() - read instruction longword #
3261# fix_skewed_ops() - adjust src operand in fsave frame #
3262# _real_snan() - "callout" to operating system SNAN handler #
3263# _dmem_write_{byte,word,long}() - store data to mem (opclass 3) #
3264# store_dreg_{b,w,l}() - store data to data regfile (opclass 3) #
3265# facc_out_{b,w,l,d,x}() - store to mem took acc error (opcl 3) #
3266# _calc_ea_fout() - fix An if <ea> is -() or ()+; also get <ea> #
3267# #
3268# INPUT *************************************************************** #
3269# - The system stack contains the FP SNAN exception frame #
3270# - The fsave frame contains the source operand #
3271# #
3272# OUTPUT ************************************************************** #
3273# No access error: #
3274# - The system stack is unchanged #
3275# - The fsave frame contains the adjusted src op for opclass 0,2 #
3276# #
3277# ALGORITHM *********************************************************** #
3278# In a system where the FP SNAN exception is enabled, the goal #
3279# is to get to the handler specified at _real_snan(). But, on the 060, #
3280# for opclass zero and two instructions taking this exception, the #
3281# input operand in the fsave frame may be incorrect for some cases #
3282# and needs to be corrected. This handler calls fix_skewed_ops() to #
3283# do just this and then exits through _real_snan(). #
3284# For opclass 3 instructions, the 060 doesn't store the default #
3285# SNAN result out to memory or data register file as it should. #
3286# This code must emulate the move out before finally exiting through #
3287# _real_snan(). The move out, if to memory, is performed using #
3288# _mem_write() "callout" routines that may return a failing result. #
3289# In this special case, the handler must exit through facc_out() #
3290# which creates an access error stack frame from the current SNAN #
3291# stack frame. #
3292# For the case of an extended precision opclass 3 instruction, #
3293# if the effective addressing mode was -() or ()+, then the address #
3294# register must get updated by calling _calc_ea_fout(). If the <ea> #
3295# was -(a7) from supervisor mode, then the exception frame currently #
3296# on the system stack must be carefully moved "down" to make room #
3297# for the operand being moved. #
3298# #
3299#########################################################################
3300
3301 global _fpsp_snan
3302_fpsp_snan:
3303
3304 link.w %a6,&-LOCAL_SIZE # init stack frame
3305
3306 fsave FP_SRC(%a6) # grab the "busy" frame
3307
3308 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
3309 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3310 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack
3311
3312# the FPIAR holds the "current PC" of the faulting instruction
3313 mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3314
3315 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
3316 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
3317 bsr.l _imem_read_long # fetch the instruction words
3318 mov.l %d0,EXC_OPWORD(%a6)
3319
3320##############################################################################
3321
3322 btst &13,%d0 # is instr an fmove out?
3323 bne.w fsnan_out # fmove out
3324
3325
3326# here, we simply see if the operand in the fsave frame needs to be "unskewed".
3327# this would be the case for opclass two operations with a source infinity or
3328# denorm operand in the sgl or dbl format. NANs also become skewed and must be
3329# fixed here.
3330 lea FP_SRC(%a6),%a0 # pass: ptr to src op
3331 bsr.l fix_skewed_ops # fix src op
3332
3333fsnan_exit:
3334 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
3335 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3336 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
3337
3338 frestore FP_SRC(%a6)
3339
3340 unlk %a6
3341 bra.l _real_snan
3342
3343########################################################################
3344
3345#
3346# the hardware does not save the default result to memory on enabled
3347# snan exceptions. we do this here before passing control to
3348# the user snan handler.
3349#
3350# byte, word, long, and packed destination format operations can pass
3351# through here. since packed format operations already were handled by
3352# fpsp_unsupp(), then we need to do nothing else for them here.
3353# for byte, word, and long, we simply need to test the sign of the src
3354# operand and save the appropriate minimum or maximum integer value
3355# to the effective address as pointed to by the stacked effective address.
3356#
3357fsnan_out:
3358
3359 bfextu %d0{&19:&3},%d0 # extract dst format field
3360 mov.b 1+EXC_OPWORD(%a6),%d1 # extract <ea> mode,reg
3361 mov.w (tbl_snan.b,%pc,%d0.w*2),%a0
3362 jmp (tbl_snan.b,%pc,%a0)
3363
3364tbl_snan:
3365 short fsnan_out_l - tbl_snan # long word integer
3366 short fsnan_out_s - tbl_snan # sgl prec shouldn't happen
3367 short fsnan_out_x - tbl_snan # ext prec shouldn't happen
3368 short tbl_snan - tbl_snan # packed needs no help
3369 short fsnan_out_w - tbl_snan # word integer
3370 short fsnan_out_d - tbl_snan # dbl prec shouldn't happen
3371 short fsnan_out_b - tbl_snan # byte integer
3372 short tbl_snan - tbl_snan # packed needs no help
3373
3374fsnan_out_b:
3375 mov.b FP_SRC_HI(%a6),%d0 # load upper byte of SNAN
3376 bset &6,%d0 # set SNAN bit
3377 cmpi.b %d1,&0x7 # is <ea> mode a data reg?
3378 ble.b fsnan_out_b_dn # yes
3379 mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result
3380 bsr.l _dmem_write_byte # write the default result
3381
3382 tst.l %d1 # did dstore fail?
3383 bne.l facc_out_b # yes
3384
3385 bra.w fsnan_exit
3386fsnan_out_b_dn:
3387 andi.w &0x0007,%d1
3388 bsr.l store_dreg_b # store result to regfile
3389 bra.w fsnan_exit
3390
3391fsnan_out_w:
3392 mov.w FP_SRC_HI(%a6),%d0 # load upper word of SNAN
3393 bset &14,%d0 # set SNAN bit
3394 cmpi.b %d1,&0x7 # is <ea> mode a data reg?
3395 ble.b fsnan_out_w_dn # yes
3396 mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result
3397 bsr.l _dmem_write_word # write the default result
3398
3399 tst.l %d1 # did dstore fail?
3400 bne.l facc_out_w # yes
3401
3402 bra.w fsnan_exit
3403fsnan_out_w_dn:
3404 andi.w &0x0007,%d1
3405 bsr.l store_dreg_w # store result to regfile
3406 bra.w fsnan_exit
3407
3408fsnan_out_l:
3409 mov.l FP_SRC_HI(%a6),%d0 # load upper longword of SNAN
3410 bset &30,%d0 # set SNAN bit
3411 cmpi.b %d1,&0x7 # is <ea> mode a data reg?
3412 ble.b fsnan_out_l_dn # yes
3413 mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result
3414 bsr.l _dmem_write_long # write the default result
3415
3416 tst.l %d1 # did dstore fail?
3417 bne.l facc_out_l # yes
3418
3419 bra.w fsnan_exit
3420fsnan_out_l_dn:
3421 andi.w &0x0007,%d1
3422 bsr.l store_dreg_l # store result to regfile
3423 bra.w fsnan_exit
3424
3425fsnan_out_s:
3426 cmpi.b %d1,&0x7 # is <ea> mode a data reg?
3427 ble.b fsnan_out_d_dn # yes
3428 mov.l FP_SRC_EX(%a6),%d0 # fetch SNAN sign
3429 andi.l &0x80000000,%d0 # keep sign
3430 ori.l &0x7fc00000,%d0 # insert new exponent,SNAN bit
3431 mov.l FP_SRC_HI(%a6),%d1 # load mantissa
3432 lsr.l &0x8,%d1 # shift mantissa for sgl
3433 or.l %d1,%d0 # create sgl SNAN
3434 mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result
3435 bsr.l _dmem_write_long # write the default result
3436
3437 tst.l %d1 # did dstore fail?
3438 bne.l facc_out_l # yes
3439
3440 bra.w fsnan_exit
3441fsnan_out_d_dn:
3442 mov.l FP_SRC_EX(%a6),%d0 # fetch SNAN sign
3443 andi.l &0x80000000,%d0 # keep sign
3444 ori.l &0x7fc00000,%d0 # insert new exponent,SNAN bit
3445 mov.l %d1,-(%sp)
3446 mov.l FP_SRC_HI(%a6),%d1 # load mantissa
3447 lsr.l &0x8,%d1 # shift mantissa for sgl
3448 or.l %d1,%d0 # create sgl SNAN
3449 mov.l (%sp)+,%d1
3450 andi.w &0x0007,%d1
3451 bsr.l store_dreg_l # store result to regfile
3452 bra.w fsnan_exit
3453
3454fsnan_out_d:
3455 mov.l FP_SRC_EX(%a6),%d0 # fetch SNAN sign
3456 andi.l &0x80000000,%d0 # keep sign
3457 ori.l &0x7ff80000,%d0 # insert new exponent,SNAN bit
3458 mov.l FP_SRC_HI(%a6),%d1 # load hi mantissa
3459 mov.l %d0,FP_SCR0_EX(%a6) # store to temp space
3460 mov.l &11,%d0 # load shift amt
3461 lsr.l %d0,%d1
3462 or.l %d1,FP_SCR0_EX(%a6) # create dbl hi
3463 mov.l FP_SRC_HI(%a6),%d1 # load hi mantissa
3464 andi.l &0x000007ff,%d1
3465 ror.l %d0,%d1
3466 mov.l %d1,FP_SCR0_HI(%a6) # store to temp space
3467 mov.l FP_SRC_LO(%a6),%d1 # load lo mantissa
3468 lsr.l %d0,%d1
3469 or.l %d1,FP_SCR0_HI(%a6) # create dbl lo
3470 lea FP_SCR0(%a6),%a0 # pass: ptr to operand
3471 mov.l EXC_EA(%a6),%a1 # pass: dst addr
3472 movq.l &0x8,%d0 # pass: size of 8 bytes
3473 bsr.l _dmem_write # write the default result
3474
3475 tst.l %d1 # did dstore fail?
3476 bne.l facc_out_d # yes
3477
3478 bra.w fsnan_exit
3479
3480# for extended precision, if the addressing mode is pre-decrement or
3481# post-increment, then the address register did not get updated.
3482# in addition, for pre-decrement, the stacked <ea> is incorrect.
3483fsnan_out_x:
3484 clr.b SPCOND_FLG(%a6) # clear special case flag
3485
3486 mov.w FP_SRC_EX(%a6),FP_SCR0_EX(%a6)
3487 clr.w 2+FP_SCR0(%a6)
3488 mov.l FP_SRC_HI(%a6),%d0
3489 bset &30,%d0
3490 mov.l %d0,FP_SCR0_HI(%a6)
3491 mov.l FP_SRC_LO(%a6),FP_SCR0_LO(%a6)
3492
3493 btst &0x5,EXC_SR(%a6) # supervisor mode exception?
3494 bne.b fsnan_out_x_s # yes
3495
3496 mov.l %usp,%a0 # fetch user stack pointer
3497 mov.l %a0,EXC_A7(%a6) # save on stack for calc_ea()
3498 mov.l (%a6),EXC_A6(%a6)
3499
3500 bsr.l _calc_ea_fout # find the correct ea,update An
3501 mov.l %a0,%a1
3502 mov.l %a0,EXC_EA(%a6) # stack correct <ea>
3503
3504 mov.l EXC_A7(%a6),%a0
3505 mov.l %a0,%usp # restore user stack pointer
3506 mov.l EXC_A6(%a6),(%a6)
3507
3508fsnan_out_x_save:
3509 lea FP_SCR0(%a6),%a0 # pass: ptr to operand
3510 movq.l &0xc,%d0 # pass: size of extended
3511 bsr.l _dmem_write # write the default result
3512
3513 tst.l %d1 # did dstore fail?
3514 bne.l facc_out_x # yes
3515
3516 bra.w fsnan_exit
3517
3518fsnan_out_x_s:
3519 mov.l (%a6),EXC_A6(%a6)
3520
3521 bsr.l _calc_ea_fout # find the correct ea,update An
3522 mov.l %a0,%a1
3523 mov.l %a0,EXC_EA(%a6) # stack correct <ea>
3524
3525 mov.l EXC_A6(%a6),(%a6)
3526
3527 cmpi.b SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)?
3528 bne.b fsnan_out_x_save # no
3529
3530# the operation was "fmove.x SNAN,-(a7)" from supervisor mode.
3531 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
3532 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3533 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
3534
3535 frestore FP_SRC(%a6)
3536
3537 mov.l EXC_A6(%a6),%a6 # restore frame pointer
3538
3539 mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
3540 mov.l LOCAL_SIZE+EXC_PC+0x2(%sp),LOCAL_SIZE+EXC_PC+0x2-0xc(%sp)
3541 mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
3542
3543 mov.l LOCAL_SIZE+FP_SCR0_EX(%sp),LOCAL_SIZE+EXC_SR(%sp)
3544 mov.l LOCAL_SIZE+FP_SCR0_HI(%sp),LOCAL_SIZE+EXC_PC+0x2(%sp)
3545 mov.l LOCAL_SIZE+FP_SCR0_LO(%sp),LOCAL_SIZE+EXC_EA(%sp)
3546
3547 add.l &LOCAL_SIZE-0x8,%sp
3548
3549 bra.l _real_snan
3550
3551#########################################################################
3552# XDEF **************************************************************** #
3553# _fpsp_inex(): 060FPSP entry point for FP Inexact exception. #
3554# #
3555# This handler should be the first code executed upon taking the #
3556# FP Inexact exception in an operating system. #
3557# #
3558# XREF **************************************************************** #
3559# _imem_read_long() - read instruction longword #
3560# fix_skewed_ops() - adjust src operand in fsave frame #
3561# set_tag_x() - determine optype of src/dst operands #
3562# store_fpreg() - store opclass 0 or 2 result to FP regfile #
3563# unnorm_fix() - change UNNORM operands to NORM or ZERO #
3564# load_fpn2() - load dst operand from FP regfile #
3565# smovcr() - emulate an "fmovcr" instruction #
3566# fout() - emulate an opclass 3 instruction #
3567# tbl_unsupp - add of table of emulation routines for opclass 0,2 #
3568# _real_inex() - "callout" to operating system inexact handler #
3569# #
3570# INPUT *************************************************************** #
3571# - The system stack contains the FP Inexact exception frame #
3572# - The fsave frame contains the source operand #
3573# #
3574# OUTPUT ************************************************************** #
3575# - The system stack is unchanged #
3576# - The fsave frame contains the adjusted src op for opclass 0,2 #
3577# #
3578# ALGORITHM *********************************************************** #
3579# In a system where the FP Inexact exception is enabled, the goal #
3580# is to get to the handler specified at _real_inex(). But, on the 060, #
3581# for opclass zero and two instruction taking this exception, the #
3582# hardware doesn't store the correct result to the destination FP #
3583# register as did the '040 and '881/2. This handler must emulate the #
3584# instruction in order to get this value and then store it to the #
3585# correct register before calling _real_inex(). #
3586# For opclass 3 instructions, the 060 doesn't store the default #
3587# inexact result out to memory or data register file as it should. #
3588# This code must emulate the move out by calling fout() before finally #
3589# exiting through _real_inex(). #
3590# #
3591#########################################################################
3592
3593 global _fpsp_inex
3594_fpsp_inex:
3595
3596 link.w %a6,&-LOCAL_SIZE # init stack frame
3597
3598 fsave FP_SRC(%a6) # grab the "busy" frame
3599
3600 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
3601 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3602 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack
3603
3604# the FPIAR holds the "current PC" of the faulting instruction
3605 mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3606
3607 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
3608 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
3609 bsr.l _imem_read_long # fetch the instruction words
3610 mov.l %d0,EXC_OPWORD(%a6)
3611
3612##############################################################################
3613
3614 btst &13,%d0 # is instr an fmove out?
3615 bne.w finex_out # fmove out
3616
3617
3618# the hardware, for "fabs" and "fneg" w/ a long source format, puts the
3619# longword integer directly into the upper longword of the mantissa along
3620# w/ an exponent value of 0x401e. we convert this to extended precision here.
3621 bfextu %d0{&19:&3},%d0 # fetch instr size
3622 bne.b finex_cont # instr size is not long
3623 cmpi.w FP_SRC_EX(%a6),&0x401e # is exponent 0x401e?
3624 bne.b finex_cont # no
3625 fmov.l &0x0,%fpcr
3626 fmov.l FP_SRC_HI(%a6),%fp0 # load integer src
3627 fmov.x %fp0,FP_SRC(%a6) # store integer as extended precision
3628 mov.w &0xe001,0x2+FP_SRC(%a6)
3629
3630finex_cont:
3631 lea FP_SRC(%a6),%a0 # pass: ptr to src op
3632 bsr.l fix_skewed_ops # fix src op
3633
3634# Here, we zero the ccode and exception byte field since we're going to
3635# emulate the whole instruction. Notice, though, that we don't kill the
3636# INEX1 bit. This is because a packed op has long since been converted
3637# to extended before arriving here. Therefore, we need to retain the
3638# INEX1 bit from when the operand was first converted.
3639 andi.l &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field
3640
3641 fmov.l &0x0,%fpcr # zero current control regs
3642 fmov.l &0x0,%fpsr
3643
3644 bfextu EXC_EXTWORD(%a6){&0:&6},%d1 # extract upper 6 of cmdreg
3645 cmpi.b %d1,&0x17 # is op an fmovecr?
3646 beq.w finex_fmovcr # yes
3647
3648 lea FP_SRC(%a6),%a0 # pass: ptr to src op
3649 bsr.l set_tag_x # tag the operand type
3650 mov.b %d0,STAG(%a6) # maybe NORM,DENORM
3651
3652# bits four and five of the fp extension word separate the monadic and dyadic
3653# operations that can pass through fpsp_inex(). remember that fcmp and ftst
3654# will never take this exception, but fsincos will.
3655 btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic?
3656 beq.b finex_extract # monadic
3657
3658 btst &0x4,1+EXC_CMDREG(%a6) # is operation an fsincos?
3659 bne.b finex_extract # yes
3660
3661 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
3662 bsr.l load_fpn2 # load dst into FP_DST
3663
3664 lea FP_DST(%a6),%a0 # pass: ptr to dst op
3665 bsr.l set_tag_x # tag the operand type
3666 cmpi.b %d0,&UNNORM # is operand an UNNORM?
3667 bne.b finex_op2_done # no
3668 bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO
3669finex_op2_done:
3670 mov.b %d0,DTAG(%a6) # save dst optype tag
3671
3672finex_extract:
3673 clr.l %d0
3674 mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode
3675
3676 mov.b 1+EXC_CMDREG(%a6),%d1
3677 andi.w &0x007f,%d1 # extract extension
3678
3679 lea FP_SRC(%a6),%a0
3680 lea FP_DST(%a6),%a1
3681
3682 mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
3683 jsr (tbl_unsupp.l,%pc,%d1.l*1)
3684
3685# the operation has been emulated. the result is in fp0.
3686finex_save:
3687 bfextu EXC_CMDREG(%a6){&6:&3},%d0
3688 bsr.l store_fpreg
3689
3690finex_exit:
3691 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
3692 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3693 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
3694
3695 frestore FP_SRC(%a6)
3696
3697 unlk %a6
3698 bra.l _real_inex
3699
3700finex_fmovcr:
3701 clr.l %d0
3702 mov.b FPCR_MODE(%a6),%d0 # pass rnd prec,mode
3703 mov.b 1+EXC_CMDREG(%a6),%d1
3704 andi.l &0x0000007f,%d1 # pass rom offset
3705 bsr.l smovcr
3706 bra.b finex_save
3707
3708########################################################################
3709
3710#
3711# the hardware does not save the default result to memory on enabled
3712# inexact exceptions. we do this here before passing control to
3713# the user inexact handler.
3714#
3715# byte, word, and long destination format operations can pass
3716# through here. so can double and single precision.
3717# although packed opclass three operations can take inexact
3718# exceptions, they won't pass through here since they are caught
3719# first by the unsupported data format exception handler. that handler
3720# sends them directly to _real_inex() if necessary.
3721#
3722finex_out:
3723
3724 mov.b &NORM,STAG(%a6) # src is a NORM
3725
3726 clr.l %d0
3727 mov.b FPCR_MODE(%a6),%d0 # pass rnd prec,mode
3728
3729 andi.l &0xffff00ff,USER_FPSR(%a6) # zero exception field
3730
3731 lea FP_SRC(%a6),%a0 # pass ptr to src operand
3732
3733 bsr.l fout # store the default result
3734
3735 bra.b finex_exit
3736
3737#########################################################################
3738# XDEF **************************************************************** #
3739# _fpsp_dz(): 060FPSP entry point for FP DZ exception. #
3740# #
3741# This handler should be the first code executed upon taking #
3742# the FP DZ exception in an operating system. #
3743# #
3744# XREF **************************************************************** #
3745# _imem_read_long() - read instruction longword from memory #
3746# fix_skewed_ops() - adjust fsave operand #
3747# _real_dz() - "callout" exit point from FP DZ handler #
3748# #
3749# INPUT *************************************************************** #
3750# - The system stack contains the FP DZ exception stack. #
3751# - The fsave frame contains the source operand. #
3752# #
3753# OUTPUT ************************************************************** #
3754# - The system stack contains the FP DZ exception stack. #
3755# - The fsave frame contains the adjusted source operand. #
3756# #
3757# ALGORITHM *********************************************************** #
3758# In a system where the DZ exception is enabled, the goal is to #
3759# get to the handler specified at _real_dz(). But, on the 060, when the #
3760# exception is taken, the input operand in the fsave state frame may #
3761# be incorrect for some cases and need to be adjusted. So, this package #
3762# adjusts the operand using fix_skewed_ops() and then branches to #
3763# _real_dz(). #
3764# #
3765#########################################################################
3766
3767 global _fpsp_dz
3768_fpsp_dz:
3769
3770 link.w %a6,&-LOCAL_SIZE # init stack frame
3771
3772 fsave FP_SRC(%a6) # grab the "busy" frame
3773
3774 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1
3775 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3776 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack
3777
3778# the FPIAR holds the "current PC" of the faulting instruction
3779 mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3780
3781 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
3782 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
3783 bsr.l _imem_read_long # fetch the instruction words
3784 mov.l %d0,EXC_OPWORD(%a6)
3785
3786##############################################################################
3787
3788
3789# here, we simply see if the operand in the fsave frame needs to be "unskewed".
3790# this would be the case for opclass two operations with a source zero
3791# in the sgl or dbl format.
3792 lea FP_SRC(%a6),%a0 # pass: ptr to src op
3793 bsr.l fix_skewed_ops # fix src op
3794
3795fdz_exit:
3796 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
3797 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3798 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
3799
3800 frestore FP_SRC(%a6)
3801
3802 unlk %a6
3803 bra.l _real_dz
3804
3805#########################################################################
3806# XDEF **************************************************************** #
3807# _fpsp_fline(): 060FPSP entry point for "Line F emulator" #
3808# exception when the "reduced" version of the #
3809# FPSP is implemented that does not emulate #
3810# FP unimplemented instructions. #
3811# #
3812# This handler should be the first code executed upon taking a #
3813# "Line F Emulator" exception in an operating system integrating #
3814# the reduced version of 060FPSP. #
3815# #
3816# XREF **************************************************************** #
3817# _real_fpu_disabled() - Handle "FPU disabled" exceptions #
3818# _real_fline() - Handle all other cases (treated equally) #
3819# #
3820# INPUT *************************************************************** #
3821# - The system stack contains a "Line F Emulator" exception #
3822# stack frame. #
3823# #
3824# OUTPUT ************************************************************** #
3825# - The system stack is unchanged. #
3826# #
3827# ALGORITHM *********************************************************** #
3828# When a "Line F Emulator" exception occurs in a system where #
3829# "FPU Unimplemented" instructions will not be emulated, the exception #
3830# can occur because then FPU is disabled or the instruction is to be #
3831# classifed as "Line F". This module determines which case exists and #
3832# calls the appropriate "callout". #
3833# #
3834#########################################################################
3835
3836 global _fpsp_fline
3837_fpsp_fline:
3838
3839# check to see if the FPU is disabled. if so, jump to the OS entry
3840# point for that condition.
3841 cmpi.w 0x6(%sp),&0x402c
3842 beq.l _real_fpu_disabled
3843
3844 bra.l _real_fline
3845
3846#########################################################################
3847# XDEF **************************************************************** #
3848# _dcalc_ea(): calc correct <ea> from <ea> stacked on exception #
3849# #
3850# XREF **************************************************************** #
3851# inc_areg() - increment an address register #
3852# dec_areg() - decrement an address register #
3853# #
3854# INPUT *************************************************************** #
3855# d0 = number of bytes to adjust <ea> by #
3856# #
3857# OUTPUT ************************************************************** #
3858# None #
3859# #
3860# ALGORITHM *********************************************************** #
3861# "Dummy" CALCulate Effective Address: #
3862# The stacked <ea> for FP unimplemented instructions and opclass #
3863# two packed instructions is correct with the exception of... #
3864# #
3865# 1) -(An) : The register is not updated regardless of size. #
3866# Also, for extended precision and packed, the #
3867# stacked <ea> value is 8 bytes too big #
3868# 2) (An)+ : The register is not updated. #
3869# 3) #<data> : The upper longword of the immediate operand is #
3870# stacked b,w,l and s sizes are completely stacked. #
3871# d,x, and p are not. #
3872# #
3873#########################################################################
3874
3875 global _dcalc_ea
3876_dcalc_ea:
3877 mov.l %d0, %a0 # move # bytes to %a0
3878
3879 mov.b 1+EXC_OPWORD(%a6), %d0 # fetch opcode word
3880 mov.l %d0, %d1 # make a copy
3881
3882 andi.w &0x38, %d0 # extract mode field
3883 andi.l &0x7, %d1 # extract reg field
3884
3885 cmpi.b %d0,&0x18 # is mode (An)+ ?
3886 beq.b dcea_pi # yes
3887
3888 cmpi.b %d0,&0x20 # is mode -(An) ?
3889 beq.b dcea_pd # yes
3890
3891 or.w %d1,%d0 # concat mode,reg
3892 cmpi.b %d0,&0x3c # is mode #<data>?
3893
3894 beq.b dcea_imm # yes
3895
3896 mov.l EXC_EA(%a6),%a0 # return <ea>
3897 rts
3898
3899# need to set immediate data flag here since we'll need to do
3900# an imem_read to fetch this later.
3901dcea_imm:
3902 mov.b &immed_flg,SPCOND_FLG(%a6)
3903 lea ([USER_FPIAR,%a6],0x4),%a0 # no; return <ea>
3904 rts
3905
3906# here, the <ea> is stacked correctly. however, we must update the
3907# address register...
3908dcea_pi:
3909 mov.l %a0,%d0 # pass amt to inc by
3910 bsr.l inc_areg # inc addr register
3911
3912 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
3913 rts
3914
3915# the <ea> is stacked correctly for all but extended and packed which
3916# the <ea>s are 8 bytes too large.
3917# it would make no sense to have a pre-decrement to a7 in supervisor
3918# mode so we don't even worry about this tricky case here : )
3919dcea_pd:
3920 mov.l %a0,%d0 # pass amt to dec by
3921 bsr.l dec_areg # dec addr register
3922
3923 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
3924
3925 cmpi.b %d0,&0xc # is opsize ext or packed?
3926 beq.b dcea_pd2 # yes
3927 rts
3928dcea_pd2:
3929 sub.l &0x8,%a0 # correct <ea>
3930 mov.l %a0,EXC_EA(%a6) # put correct <ea> on stack
3931 rts
3932
3933#########################################################################
3934# XDEF **************************************************************** #
3935# _calc_ea_fout(): calculate correct stacked <ea> for extended #
3936# and packed data opclass 3 operations. #
3937# #
3938# XREF **************************************************************** #
3939# None #
3940# #
3941# INPUT *************************************************************** #
3942# None #
3943# #
3944# OUTPUT ************************************************************** #
3945# a0 = return correct effective address #
3946# #
3947# ALGORITHM *********************************************************** #
3948# For opclass 3 extended and packed data operations, the <ea> #
3949# stacked for the exception is incorrect for -(an) and (an)+ addressing #
3950# modes. Also, while we're at it, the index register itself must get #
3951# updated. #
3952# So, for -(an), we must subtract 8 off of the stacked <ea> value #
3953# and return that value as the correct <ea> and store that value in An. #
3954# For (an)+, the stacked <ea> is correct but we must adjust An by +12. #
3955# #
3956#########################################################################
3957
3958# This calc_ea is currently used to retrieve the correct <ea>
3959# for fmove outs of type extended and packed.
3960 global _calc_ea_fout
3961_calc_ea_fout:
3962 mov.b 1+EXC_OPWORD(%a6),%d0 # fetch opcode word
3963 mov.l %d0,%d1 # make a copy
3964
3965 andi.w &0x38,%d0 # extract mode field
3966 andi.l &0x7,%d1 # extract reg field
3967
3968 cmpi.b %d0,&0x18 # is mode (An)+ ?
3969 beq.b ceaf_pi # yes
3970
3971 cmpi.b %d0,&0x20 # is mode -(An) ?
3972 beq.w ceaf_pd # yes
3973
3974 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
3975 rts
3976
3977# (An)+ : extended and packed fmove out
3978# : stacked <ea> is correct
3979# : "An" not updated
3980ceaf_pi:
3981 mov.w (tbl_ceaf_pi.b,%pc,%d1.w*2),%d1
3982 mov.l EXC_EA(%a6),%a0
3983 jmp (tbl_ceaf_pi.b,%pc,%d1.w*1)
3984
3985 swbeg &0x8
3986tbl_ceaf_pi:
3987 short ceaf_pi0 - tbl_ceaf_pi
3988 short ceaf_pi1 - tbl_ceaf_pi
3989 short ceaf_pi2 - tbl_ceaf_pi
3990 short ceaf_pi3 - tbl_ceaf_pi
3991 short ceaf_pi4 - tbl_ceaf_pi
3992 short ceaf_pi5 - tbl_ceaf_pi
3993 short ceaf_pi6 - tbl_ceaf_pi
3994 short ceaf_pi7 - tbl_ceaf_pi
3995
3996ceaf_pi0:
3997 addi.l &0xc,EXC_DREGS+0x8(%a6)
3998 rts
3999ceaf_pi1:
4000 addi.l &0xc,EXC_DREGS+0xc(%a6)
4001 rts
4002ceaf_pi2:
4003 add.l &0xc,%a2
4004 rts
4005ceaf_pi3:
4006 add.l &0xc,%a3
4007 rts
4008ceaf_pi4:
4009 add.l &0xc,%a4
4010 rts
4011ceaf_pi5:
4012 add.l &0xc,%a5
4013 rts
4014ceaf_pi6:
4015 addi.l &0xc,EXC_A6(%a6)
4016 rts
4017ceaf_pi7:
4018 mov.b &mia7_flg,SPCOND_FLG(%a6)
4019 addi.l &0xc,EXC_A7(%a6)
4020 rts
4021
4022# -(An) : extended and packed fmove out
4023# : stacked <ea> = actual <ea> + 8
4024# : "An" not updated
4025ceaf_pd:
4026 mov.w (tbl_ceaf_pd.b,%pc,%d1.w*2),%d1
4027 mov.l EXC_EA(%a6),%a0
4028 sub.l &0x8,%a0
4029 sub.l &0x8,EXC_EA(%a6)
4030 jmp (tbl_ceaf_pd.b,%pc,%d1.w*1)
4031
4032 swbeg &0x8
4033tbl_ceaf_pd:
4034 short ceaf_pd0 - tbl_ceaf_pd
4035 short ceaf_pd1 - tbl_ceaf_pd
4036 short ceaf_pd2 - tbl_ceaf_pd
4037 short ceaf_pd3 - tbl_ceaf_pd
4038 short ceaf_pd4 - tbl_ceaf_pd
4039 short ceaf_pd5 - tbl_ceaf_pd
4040 short ceaf_pd6 - tbl_ceaf_pd
4041 short ceaf_pd7 - tbl_ceaf_pd
4042
4043ceaf_pd0:
4044 mov.l %a0,EXC_DREGS+0x8(%a6)
4045 rts
4046ceaf_pd1:
4047 mov.l %a0,EXC_DREGS+0xc(%a6)
4048 rts
4049ceaf_pd2:
4050 mov.l %a0,%a2
4051 rts
4052ceaf_pd3:
4053 mov.l %a0,%a3
4054 rts
4055ceaf_pd4:
4056 mov.l %a0,%a4
4057 rts
4058ceaf_pd5:
4059 mov.l %a0,%a5
4060 rts
4061ceaf_pd6:
4062 mov.l %a0,EXC_A6(%a6)
4063 rts
4064ceaf_pd7:
4065 mov.l %a0,EXC_A7(%a6)
4066 mov.b &mda7_flg,SPCOND_FLG(%a6)
4067 rts
4068
4069#
4070# This table holds the offsets of the emulation routines for each individual
4071# math operation relative to the address of this table. Included are
4072# routines like fadd/fmul/fabs. The transcendentals ARE NOT. This is because
4073# this table is for the version if the 060FPSP without transcendentals.
4074# The location within the table is determined by the extension bits of the
4075# operation longword.
4076#
4077
4078 swbeg &109
4079tbl_unsupp:
4080 long fin - tbl_unsupp # 00: fmove
4081 long fint - tbl_unsupp # 01: fint
4082 long tbl_unsupp - tbl_unsupp # 02: fsinh
4083 long fintrz - tbl_unsupp # 03: fintrz
4084 long fsqrt - tbl_unsupp # 04: fsqrt
4085 long tbl_unsupp - tbl_unsupp
4086 long tbl_unsupp - tbl_unsupp # 06: flognp1
4087 long tbl_unsupp - tbl_unsupp
4088 long tbl_unsupp - tbl_unsupp # 08: fetoxm1
4089 long tbl_unsupp - tbl_unsupp # 09: ftanh
4090 long tbl_unsupp - tbl_unsupp # 0a: fatan
4091 long tbl_unsupp - tbl_unsupp
4092 long tbl_unsupp - tbl_unsupp # 0c: fasin
4093 long tbl_unsupp - tbl_unsupp # 0d: fatanh
4094 long tbl_unsupp - tbl_unsupp # 0e: fsin
4095 long tbl_unsupp - tbl_unsupp # 0f: ftan
4096 long tbl_unsupp - tbl_unsupp # 10: fetox
4097 long tbl_unsupp - tbl_unsupp # 11: ftwotox
4098 long tbl_unsupp - tbl_unsupp # 12: ftentox
4099 long tbl_unsupp - tbl_unsupp
4100 long tbl_unsupp - tbl_unsupp # 14: flogn
4101 long tbl_unsupp - tbl_unsupp # 15: flog10
4102 long tbl_unsupp - tbl_unsupp # 16: flog2
4103 long tbl_unsupp - tbl_unsupp
4104 long fabs - tbl_unsupp # 18: fabs
4105 long tbl_unsupp - tbl_unsupp # 19: fcosh
4106 long fneg - tbl_unsupp # 1a: fneg
4107 long tbl_unsupp - tbl_unsupp
4108 long tbl_unsupp - tbl_unsupp # 1c: facos
4109 long tbl_unsupp - tbl_unsupp # 1d: fcos
4110 long tbl_unsupp - tbl_unsupp # 1e: fgetexp
4111 long tbl_unsupp - tbl_unsupp # 1f: fgetman
4112 long fdiv - tbl_unsupp # 20: fdiv
4113 long tbl_unsupp - tbl_unsupp # 21: fmod
4114 long fadd - tbl_unsupp # 22: fadd
4115 long fmul - tbl_unsupp # 23: fmul
4116 long fsgldiv - tbl_unsupp # 24: fsgldiv
4117 long tbl_unsupp - tbl_unsupp # 25: frem
4118 long tbl_unsupp - tbl_unsupp # 26: fscale
4119 long fsglmul - tbl_unsupp # 27: fsglmul
4120 long fsub - tbl_unsupp # 28: fsub
4121 long tbl_unsupp - tbl_unsupp
4122 long tbl_unsupp - tbl_unsupp
4123 long tbl_unsupp - tbl_unsupp
4124 long tbl_unsupp - tbl_unsupp
4125 long tbl_unsupp - tbl_unsupp
4126 long tbl_unsupp - tbl_unsupp
4127 long tbl_unsupp - tbl_unsupp
4128 long tbl_unsupp - tbl_unsupp # 30: fsincos
4129 long tbl_unsupp - tbl_unsupp # 31: fsincos
4130 long tbl_unsupp - tbl_unsupp # 32: fsincos
4131 long tbl_unsupp - tbl_unsupp # 33: fsincos
4132 long tbl_unsupp - tbl_unsupp # 34: fsincos
4133 long tbl_unsupp - tbl_unsupp # 35: fsincos
4134 long tbl_unsupp - tbl_unsupp # 36: fsincos
4135 long tbl_unsupp - tbl_unsupp # 37: fsincos
4136 long fcmp - tbl_unsupp # 38: fcmp
4137 long tbl_unsupp - tbl_unsupp
4138 long ftst - tbl_unsupp # 3a: ftst
4139 long tbl_unsupp - tbl_unsupp
4140 long tbl_unsupp - tbl_unsupp
4141 long tbl_unsupp - tbl_unsupp
4142 long tbl_unsupp - tbl_unsupp
4143 long tbl_unsupp - tbl_unsupp
4144 long fsin - tbl_unsupp # 40: fsmove
4145 long fssqrt - tbl_unsupp # 41: fssqrt
4146 long tbl_unsupp - tbl_unsupp
4147 long tbl_unsupp - tbl_unsupp
4148 long fdin - tbl_unsupp # 44: fdmove
4149 long fdsqrt - tbl_unsupp # 45: fdsqrt
4150 long tbl_unsupp - tbl_unsupp
4151 long tbl_unsupp - tbl_unsupp
4152 long tbl_unsupp - tbl_unsupp
4153 long tbl_unsupp - tbl_unsupp
4154 long tbl_unsupp - tbl_unsupp
4155 long tbl_unsupp - tbl_unsupp
4156 long tbl_unsupp - tbl_unsupp
4157 long tbl_unsupp - tbl_unsupp
4158 long tbl_unsupp - tbl_unsupp
4159 long tbl_unsupp - tbl_unsupp
4160 long tbl_unsupp - tbl_unsupp
4161 long tbl_unsupp - tbl_unsupp
4162 long tbl_unsupp - tbl_unsupp
4163 long tbl_unsupp - tbl_unsupp
4164 long tbl_unsupp - tbl_unsupp
4165 long tbl_unsupp - tbl_unsupp
4166 long tbl_unsupp - tbl_unsupp
4167 long tbl_unsupp - tbl_unsupp
4168 long fsabs - tbl_unsupp # 58: fsabs
4169 long tbl_unsupp - tbl_unsupp
4170 long fsneg - tbl_unsupp # 5a: fsneg
4171 long tbl_unsupp - tbl_unsupp
4172 long fdabs - tbl_unsupp # 5c: fdabs
4173 long tbl_unsupp - tbl_unsupp
4174 long fdneg - tbl_unsupp # 5e: fdneg
4175 long tbl_unsupp - tbl_unsupp
4176 long fsdiv - tbl_unsupp # 60: fsdiv
4177 long tbl_unsupp - tbl_unsupp
4178 long fsadd - tbl_unsupp # 62: fsadd
4179 long fsmul - tbl_unsupp # 63: fsmul
4180 long fddiv - tbl_unsupp # 64: fddiv
4181 long tbl_unsupp - tbl_unsupp
4182 long fdadd - tbl_unsupp # 66: fdadd
4183 long fdmul - tbl_unsupp # 67: fdmul
4184 long fssub - tbl_unsupp # 68: fssub
4185 long tbl_unsupp - tbl_unsupp
4186 long tbl_unsupp - tbl_unsupp
4187 long tbl_unsupp - tbl_unsupp
4188 long fdsub - tbl_unsupp # 6c: fdsub
4189
4190#################################################
4191# Add this here so non-fp modules can compile.
4192# (smovcr is called from fpsp_inex.)
4193 global smovcr
4194smovcr:
4195 bra.b smovcr
4196
4197#########################################################################
4198# XDEF **************************************************************** #
4199# fmovm_dynamic(): emulate "fmovm" dynamic instruction #
4200# #
4201# XREF **************************************************************** #
4202# fetch_dreg() - fetch data register #
4203# {i,d,}mem_read() - fetch data from memory #
4204# _mem_write() - write data to memory #
4205# iea_iacc() - instruction memory access error occurred #
4206# iea_dacc() - data memory access error occurred #
4207# restore() - restore An index regs if access error occurred #
4208# #
4209# INPUT *************************************************************** #
4210# None #
4211# #
4212# OUTPUT ************************************************************** #
4213# If instr is "fmovm Dn,-(A7)" from supervisor mode, #
4214# d0 = size of dump #
4215# d1 = Dn #
4216# Else if instruction access error, #
4217# d0 = FSLW #
4218# Else if data access error, #
4219# d0 = FSLW #
4220# a0 = address of fault #
4221# Else #
4222# none. #
4223# #
4224# ALGORITHM *********************************************************** #
4225# The effective address must be calculated since this is entered #
4226# from an "Unimplemented Effective Address" exception handler. So, we #
4227# have our own fcalc_ea() routine here. If an access error is flagged #
4228# by a _{i,d,}mem_read() call, we must exit through the special #
4229# handler. #
4230# The data register is determined and its value loaded to get the #
4231# string of FP registers affected. This value is used as an index into #
4232# a lookup table such that we can determine the number of bytes #
4233# involved. #
4234# If the instruction is "fmovm.x <ea>,Dn", a _mem_read() is used #
4235# to read in all FP values. Again, _mem_read() may fail and require a #
4236# special exit. #
4237# If the instruction is "fmovm.x DN,<ea>", a _mem_write() is used #
4238# to write all FP values. _mem_write() may also fail. #
4239# If the instruction is "fmovm.x DN,-(a7)" from supervisor mode, #
4240# then we return the size of the dump and the string to the caller #
4241# so that the move can occur outside of this routine. This special #
4242# case is required so that moves to the system stack are handled #
4243# correctly. #
4244# #
4245# DYNAMIC: #
4246# fmovm.x dn, <ea> #
4247# fmovm.x <ea>, dn #
4248# #
4249# <WORD 1> <WORD2> #
4250# 1111 0010 00 |<ea>| 11@& 1000 0$$$ 0000 #
4251# #
4252# & = (0): predecrement addressing mode #
4253# (1): postincrement or control addressing mode #
4254# @ = (0): move listed regs from memory to the FPU #
4255# (1): move listed regs from the FPU to memory #
4256# $$$ : index of data register holding reg select mask #
4257# #
4258# NOTES: #
4259# If the data register holds a zero, then the #
4260# instruction is a nop. #
4261# #
4262#########################################################################
4263
4264 global fmovm_dynamic
4265fmovm_dynamic:
4266
4267# extract the data register in which the bit string resides...
4268 mov.b 1+EXC_EXTWORD(%a6),%d1 # fetch extword
4269 andi.w &0x70,%d1 # extract reg bits
4270 lsr.b &0x4,%d1 # shift into lo bits
4271
4272# fetch the bit string into d0...
4273 bsr.l fetch_dreg # fetch reg string
4274
4275 andi.l &0x000000ff,%d0 # keep only lo byte
4276
4277 mov.l %d0,-(%sp) # save strg
4278 mov.b (tbl_fmovm_size.w,%pc,%d0),%d0
4279 mov.l %d0,-(%sp) # save size
4280 bsr.l fmovm_calc_ea # calculate <ea>
4281 mov.l (%sp)+,%d0 # restore size
4282 mov.l (%sp)+,%d1 # restore strg
4283
4284# if the bit string is a zero, then the operation is a no-op
4285# but, make sure that we've calculated ea and advanced the opword pointer
4286 beq.w fmovm_data_done
4287
4288# separate move ins from move outs...
4289 btst &0x5,EXC_EXTWORD(%a6) # is it a move in or out?
4290 beq.w fmovm_data_in # it's a move out
4291
4292#############
4293# MOVE OUT: #
4294#############
4295fmovm_data_out:
4296 btst &0x4,EXC_EXTWORD(%a6) # control or predecrement?
4297 bne.w fmovm_out_ctrl # control
4298
4299############################
4300fmovm_out_predec:
4301# for predecrement mode, the bit string is the opposite of both control
4302# operations and postincrement mode. (bit7 = FP7 ... bit0 = FP0)
4303# here, we convert it to be just like the others...
4304 mov.b (tbl_fmovm_convert.w,%pc,%d1.w*1),%d1
4305
4306 btst &0x5,EXC_SR(%a6) # user or supervisor mode?
4307 beq.b fmovm_out_ctrl # user
4308
4309fmovm_out_predec_s:
4310 cmpi.b SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)?
4311 bne.b fmovm_out_ctrl
4312
4313# the operation was unfortunately an: fmovm.x dn,-(sp)
4314# called from supervisor mode.
4315# we're also passing "size" and "strg" back to the calling routine
4316 rts
4317
4318############################
4319fmovm_out_ctrl:
4320 mov.l %a0,%a1 # move <ea> to a1
4321
4322 sub.l %d0,%sp # subtract size of dump
4323 lea (%sp),%a0
4324
4325 tst.b %d1 # should FP0 be moved?
4326 bpl.b fmovm_out_ctrl_fp1 # no
4327
4328 mov.l 0x0+EXC_FP0(%a6),(%a0)+ # yes
4329 mov.l 0x4+EXC_FP0(%a6),(%a0)+
4330 mov.l 0x8+EXC_FP0(%a6),(%a0)+
4331
4332fmovm_out_ctrl_fp1:
4333 lsl.b &0x1,%d1 # should FP1 be moved?
4334 bpl.b fmovm_out_ctrl_fp2 # no
4335
4336 mov.l 0x0+EXC_FP1(%a6),(%a0)+ # yes
4337 mov.l 0x4+EXC_FP1(%a6),(%a0)+
4338 mov.l 0x8+EXC_FP1(%a6),(%a0)+
4339
4340fmovm_out_ctrl_fp2:
4341 lsl.b &0x1,%d1 # should FP2 be moved?
4342 bpl.b fmovm_out_ctrl_fp3 # no
4343
4344 fmovm.x &0x20,(%a0) # yes
4345 add.l &0xc,%a0
4346
4347fmovm_out_ctrl_fp3:
4348 lsl.b &0x1,%d1 # should FP3 be moved?
4349 bpl.b fmovm_out_ctrl_fp4 # no
4350
4351 fmovm.x &0x10,(%a0) # yes
4352 add.l &0xc,%a0
4353
4354fmovm_out_ctrl_fp4:
4355 lsl.b &0x1,%d1 # should FP4 be moved?
4356 bpl.b fmovm_out_ctrl_fp5 # no
4357
4358 fmovm.x &0x08,(%a0) # yes
4359 add.l &0xc,%a0
4360
4361fmovm_out_ctrl_fp5:
4362 lsl.b &0x1,%d1 # should FP5 be moved?
4363 bpl.b fmovm_out_ctrl_fp6 # no
4364
4365 fmovm.x &0x04,(%a0) # yes
4366 add.l &0xc,%a0
4367
4368fmovm_out_ctrl_fp6:
4369 lsl.b &0x1,%d1 # should FP6 be moved?
4370 bpl.b fmovm_out_ctrl_fp7 # no
4371
4372 fmovm.x &0x02,(%a0) # yes
4373 add.l &0xc,%a0
4374
4375fmovm_out_ctrl_fp7:
4376 lsl.b &0x1,%d1 # should FP7 be moved?
4377 bpl.b fmovm_out_ctrl_done # no
4378
4379 fmovm.x &0x01,(%a0) # yes
4380 add.l &0xc,%a0
4381
4382fmovm_out_ctrl_done:
4383 mov.l %a1,L_SCR1(%a6)
4384
4385 lea (%sp),%a0 # pass: supervisor src
4386 mov.l %d0,-(%sp) # save size
4387 bsr.l _dmem_write # copy data to user mem
4388
4389 mov.l (%sp)+,%d0
4390 add.l %d0,%sp # clear fpreg data from stack
4391
4392 tst.l %d1 # did dstore err?
4393 bne.w fmovm_out_err # yes
4394
4395 rts
4396
4397############
4398# MOVE IN: #
4399############
4400fmovm_data_in:
4401 mov.l %a0,L_SCR1(%a6)
4402
4403 sub.l %d0,%sp # make room for fpregs
4404 lea (%sp),%a1
4405
4406 mov.l %d1,-(%sp) # save bit string for later
4407 mov.l %d0,-(%sp) # save # of bytes
4408
4409 bsr.l _dmem_read # copy data from user mem
4410
4411 mov.l (%sp)+,%d0 # retrieve # of bytes
4412
4413 tst.l %d1 # did dfetch fail?
4414 bne.w fmovm_in_err # yes
4415
4416 mov.l (%sp)+,%d1 # load bit string
4417
4418 lea (%sp),%a0 # addr of stack
4419
4420 tst.b %d1 # should FP0 be moved?
4421 bpl.b fmovm_data_in_fp1 # no
4422
4423 mov.l (%a0)+,0x0+EXC_FP0(%a6) # yes
4424 mov.l (%a0)+,0x4+EXC_FP0(%a6)
4425 mov.l (%a0)+,0x8+EXC_FP0(%a6)
4426
4427fmovm_data_in_fp1:
4428 lsl.b &0x1,%d1 # should FP1 be moved?
4429 bpl.b fmovm_data_in_fp2 # no
4430
4431 mov.l (%a0)+,0x0+EXC_FP1(%a6) # yes
4432 mov.l (%a0)+,0x4+EXC_FP1(%a6)
4433 mov.l (%a0)+,0x8+EXC_FP1(%a6)
4434
4435fmovm_data_in_fp2:
4436 lsl.b &0x1,%d1 # should FP2 be moved?
4437 bpl.b fmovm_data_in_fp3 # no
4438
4439 fmovm.x (%a0)+,&0x20 # yes
4440
4441fmovm_data_in_fp3:
4442 lsl.b &0x1,%d1 # should FP3 be moved?
4443 bpl.b fmovm_data_in_fp4 # no
4444
4445 fmovm.x (%a0)+,&0x10 # yes
4446
4447fmovm_data_in_fp4:
4448 lsl.b &0x1,%d1 # should FP4 be moved?
4449 bpl.b fmovm_data_in_fp5 # no
4450
4451 fmovm.x (%a0)+,&0x08 # yes
4452
4453fmovm_data_in_fp5:
4454 lsl.b &0x1,%d1 # should FP5 be moved?
4455 bpl.b fmovm_data_in_fp6 # no
4456
4457 fmovm.x (%a0)+,&0x04 # yes
4458
4459fmovm_data_in_fp6:
4460 lsl.b &0x1,%d1 # should FP6 be moved?
4461 bpl.b fmovm_data_in_fp7 # no
4462
4463 fmovm.x (%a0)+,&0x02 # yes
4464
4465fmovm_data_in_fp7:
4466 lsl.b &0x1,%d1 # should FP7 be moved?
4467 bpl.b fmovm_data_in_done # no
4468
4469 fmovm.x (%a0)+,&0x01 # yes
4470
4471fmovm_data_in_done:
4472 add.l %d0,%sp # remove fpregs from stack
4473 rts
4474
4475#####################################
4476
4477fmovm_data_done:
4478 rts
4479
4480##############################################################################
4481
4482#
4483# table indexed by the operation's bit string that gives the number
4484# of bytes that will be moved.
4485#
4486# number of bytes = (# of 1's in bit string) * 12(bytes/fpreg)
4487#
4488tbl_fmovm_size:
4489 byte 0x00,0x0c,0x0c,0x18,0x0c,0x18,0x18,0x24
4490 byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4491 byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4492 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4493 byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4494 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4495 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4496 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4497 byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4498 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4499 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4500 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4501 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4502 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4503 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4504 byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4505 byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4506 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4507 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4508 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4509 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4510 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4511 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4512 byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4513 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4514 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4515 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4516 byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4517 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4518 byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4519 byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4520 byte 0x3c,0x48,0x48,0x54,0x48,0x54,0x54,0x60
4521
4522#
4523# table to convert a pre-decrement bit string into a post-increment
4524# or control bit string.
4525# ex: 0x00 ==> 0x00
4526# 0x01 ==> 0x80
4527# 0x02 ==> 0x40
4528# .
4529# .
4530# 0xfd ==> 0xbf
4531# 0xfe ==> 0x7f
4532# 0xff ==> 0xff
4533#
4534tbl_fmovm_convert:
4535 byte 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0
4536 byte 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0
4537 byte 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8
4538 byte 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8
4539 byte 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4
4540 byte 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4
4541 byte 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec
4542 byte 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc
4543 byte 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2
4544 byte 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2
4545 byte 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea
4546 byte 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa
4547 byte 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6
4548 byte 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6
4549 byte 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee
4550 byte 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe
4551 byte 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1
4552 byte 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1
4553 byte 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9
4554 byte 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9
4555 byte 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5
4556 byte 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5
4557 byte 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed
4558 byte 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd
4559 byte 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3
4560 byte 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3
4561 byte 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb
4562 byte 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb
4563 byte 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7
4564 byte 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7
4565 byte 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef
4566 byte 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
4567
4568 global fmovm_calc_ea
4569###############################################
4570# _fmovm_calc_ea: calculate effective address #
4571###############################################
4572fmovm_calc_ea:
4573 mov.l %d0,%a0 # move # bytes to a0
4574
4575# currently, MODE and REG are taken from the EXC_OPWORD. this could be
4576# easily changed if they were inputs passed in registers.
4577 mov.w EXC_OPWORD(%a6),%d0 # fetch opcode word
4578 mov.w %d0,%d1 # make a copy
4579
4580 andi.w &0x3f,%d0 # extract mode field
4581 andi.l &0x7,%d1 # extract reg field
4582
4583# jump to the corresponding function for each {MODE,REG} pair.
4584 mov.w (tbl_fea_mode.b,%pc,%d0.w*2),%d0 # fetch jmp distance
4585 jmp (tbl_fea_mode.b,%pc,%d0.w*1) # jmp to correct ea mode
4586
4587 swbeg &64
4588tbl_fea_mode:
4589 short tbl_fea_mode - tbl_fea_mode
4590 short tbl_fea_mode - tbl_fea_mode
4591 short tbl_fea_mode - tbl_fea_mode
4592 short tbl_fea_mode - tbl_fea_mode
4593 short tbl_fea_mode - tbl_fea_mode
4594 short tbl_fea_mode - tbl_fea_mode
4595 short tbl_fea_mode - tbl_fea_mode
4596 short tbl_fea_mode - tbl_fea_mode
4597
4598 short tbl_fea_mode - tbl_fea_mode
4599 short tbl_fea_mode - tbl_fea_mode
4600 short tbl_fea_mode - tbl_fea_mode
4601 short tbl_fea_mode - tbl_fea_mode
4602 short tbl_fea_mode - tbl_fea_mode
4603 short tbl_fea_mode - tbl_fea_mode
4604 short tbl_fea_mode - tbl_fea_mode
4605 short tbl_fea_mode - tbl_fea_mode
4606
4607 short faddr_ind_a0 - tbl_fea_mode
4608 short faddr_ind_a1 - tbl_fea_mode
4609 short faddr_ind_a2 - tbl_fea_mode
4610 short faddr_ind_a3 - tbl_fea_mode
4611 short faddr_ind_a4 - tbl_fea_mode
4612 short faddr_ind_a5 - tbl_fea_mode
4613 short faddr_ind_a6 - tbl_fea_mode
4614 short faddr_ind_a7 - tbl_fea_mode
4615
4616 short faddr_ind_p_a0 - tbl_fea_mode
4617 short faddr_ind_p_a1 - tbl_fea_mode
4618 short faddr_ind_p_a2 - tbl_fea_mode
4619 short faddr_ind_p_a3 - tbl_fea_mode
4620 short faddr_ind_p_a4 - tbl_fea_mode
4621 short faddr_ind_p_a5 - tbl_fea_mode
4622 short faddr_ind_p_a6 - tbl_fea_mode
4623 short faddr_ind_p_a7 - tbl_fea_mode
4624
4625 short faddr_ind_m_a0 - tbl_fea_mode
4626 short faddr_ind_m_a1 - tbl_fea_mode
4627 short faddr_ind_m_a2 - tbl_fea_mode
4628 short faddr_ind_m_a3 - tbl_fea_mode
4629 short faddr_ind_m_a4 - tbl_fea_mode
4630 short faddr_ind_m_a5 - tbl_fea_mode
4631 short faddr_ind_m_a6 - tbl_fea_mode
4632 short faddr_ind_m_a7 - tbl_fea_mode
4633
4634 short faddr_ind_disp_a0 - tbl_fea_mode
4635 short faddr_ind_disp_a1 - tbl_fea_mode
4636 short faddr_ind_disp_a2 - tbl_fea_mode
4637 short faddr_ind_disp_a3 - tbl_fea_mode
4638 short faddr_ind_disp_a4 - tbl_fea_mode
4639 short faddr_ind_disp_a5 - tbl_fea_mode
4640 short faddr_ind_disp_a6 - tbl_fea_mode
4641 short faddr_ind_disp_a7 - tbl_fea_mode
4642
4643 short faddr_ind_ext - tbl_fea_mode
4644 short faddr_ind_ext - tbl_fea_mode
4645 short faddr_ind_ext - tbl_fea_mode
4646 short faddr_ind_ext - tbl_fea_mode
4647 short faddr_ind_ext - tbl_fea_mode
4648 short faddr_ind_ext - tbl_fea_mode
4649 short faddr_ind_ext - tbl_fea_mode
4650 short faddr_ind_ext - tbl_fea_mode
4651
4652 short fabs_short - tbl_fea_mode
4653 short fabs_long - tbl_fea_mode
4654 short fpc_ind - tbl_fea_mode
4655 short fpc_ind_ext - tbl_fea_mode
4656 short tbl_fea_mode - tbl_fea_mode
4657 short tbl_fea_mode - tbl_fea_mode
4658 short tbl_fea_mode - tbl_fea_mode
4659 short tbl_fea_mode - tbl_fea_mode
4660
4661###################################
4662# Address register indirect: (An) #
4663###################################
4664faddr_ind_a0:
4665 mov.l EXC_DREGS+0x8(%a6),%a0 # Get current a0
4666 rts
4667
4668faddr_ind_a1:
4669 mov.l EXC_DREGS+0xc(%a6),%a0 # Get current a1
4670 rts
4671
4672faddr_ind_a2:
4673 mov.l %a2,%a0 # Get current a2
4674 rts
4675
4676faddr_ind_a3:
4677 mov.l %a3,%a0 # Get current a3
4678 rts
4679
4680faddr_ind_a4:
4681 mov.l %a4,%a0 # Get current a4
4682 rts
4683
4684faddr_ind_a5:
4685 mov.l %a5,%a0 # Get current a5
4686 rts
4687
4688faddr_ind_a6:
4689 mov.l (%a6),%a0 # Get current a6
4690 rts
4691
4692faddr_ind_a7:
4693 mov.l EXC_A7(%a6),%a0 # Get current a7
4694 rts
4695
4696#####################################################
4697# Address register indirect w/ postincrement: (An)+ #
4698#####################################################
4699faddr_ind_p_a0:
4700 mov.l EXC_DREGS+0x8(%a6),%d0 # Get current a0
4701 mov.l %d0,%d1
4702 add.l %a0,%d1 # Increment
4703 mov.l %d1,EXC_DREGS+0x8(%a6) # Save incr value
4704 mov.l %d0,%a0
4705 rts
4706
4707faddr_ind_p_a1:
4708 mov.l EXC_DREGS+0xc(%a6),%d0 # Get current a1
4709 mov.l %d0,%d1
4710 add.l %a0,%d1 # Increment
4711 mov.l %d1,EXC_DREGS+0xc(%a6) # Save incr value
4712 mov.l %d0,%a0
4713 rts
4714
4715faddr_ind_p_a2:
4716 mov.l %a2,%d0 # Get current a2
4717 mov.l %d0,%d1
4718 add.l %a0,%d1 # Increment
4719 mov.l %d1,%a2 # Save incr value
4720 mov.l %d0,%a0
4721 rts
4722
4723faddr_ind_p_a3:
4724 mov.l %a3,%d0 # Get current a3
4725 mov.l %d0,%d1
4726 add.l %a0,%d1 # Increment
4727 mov.l %d1,%a3 # Save incr value
4728 mov.l %d0,%a0
4729 rts
4730
4731faddr_ind_p_a4:
4732 mov.l %a4,%d0 # Get current a4
4733 mov.l %d0,%d1
4734 add.l %a0,%d1 # Increment
4735 mov.l %d1,%a4 # Save incr value
4736 mov.l %d0,%a0
4737 rts
4738
4739faddr_ind_p_a5:
4740 mov.l %a5,%d0 # Get current a5
4741 mov.l %d0,%d1
4742 add.l %a0,%d1 # Increment
4743 mov.l %d1,%a5 # Save incr value
4744 mov.l %d0,%a0
4745 rts
4746
4747faddr_ind_p_a6:
4748 mov.l (%a6),%d0 # Get current a6
4749 mov.l %d0,%d1
4750 add.l %a0,%d1 # Increment
4751 mov.l %d1,(%a6) # Save incr value
4752 mov.l %d0,%a0
4753 rts
4754
4755faddr_ind_p_a7:
4756 mov.b &mia7_flg,SPCOND_FLG(%a6) # set "special case" flag
4757
4758 mov.l EXC_A7(%a6),%d0 # Get current a7
4759 mov.l %d0,%d1
4760 add.l %a0,%d1 # Increment
4761 mov.l %d1,EXC_A7(%a6) # Save incr value
4762 mov.l %d0,%a0
4763 rts
4764
4765####################################################
4766# Address register indirect w/ predecrement: -(An) #
4767####################################################
4768faddr_ind_m_a0:
4769 mov.l EXC_DREGS+0x8(%a6),%d0 # Get current a0
4770 sub.l %a0,%d0 # Decrement
4771 mov.l %d0,EXC_DREGS+0x8(%a6) # Save decr value
4772 mov.l %d0,%a0
4773 rts
4774
4775faddr_ind_m_a1:
4776 mov.l EXC_DREGS+0xc(%a6),%d0 # Get current a1
4777 sub.l %a0,%d0 # Decrement
4778 mov.l %d0,EXC_DREGS+0xc(%a6) # Save decr value
4779 mov.l %d0,%a0
4780 rts
4781
4782faddr_ind_m_a2:
4783 mov.l %a2,%d0 # Get current a2
4784 sub.l %a0,%d0 # Decrement
4785 mov.l %d0,%a2 # Save decr value
4786 mov.l %d0,%a0
4787 rts
4788
4789faddr_ind_m_a3:
4790 mov.l %a3,%d0 # Get current a3
4791 sub.l %a0,%d0 # Decrement
4792 mov.l %d0,%a3 # Save decr value
4793 mov.l %d0,%a0
4794 rts
4795
4796faddr_ind_m_a4:
4797 mov.l %a4,%d0 # Get current a4
4798 sub.l %a0,%d0 # Decrement
4799 mov.l %d0,%a4 # Save decr value
4800 mov.l %d0,%a0
4801 rts
4802
4803faddr_ind_m_a5:
4804 mov.l %a5,%d0 # Get current a5
4805 sub.l %a0,%d0 # Decrement
4806 mov.l %d0,%a5 # Save decr value
4807 mov.l %d0,%a0
4808 rts
4809
4810faddr_ind_m_a6:
4811 mov.l (%a6),%d0 # Get current a6
4812 sub.l %a0,%d0 # Decrement
4813 mov.l %d0,(%a6) # Save decr value
4814 mov.l %d0,%a0
4815 rts
4816
4817faddr_ind_m_a7:
4818 mov.b &mda7_flg,SPCOND_FLG(%a6) # set "special case" flag
4819
4820 mov.l EXC_A7(%a6),%d0 # Get current a7
4821 sub.l %a0,%d0 # Decrement
4822 mov.l %d0,EXC_A7(%a6) # Save decr value
4823 mov.l %d0,%a0
4824 rts
4825
4826########################################################
4827# Address register indirect w/ displacement: (d16, An) #
4828########################################################
4829faddr_ind_disp_a0:
4830 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4831 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4832 bsr.l _imem_read_word
4833
4834 tst.l %d1 # did ifetch fail?
4835 bne.l iea_iacc # yes
4836
4837 mov.w %d0,%a0 # sign extend displacement
4838
4839 add.l EXC_DREGS+0x8(%a6),%a0 # a0 + d16
4840 rts
4841
4842faddr_ind_disp_a1:
4843 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4844 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4845 bsr.l _imem_read_word
4846
4847 tst.l %d1 # did ifetch fail?
4848 bne.l iea_iacc # yes
4849
4850 mov.w %d0,%a0 # sign extend displacement
4851
4852 add.l EXC_DREGS+0xc(%a6),%a0 # a1 + d16
4853 rts
4854
4855faddr_ind_disp_a2:
4856 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4857 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4858 bsr.l _imem_read_word
4859
4860 tst.l %d1 # did ifetch fail?
4861 bne.l iea_iacc # yes
4862
4863 mov.w %d0,%a0 # sign extend displacement
4864
4865 add.l %a2,%a0 # a2 + d16
4866 rts
4867
4868faddr_ind_disp_a3:
4869 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4870 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4871 bsr.l _imem_read_word
4872
4873 tst.l %d1 # did ifetch fail?
4874 bne.l iea_iacc # yes
4875
4876 mov.w %d0,%a0 # sign extend displacement
4877
4878 add.l %a3,%a0 # a3 + d16
4879 rts
4880
4881faddr_ind_disp_a4:
4882 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4883 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4884 bsr.l _imem_read_word
4885
4886 tst.l %d1 # did ifetch fail?
4887 bne.l iea_iacc # yes
4888
4889 mov.w %d0,%a0 # sign extend displacement
4890
4891 add.l %a4,%a0 # a4 + d16
4892 rts
4893
4894faddr_ind_disp_a5:
4895 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4896 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4897 bsr.l _imem_read_word
4898
4899 tst.l %d1 # did ifetch fail?
4900 bne.l iea_iacc # yes
4901
4902 mov.w %d0,%a0 # sign extend displacement
4903
4904 add.l %a5,%a0 # a5 + d16
4905 rts
4906
4907faddr_ind_disp_a6:
4908 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4909 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4910 bsr.l _imem_read_word
4911
4912 tst.l %d1 # did ifetch fail?
4913 bne.l iea_iacc # yes
4914
4915 mov.w %d0,%a0 # sign extend displacement
4916
4917 add.l (%a6),%a0 # a6 + d16
4918 rts
4919
4920faddr_ind_disp_a7:
4921 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4922 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4923 bsr.l _imem_read_word
4924
4925 tst.l %d1 # did ifetch fail?
4926 bne.l iea_iacc # yes
4927
4928 mov.w %d0,%a0 # sign extend displacement
4929
4930 add.l EXC_A7(%a6),%a0 # a7 + d16
4931 rts
4932
4933########################################################################
4934# Address register indirect w/ index(8-bit displacement): (d8, An, Xn) #
4935# " " " w/ " (base displacement): (bd, An, Xn) #
4936# Memory indirect postindexed: ([bd, An], Xn, od) #
4937# Memory indirect preindexed: ([bd, An, Xn], od) #
4938########################################################################
4939faddr_ind_ext:
4940 addq.l &0x8,%d1
4941 bsr.l fetch_dreg # fetch base areg
4942 mov.l %d0,-(%sp)
4943
4944 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4945 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4946 bsr.l _imem_read_word # fetch extword in d0
4947
4948 tst.l %d1 # did ifetch fail?
4949 bne.l iea_iacc # yes
4950
4951 mov.l (%sp)+,%a0
4952
4953 btst &0x8,%d0
4954 bne.w fcalc_mem_ind
4955
4956 mov.l %d0,L_SCR1(%a6) # hold opword
4957
4958 mov.l %d0,%d1
4959 rol.w &0x4,%d1
4960 andi.w &0xf,%d1 # extract index regno
4961
4962# count on fetch_dreg() not to alter a0...
4963 bsr.l fetch_dreg # fetch index
4964
4965 mov.l %d2,-(%sp) # save d2
4966 mov.l L_SCR1(%a6),%d2 # fetch opword
4967
4968 btst &0xb,%d2 # is it word or long?
4969 bne.b faii8_long
4970 ext.l %d0 # sign extend word index
4971faii8_long:
4972 mov.l %d2,%d1
4973 rol.w &0x7,%d1
4974 andi.l &0x3,%d1 # extract scale value
4975
4976 lsl.l %d1,%d0 # shift index by scale
4977
4978 extb.l %d2 # sign extend displacement
4979 add.l %d2,%d0 # index + disp
4980 add.l %d0,%a0 # An + (index + disp)
4981
4982 mov.l (%sp)+,%d2 # restore old d2
4983 rts
4984
4985###########################
4986# Absolute short: (XXX).W #
4987###########################
4988fabs_short:
4989 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
4990 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
4991 bsr.l _imem_read_word # fetch short address
4992
4993 tst.l %d1 # did ifetch fail?
4994 bne.l iea_iacc # yes
4995
4996 mov.w %d0,%a0 # return <ea> in a0
4997 rts
4998
4999##########################
5000# Absolute long: (XXX).L #
5001##########################
5002fabs_long:
5003 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5004 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5005 bsr.l _imem_read_long # fetch long address
5006
5007 tst.l %d1 # did ifetch fail?
5008 bne.l iea_iacc # yes
5009
5010 mov.l %d0,%a0 # return <ea> in a0
5011 rts
5012
5013#######################################################
5014# Program counter indirect w/ displacement: (d16, PC) #
5015#######################################################
5016fpc_ind:
5017 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5018 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
5019 bsr.l _imem_read_word # fetch word displacement
5020
5021 tst.l %d1 # did ifetch fail?
5022 bne.l iea_iacc # yes
5023
5024 mov.w %d0,%a0 # sign extend displacement
5025
5026 add.l EXC_EXTWPTR(%a6),%a0 # pc + d16
5027
5028# _imem_read_word() increased the extwptr by 2. need to adjust here.
5029 subq.l &0x2,%a0 # adjust <ea>
5030 rts
5031
5032##########################################################
5033# PC indirect w/ index(8-bit displacement): (d8, PC, An) #
5034# " " w/ " (base displacement): (bd, PC, An) #
5035# PC memory indirect postindexed: ([bd, PC], Xn, od) #
5036# PC memory indirect preindexed: ([bd, PC, Xn], od) #
5037##########################################################
5038fpc_ind_ext:
5039 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5040 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
5041 bsr.l _imem_read_word # fetch ext word
5042
5043 tst.l %d1 # did ifetch fail?
5044 bne.l iea_iacc # yes
5045
5046 mov.l EXC_EXTWPTR(%a6),%a0 # put base in a0
5047 subq.l &0x2,%a0 # adjust base
5048
5049 btst &0x8,%d0 # is disp only 8 bits?
5050 bne.w fcalc_mem_ind # calc memory indirect
5051
5052 mov.l %d0,L_SCR1(%a6) # store opword
5053
5054 mov.l %d0,%d1 # make extword copy
5055 rol.w &0x4,%d1 # rotate reg num into place
5056 andi.w &0xf,%d1 # extract register number
5057
5058# count on fetch_dreg() not to alter a0...
5059 bsr.l fetch_dreg # fetch index
5060
5061 mov.l %d2,-(%sp) # save d2
5062 mov.l L_SCR1(%a6),%d2 # fetch opword
5063
5064 btst &0xb,%d2 # is index word or long?
5065 bne.b fpii8_long # long
5066 ext.l %d0 # sign extend word index
5067fpii8_long:
5068 mov.l %d2,%d1
5069 rol.w &0x7,%d1 # rotate scale value into place
5070 andi.l &0x3,%d1 # extract scale value
5071
5072 lsl.l %d1,%d0 # shift index by scale
5073
5074 extb.l %d2 # sign extend displacement
5075 add.l %d2,%d0 # disp + index
5076 add.l %d0,%a0 # An + (index + disp)
5077
5078 mov.l (%sp)+,%d2 # restore temp register
5079 rts
5080
5081# d2 = index
5082# d3 = base
5083# d4 = od
5084# d5 = extword
5085fcalc_mem_ind:
5086 btst &0x6,%d0 # is the index suppressed?
5087 beq.b fcalc_index
5088
5089 movm.l &0x3c00,-(%sp) # save d2-d5
5090
5091 mov.l %d0,%d5 # put extword in d5
5092 mov.l %a0,%d3 # put base in d3
5093
5094 clr.l %d2 # yes, so index = 0
5095 bra.b fbase_supp_ck
5096
5097# index:
5098fcalc_index:
5099 mov.l %d0,L_SCR1(%a6) # save d0 (opword)
5100 bfextu %d0{&16:&4},%d1 # fetch dreg index
5101 bsr.l fetch_dreg
5102
5103 movm.l &0x3c00,-(%sp) # save d2-d5
5104 mov.l %d0,%d2 # put index in d2
5105 mov.l L_SCR1(%a6),%d5
5106 mov.l %a0,%d3
5107
5108 btst &0xb,%d5 # is index word or long?
5109 bne.b fno_ext
5110 ext.l %d2
5111
5112fno_ext:
5113 bfextu %d5{&21:&2},%d0
5114 lsl.l %d0,%d2
5115
5116# base address (passed as parameter in d3):
5117# we clear the value here if it should actually be suppressed.
5118fbase_supp_ck:
5119 btst &0x7,%d5 # is the bd suppressed?
5120 beq.b fno_base_sup
5121 clr.l %d3
5122
5123# base displacement:
5124fno_base_sup:
5125 bfextu %d5{&26:&2},%d0 # get bd size
5126# beq.l fmovm_error # if (size == 0) it's reserved
5127
5128 cmpi.b %d0,&0x2
5129 blt.b fno_bd
5130 beq.b fget_word_bd
5131
5132 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5133 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5134 bsr.l _imem_read_long
5135
5136 tst.l %d1 # did ifetch fail?
5137 bne.l fcea_iacc # yes
5138
5139 bra.b fchk_ind
5140
5141fget_word_bd:
5142 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5143 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
5144 bsr.l _imem_read_word
5145
5146 tst.l %d1 # did ifetch fail?
5147 bne.l fcea_iacc # yes
5148
5149 ext.l %d0 # sign extend bd
5150
5151fchk_ind:
5152 add.l %d0,%d3 # base += bd
5153
5154# outer displacement:
5155fno_bd:
5156 bfextu %d5{&30:&2},%d0 # is od suppressed?
5157 beq.w faii_bd
5158
5159 cmpi.b %d0,&0x2
5160 blt.b fnull_od
5161 beq.b fword_od
5162
5163 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5164 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5165 bsr.l _imem_read_long
5166
5167 tst.l %d1 # did ifetch fail?
5168 bne.l fcea_iacc # yes
5169
5170 bra.b fadd_them
5171
5172fword_od:
5173 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5174 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
5175 bsr.l _imem_read_word
5176
5177 tst.l %d1 # did ifetch fail?
5178 bne.l fcea_iacc # yes
5179
5180 ext.l %d0 # sign extend od
5181 bra.b fadd_them
5182
5183fnull_od:
5184 clr.l %d0
5185
5186fadd_them:
5187 mov.l %d0,%d4
5188
5189 btst &0x2,%d5 # pre or post indexing?
5190 beq.b fpre_indexed
5191
5192 mov.l %d3,%a0
5193 bsr.l _dmem_read_long
5194
5195 tst.l %d1 # did dfetch fail?
5196 bne.w fcea_err # yes
5197
5198 add.l %d2,%d0 # <ea> += index
5199 add.l %d4,%d0 # <ea> += od
5200 bra.b fdone_ea
5201
5202fpre_indexed:
5203 add.l %d2,%d3 # preindexing
5204 mov.l %d3,%a0
5205 bsr.l _dmem_read_long
5206
5207 tst.l %d1 # did dfetch fail?
5208 bne.w fcea_err # yes
5209
5210 add.l %d4,%d0 # ea += od
5211 bra.b fdone_ea
5212
5213faii_bd:
5214 add.l %d2,%d3 # ea = (base + bd) + index
5215 mov.l %d3,%d0
5216fdone_ea:
5217 mov.l %d0,%a0
5218
5219 movm.l (%sp)+,&0x003c # restore d2-d5
5220 rts
5221
5222#########################################################
5223fcea_err:
5224 mov.l %d3,%a0
5225
5226 movm.l (%sp)+,&0x003c # restore d2-d5
5227 mov.w &0x0101,%d0
5228 bra.l iea_dacc
5229
5230fcea_iacc:
5231 movm.l (%sp)+,&0x003c # restore d2-d5
5232 bra.l iea_iacc
5233
5234fmovm_out_err:
5235 bsr.l restore
5236 mov.w &0x00e1,%d0
5237 bra.b fmovm_err
5238
5239fmovm_in_err:
5240 bsr.l restore
5241 mov.w &0x0161,%d0
5242
5243fmovm_err:
5244 mov.l L_SCR1(%a6),%a0
5245 bra.l iea_dacc
5246
5247#########################################################################
5248# XDEF **************************************************************** #
5249# fmovm_ctrl(): emulate fmovm.l of control registers instr #
5250# #
5251# XREF **************************************************************** #
5252# _imem_read_long() - read longword from memory #
5253# iea_iacc() - _imem_read_long() failed; error recovery #
5254# #
5255# INPUT *************************************************************** #
5256# None #
5257# #
5258# OUTPUT ************************************************************** #
5259# If _imem_read_long() doesn't fail: #
5260# USER_FPCR(a6) = new FPCR value #
5261# USER_FPSR(a6) = new FPSR value #
5262# USER_FPIAR(a6) = new FPIAR value #
5263# #
5264# ALGORITHM *********************************************************** #
5265# Decode the instruction type by looking at the extension word #
5266# in order to see how many control registers to fetch from memory. #
5267# Fetch them using _imem_read_long(). If this fetch fails, exit through #
5268# the special access error exit handler iea_iacc(). #
5269# #
5270# Instruction word decoding: #
5271# #
5272# fmovem.l #<data>, {FPIAR&|FPCR&|FPSR} #
5273# #
5274# WORD1 WORD2 #
5275# 1111 0010 00 111100 100$ $$00 0000 0000 #
5276# #
5277# $$$ (100): FPCR #
5278# (010): FPSR #
5279# (001): FPIAR #
5280# (000): FPIAR #
5281# #
5282#########################################################################
5283
5284 global fmovm_ctrl
5285fmovm_ctrl:
5286 mov.b EXC_EXTWORD(%a6),%d0 # fetch reg select bits
5287 cmpi.b %d0,&0x9c # fpcr & fpsr & fpiar ?
5288 beq.w fctrl_in_7 # yes
5289 cmpi.b %d0,&0x98 # fpcr & fpsr ?
5290 beq.w fctrl_in_6 # yes
5291 cmpi.b %d0,&0x94 # fpcr & fpiar ?
5292 beq.b fctrl_in_5 # yes
5293
5294# fmovem.l #<data>, fpsr/fpiar
5295fctrl_in_3:
5296 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5297 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5298 bsr.l _imem_read_long # fetch FPSR from mem
5299
5300 tst.l %d1 # did ifetch fail?
5301 bne.l iea_iacc # yes
5302
5303 mov.l %d0,USER_FPSR(%a6) # store new FPSR to stack
5304 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5305 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5306 bsr.l _imem_read_long # fetch FPIAR from mem
5307
5308 tst.l %d1 # did ifetch fail?
5309 bne.l iea_iacc # yes
5310
5311 mov.l %d0,USER_FPIAR(%a6) # store new FPIAR to stack
5312 rts
5313
5314# fmovem.l #<data>, fpcr/fpiar
5315fctrl_in_5:
5316 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5317 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5318 bsr.l _imem_read_long # fetch FPCR from mem
5319
5320 tst.l %d1 # did ifetch fail?
5321 bne.l iea_iacc # yes
5322
5323 mov.l %d0,USER_FPCR(%a6) # store new FPCR to stack
5324 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5325 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5326 bsr.l _imem_read_long # fetch FPIAR from mem
5327
5328 tst.l %d1 # did ifetch fail?
5329 bne.l iea_iacc # yes
5330
5331 mov.l %d0,USER_FPIAR(%a6) # store new FPIAR to stack
5332 rts
5333
5334# fmovem.l #<data>, fpcr/fpsr
5335fctrl_in_6:
5336 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5337 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5338 bsr.l _imem_read_long # fetch FPCR from mem
5339
5340 tst.l %d1 # did ifetch fail?
5341 bne.l iea_iacc # yes
5342
5343 mov.l %d0,USER_FPCR(%a6) # store new FPCR to mem
5344 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5345 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5346 bsr.l _imem_read_long # fetch FPSR from mem
5347
5348 tst.l %d1 # did ifetch fail?
5349 bne.l iea_iacc # yes
5350
5351 mov.l %d0,USER_FPSR(%a6) # store new FPSR to mem
5352 rts
5353
5354# fmovem.l #<data>, fpcr/fpsr/fpiar
5355fctrl_in_7:
5356 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5357 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5358 bsr.l _imem_read_long # fetch FPCR from mem
5359
5360 tst.l %d1 # did ifetch fail?
5361 bne.l iea_iacc # yes
5362
5363 mov.l %d0,USER_FPCR(%a6) # store new FPCR to mem
5364 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5365 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5366 bsr.l _imem_read_long # fetch FPSR from mem
5367
5368 tst.l %d1 # did ifetch fail?
5369 bne.l iea_iacc # yes
5370
5371 mov.l %d0,USER_FPSR(%a6) # store new FPSR to mem
5372 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
5373 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
5374 bsr.l _imem_read_long # fetch FPIAR from mem
5375
5376 tst.l %d1 # did ifetch fail?
5377 bne.l iea_iacc # yes
5378
5379 mov.l %d0,USER_FPIAR(%a6) # store new FPIAR to mem
5380 rts
5381
5382##########################################################################
5383
5384#########################################################################
5385# XDEF **************************************************************** #
5386# addsub_scaler2(): scale inputs to fadd/fsub such that no #
5387# OVFL/UNFL exceptions will result #
5388# #
5389# XREF **************************************************************** #
5390# norm() - normalize mantissa after adjusting exponent #
5391# #
5392# INPUT *************************************************************** #
5393# FP_SRC(a6) = fp op1(src) #
5394# FP_DST(a6) = fp op2(dst) #
5395# #
5396# OUTPUT ************************************************************** #
5397# FP_SRC(a6) = fp op1 scaled(src) #
5398# FP_DST(a6) = fp op2 scaled(dst) #
5399# d0 = scale amount #
5400# #
5401# ALGORITHM *********************************************************** #
5402# If the DST exponent is > the SRC exponent, set the DST exponent #
5403# equal to 0x3fff and scale the SRC exponent by the value that the #
5404# DST exponent was scaled by. If the SRC exponent is greater or equal, #
5405# do the opposite. Return this scale factor in d0. #
5406# If the two exponents differ by > the number of mantissa bits #
5407# plus two, then set the smallest exponent to a very small value as a #
5408# quick shortcut. #
5409# #
5410#########################################################################
5411
5412 global addsub_scaler2
5413addsub_scaler2:
5414 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
5415 mov.l DST_HI(%a1),FP_SCR1_HI(%a6)
5416 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
5417 mov.l DST_LO(%a1),FP_SCR1_LO(%a6)
5418 mov.w SRC_EX(%a0),%d0
5419 mov.w DST_EX(%a1),%d1
5420 mov.w %d0,FP_SCR0_EX(%a6)
5421 mov.w %d1,FP_SCR1_EX(%a6)
5422
5423 andi.w &0x7fff,%d0
5424 andi.w &0x7fff,%d1
5425 mov.w %d0,L_SCR1(%a6) # store src exponent
5426 mov.w %d1,2+L_SCR1(%a6) # store dst exponent
5427
5428 cmp.w %d0, %d1 # is src exp >= dst exp?
5429 bge.l src_exp_ge2
5430
5431# dst exp is > src exp; scale dst to exp = 0x3fff
5432dst_exp_gt2:
5433 bsr.l scale_to_zero_dst
5434 mov.l %d0,-(%sp) # save scale factor
5435
5436 cmpi.b STAG(%a6),&DENORM # is dst denormalized?
5437 bne.b cmpexp12
5438
5439 lea FP_SCR0(%a6),%a0
5440 bsr.l norm # normalize the denorm; result is new exp
5441 neg.w %d0 # new exp = -(shft val)
5442 mov.w %d0,L_SCR1(%a6) # inset new exp
5443
5444cmpexp12:
5445 mov.w 2+L_SCR1(%a6),%d0
5446 subi.w &mantissalen+2,%d0 # subtract mantissalen+2 from larger exp
5447
5448 cmp.w %d0,L_SCR1(%a6) # is difference >= len(mantissa)+2?
5449 bge.b quick_scale12
5450
5451 mov.w L_SCR1(%a6),%d0
5452 add.w 0x2(%sp),%d0 # scale src exponent by scale factor
5453 mov.w FP_SCR0_EX(%a6),%d1
5454 and.w &0x8000,%d1
5455 or.w %d1,%d0 # concat {sgn,new exp}
5456 mov.w %d0,FP_SCR0_EX(%a6) # insert new dst exponent
5457
5458 mov.l (%sp)+,%d0 # return SCALE factor
5459 rts
5460
5461quick_scale12:
5462 andi.w &0x8000,FP_SCR0_EX(%a6) # zero src exponent
5463 bset &0x0,1+FP_SCR0_EX(%a6) # set exp = 1
5464
5465 mov.l (%sp)+,%d0 # return SCALE factor
5466 rts
5467
5468# src exp is >= dst exp; scale src to exp = 0x3fff
5469src_exp_ge2:
5470 bsr.l scale_to_zero_src
5471 mov.l %d0,-(%sp) # save scale factor
5472
5473 cmpi.b DTAG(%a6),&DENORM # is dst denormalized?
5474 bne.b cmpexp22
5475 lea FP_SCR1(%a6),%a0
5476 bsr.l norm # normalize the denorm; result is new exp
5477 neg.w %d0 # new exp = -(shft val)
5478 mov.w %d0,2+L_SCR1(%a6) # inset new exp
5479
5480cmpexp22:
5481 mov.w L_SCR1(%a6),%d0
5482 subi.w &mantissalen+2,%d0 # subtract mantissalen+2 from larger exp
5483
5484 cmp.w %d0,2+L_SCR1(%a6) # is difference >= len(mantissa)+2?
5485 bge.b quick_scale22
5486
5487 mov.w 2+L_SCR1(%a6),%d0
5488 add.w 0x2(%sp),%d0 # scale dst exponent by scale factor
5489 mov.w FP_SCR1_EX(%a6),%d1
5490 andi.w &0x8000,%d1
5491 or.w %d1,%d0 # concat {sgn,new exp}
5492 mov.w %d0,FP_SCR1_EX(%a6) # insert new dst exponent
5493
5494 mov.l (%sp)+,%d0 # return SCALE factor
5495 rts
5496
5497quick_scale22:
5498 andi.w &0x8000,FP_SCR1_EX(%a6) # zero dst exponent
5499 bset &0x0,1+FP_SCR1_EX(%a6) # set exp = 1
5500
5501 mov.l (%sp)+,%d0 # return SCALE factor
5502 rts
5503
5504##########################################################################
5505
5506#########################################################################
5507# XDEF **************************************************************** #
5508# scale_to_zero_src(): scale the exponent of extended precision #
5509# value at FP_SCR0(a6). #
5510# #
5511# XREF **************************************************************** #
5512# norm() - normalize the mantissa if the operand was a DENORM #
5513# #
5514# INPUT *************************************************************** #
5515# FP_SCR0(a6) = extended precision operand to be scaled #
5516# #
5517# OUTPUT ************************************************************** #
5518# FP_SCR0(a6) = scaled extended precision operand #
5519# d0 = scale value #
5520# #
5521# ALGORITHM *********************************************************** #
5522# Set the exponent of the input operand to 0x3fff. Save the value #
5523# of the difference between the original and new exponent. Then, #
5524# normalize the operand if it was a DENORM. Add this normalization #
5525# value to the previous value. Return the result. #
5526# #
5527#########################################################################
5528
5529 global scale_to_zero_src
5530scale_to_zero_src:
5531 mov.w FP_SCR0_EX(%a6),%d1 # extract operand's {sgn,exp}
5532 mov.w %d1,%d0 # make a copy
5533
5534 andi.l &0x7fff,%d1 # extract operand's exponent
5535
5536 andi.w &0x8000,%d0 # extract operand's sgn
5537 or.w &0x3fff,%d0 # insert new operand's exponent(=0)
5538
5539 mov.w %d0,FP_SCR0_EX(%a6) # insert biased exponent
5540
5541 cmpi.b STAG(%a6),&DENORM # is operand normalized?
5542 beq.b stzs_denorm # normalize the DENORM
5543
5544stzs_norm:
5545 mov.l &0x3fff,%d0
5546 sub.l %d1,%d0 # scale = BIAS + (-exp)
5547
5548 rts
5549
5550stzs_denorm:
5551 lea FP_SCR0(%a6),%a0 # pass ptr to src op
5552 bsr.l norm # normalize denorm
5553 neg.l %d0 # new exponent = -(shft val)
5554 mov.l %d0,%d1 # prepare for op_norm call
5555 bra.b stzs_norm # finish scaling
5556
5557###
5558
5559#########################################################################
5560# XDEF **************************************************************** #
5561# scale_sqrt(): scale the input operand exponent so a subsequent #
5562# fsqrt operation won't take an exception. #
5563# #
5564# XREF **************************************************************** #
5565# norm() - normalize the mantissa if the operand was a DENORM #
5566# #
5567# INPUT *************************************************************** #
5568# FP_SCR0(a6) = extended precision operand to be scaled #
5569# #
5570# OUTPUT ************************************************************** #
5571# FP_SCR0(a6) = scaled extended precision operand #
5572# d0 = scale value #
5573# #
5574# ALGORITHM *********************************************************** #
5575# If the input operand is a DENORM, normalize it. #
5576# If the exponent of the input operand is even, set the exponent #
5577# to 0x3ffe and return a scale factor of "(exp-0x3ffe)/2". If the #
5578# exponent of the input operand is off, set the exponent to ox3fff and #
5579# return a scale factor of "(exp-0x3fff)/2". #
5580# #
5581#########################################################################
5582
5583 global scale_sqrt
5584scale_sqrt:
5585 cmpi.b STAG(%a6),&DENORM # is operand normalized?
5586 beq.b ss_denorm # normalize the DENORM
5587
5588 mov.w FP_SCR0_EX(%a6),%d1 # extract operand's {sgn,exp}
5589 andi.l &0x7fff,%d1 # extract operand's exponent
5590
5591 andi.w &0x8000,FP_SCR0_EX(%a6) # extract operand's sgn
5592
5593 btst &0x0,%d1 # is exp even or odd?
5594 beq.b ss_norm_even
5595
5596 ori.w &0x3fff,FP_SCR0_EX(%a6) # insert new operand's exponent(=0)
5597
5598 mov.l &0x3fff,%d0
5599 sub.l %d1,%d0 # scale = BIAS + (-exp)
5600 asr.l &0x1,%d0 # divide scale factor by 2
5601 rts
5602
5603ss_norm_even:
5604 ori.w &0x3ffe,FP_SCR0_EX(%a6) # insert new operand's exponent(=0)
5605
5606 mov.l &0x3ffe,%d0
5607 sub.l %d1,%d0 # scale = BIAS + (-exp)
5608 asr.l &0x1,%d0 # divide scale factor by 2
5609 rts
5610
5611ss_denorm:
5612 lea FP_SCR0(%a6),%a0 # pass ptr to src op
5613 bsr.l norm # normalize denorm
5614
5615 btst &0x0,%d0 # is exp even or odd?
5616 beq.b ss_denorm_even
5617
5618 ori.w &0x3fff,FP_SCR0_EX(%a6) # insert new operand's exponent(=0)
5619
5620 add.l &0x3fff,%d0
5621 asr.l &0x1,%d0 # divide scale factor by 2
5622 rts
5623
5624ss_denorm_even:
5625 ori.w &0x3ffe,FP_SCR0_EX(%a6) # insert new operand's exponent(=0)
5626
5627 add.l &0x3ffe,%d0
5628 asr.l &0x1,%d0 # divide scale factor by 2
5629 rts
5630
5631###
5632
5633#########################################################################
5634# XDEF **************************************************************** #
5635# scale_to_zero_dst(): scale the exponent of extended precision #
5636# value at FP_SCR1(a6). #
5637# #
5638# XREF **************************************************************** #
5639# norm() - normalize the mantissa if the operand was a DENORM #
5640# #
5641# INPUT *************************************************************** #
5642# FP_SCR1(a6) = extended precision operand to be scaled #
5643# #
5644# OUTPUT ************************************************************** #
5645# FP_SCR1(a6) = scaled extended precision operand #
5646# d0 = scale value #
5647# #
5648# ALGORITHM *********************************************************** #
5649# Set the exponent of the input operand to 0x3fff. Save the value #
5650# of the difference between the original and new exponent. Then, #
5651# normalize the operand if it was a DENORM. Add this normalization #
5652# value to the previous value. Return the result. #
5653# #
5654#########################################################################
5655
5656 global scale_to_zero_dst
5657scale_to_zero_dst:
5658 mov.w FP_SCR1_EX(%a6),%d1 # extract operand's {sgn,exp}
5659 mov.w %d1,%d0 # make a copy
5660
5661 andi.l &0x7fff,%d1 # extract operand's exponent
5662
5663 andi.w &0x8000,%d0 # extract operand's sgn
5664 or.w &0x3fff,%d0 # insert new operand's exponent(=0)
5665
5666 mov.w %d0,FP_SCR1_EX(%a6) # insert biased exponent
5667
5668 cmpi.b DTAG(%a6),&DENORM # is operand normalized?
5669 beq.b stzd_denorm # normalize the DENORM
5670
5671stzd_norm:
5672 mov.l &0x3fff,%d0
5673 sub.l %d1,%d0 # scale = BIAS + (-exp)
5674 rts
5675
5676stzd_denorm:
5677 lea FP_SCR1(%a6),%a0 # pass ptr to dst op
5678 bsr.l norm # normalize denorm
5679 neg.l %d0 # new exponent = -(shft val)
5680 mov.l %d0,%d1 # prepare for op_norm call
5681 bra.b stzd_norm # finish scaling
5682
5683##########################################################################
5684
5685#########################################################################
5686# XDEF **************************************************************** #
5687# res_qnan(): return default result w/ QNAN operand for dyadic #
5688# res_snan(): return default result w/ SNAN operand for dyadic #
5689# res_qnan_1op(): return dflt result w/ QNAN operand for monadic #
5690# res_snan_1op(): return dflt result w/ SNAN operand for monadic #
5691# #
5692# XREF **************************************************************** #
5693# None #
5694# #
5695# INPUT *************************************************************** #
5696# FP_SRC(a6) = pointer to extended precision src operand #
5697# FP_DST(a6) = pointer to extended precision dst operand #
5698# #
5699# OUTPUT ************************************************************** #
5700# fp0 = default result #
5701# #
5702# ALGORITHM *********************************************************** #
5703# If either operand (but not both operands) of an operation is a #
5704# nonsignalling NAN, then that NAN is returned as the result. If both #
5705# operands are nonsignalling NANs, then the destination operand #
5706# nonsignalling NAN is returned as the result. #
5707# If either operand to an operation is a signalling NAN (SNAN), #
5708# then, the SNAN bit is set in the FPSR EXC byte. If the SNAN trap #
5709# enable bit is set in the FPCR, then the trap is taken and the #
5710# destination is not modified. If the SNAN trap enable bit is not set, #
5711# then the SNAN is converted to a nonsignalling NAN (by setting the #
5712# SNAN bit in the operand to one), and the operation continues as #
5713# described in the preceding paragraph, for nonsignalling NANs. #
5714# Make sure the appropriate FPSR bits are set before exiting. #
5715# #
5716#########################################################################
5717
5718 global res_qnan
5719 global res_snan
5720res_qnan:
5721res_snan:
5722 cmp.b DTAG(%a6), &SNAN # is the dst an SNAN?
5723 beq.b dst_snan2
5724 cmp.b DTAG(%a6), &QNAN # is the dst a QNAN?
5725 beq.b dst_qnan2
5726src_nan:
5727 cmp.b STAG(%a6), &QNAN
5728 beq.b src_qnan2
5729 global res_snan_1op
5730res_snan_1op:
5731src_snan2:
5732 bset &0x6, FP_SRC_HI(%a6) # set SNAN bit
5733 or.l &nan_mask+aiop_mask+snan_mask, USER_FPSR(%a6)
5734 lea FP_SRC(%a6), %a0
5735 bra.b nan_comp
5736 global res_qnan_1op
5737res_qnan_1op:
5738src_qnan2:
5739 or.l &nan_mask, USER_FPSR(%a6)
5740 lea FP_SRC(%a6), %a0
5741 bra.b nan_comp
5742dst_snan2:
5743 or.l &nan_mask+aiop_mask+snan_mask, USER_FPSR(%a6)
5744 bset &0x6, FP_DST_HI(%a6) # set SNAN bit
5745 lea FP_DST(%a6), %a0
5746 bra.b nan_comp
5747dst_qnan2:
5748 lea FP_DST(%a6), %a0
5749 cmp.b STAG(%a6), &SNAN
5750 bne nan_done
5751 or.l &aiop_mask+snan_mask, USER_FPSR(%a6)
5752nan_done:
5753 or.l &nan_mask, USER_FPSR(%a6)
5754nan_comp:
5755 btst &0x7, FTEMP_EX(%a0) # is NAN neg?
5756 beq.b nan_not_neg
5757 or.l &neg_mask, USER_FPSR(%a6)
5758nan_not_neg:
5759 fmovm.x (%a0), &0x80
5760 rts
5761
5762#########################################################################
5763# XDEF **************************************************************** #
5764# res_operr(): return default result during operand error #
5765# #
5766# XREF **************************************************************** #
5767# None #
5768# #
5769# INPUT *************************************************************** #
5770# None #
5771# #
5772# OUTPUT ************************************************************** #
5773# fp0 = default operand error result #
5774# #
5775# ALGORITHM *********************************************************** #
5776# An nonsignalling NAN is returned as the default result when #
5777# an operand error occurs for the following cases: #
5778# #
5779# Multiply: (Infinity x Zero) #
5780# Divide : (Zero / Zero) || (Infinity / Infinity) #
5781# #
5782#########################################################################
5783
5784 global res_operr
5785res_operr:
5786 or.l &nan_mask+operr_mask+aiop_mask, USER_FPSR(%a6)
5787 fmovm.x nan_return(%pc), &0x80
5788 rts
5789
5790nan_return:
5791 long 0x7fff0000, 0xffffffff, 0xffffffff
5792
5793#########################################################################
5794# XDEF **************************************************************** #
5795# _denorm(): denormalize an intermediate result #
5796# #
5797# XREF **************************************************************** #
5798# None #
5799# #
5800# INPUT *************************************************************** #
5801# a0 = points to the operand to be denormalized #
5802# (in the internal extended format) #
5803# #
5804# d0 = rounding precision #
5805# #
5806# OUTPUT ************************************************************** #
5807# a0 = pointer to the denormalized result #
5808# (in the internal extended format) #
5809# #
5810# d0 = guard,round,sticky #
5811# #
5812# ALGORITHM *********************************************************** #
5813# According to the exponent underflow threshold for the given #
5814# precision, shift the mantissa bits to the right in order raise the #
5815# exponent of the operand to the threshold value. While shifting the #
5816# mantissa bits right, maintain the value of the guard, round, and #
5817# sticky bits. #
5818# other notes: #
5819# (1) _denorm() is called by the underflow routines #
5820# (2) _denorm() does NOT affect the status register #
5821# #
5822#########################################################################
5823
5824#
5825# table of exponent threshold values for each precision
5826#
5827tbl_thresh:
5828 short 0x0
5829 short sgl_thresh
5830 short dbl_thresh
5831
5832 global _denorm
5833_denorm:
5834#
5835# Load the exponent threshold for the precision selected and check
5836# to see if (threshold - exponent) is > 65 in which case we can
5837# simply calculate the sticky bit and zero the mantissa. otherwise
5838# we have to call the denormalization routine.
5839#
5840 lsr.b &0x2, %d0 # shift prec to lo bits
5841 mov.w (tbl_thresh.b,%pc,%d0.w*2), %d1 # load prec threshold
5842 mov.w %d1, %d0 # copy d1 into d0
5843 sub.w FTEMP_EX(%a0), %d0 # diff = threshold - exp
5844 cmpi.w %d0, &66 # is diff > 65? (mant + g,r bits)
5845 bpl.b denorm_set_stky # yes; just calc sticky
5846
5847 clr.l %d0 # clear g,r,s
5848 btst &inex2_bit, FPSR_EXCEPT(%a6) # yes; was INEX2 set?
5849 beq.b denorm_call # no; don't change anything
5850 bset &29, %d0 # yes; set sticky bit
5851
5852denorm_call:
5853 bsr.l dnrm_lp # denormalize the number
5854 rts
5855
5856#
5857# all bit would have been shifted off during the denorm so simply
5858# calculate if the sticky should be set and clear the entire mantissa.
5859#
5860denorm_set_stky:
5861 mov.l &0x20000000, %d0 # set sticky bit in return value
5862 mov.w %d1, FTEMP_EX(%a0) # load exp with threshold
5863 clr.l FTEMP_HI(%a0) # set d1 = 0 (ms mantissa)
5864 clr.l FTEMP_LO(%a0) # set d2 = 0 (ms mantissa)
5865 rts
5866
5867# #
5868# dnrm_lp(): normalize exponent/mantissa to specified threshhold #
5869# #
5870# INPUT: #
5871# %a0 : points to the operand to be denormalized #
5872# %d0{31:29} : initial guard,round,sticky #
5873# %d1{15:0} : denormalization threshold #
5874# OUTPUT: #
5875# %a0 : points to the denormalized operand #
5876# %d0{31:29} : final guard,round,sticky #
5877# #
5878
5879# *** Local Equates *** #
5880set GRS, L_SCR2 # g,r,s temp storage
5881set FTEMP_LO2, L_SCR1 # FTEMP_LO copy
5882
5883 global dnrm_lp
5884dnrm_lp:
5885
5886#
5887# make a copy of FTEMP_LO and place the g,r,s bits directly after it
5888# in memory so as to make the bitfield extraction for denormalization easier.
5889#
5890 mov.l FTEMP_LO(%a0), FTEMP_LO2(%a6) # make FTEMP_LO copy
5891 mov.l %d0, GRS(%a6) # place g,r,s after it
5892
5893#
5894# check to see how much less than the underflow threshold the operand
5895# exponent is.
5896#
5897 mov.l %d1, %d0 # copy the denorm threshold
5898 sub.w FTEMP_EX(%a0), %d1 # d1 = threshold - uns exponent
5899 ble.b dnrm_no_lp # d1 <= 0
5900 cmpi.w %d1, &0x20 # is ( 0 <= d1 < 32) ?
5901 blt.b case_1 # yes
5902 cmpi.w %d1, &0x40 # is (32 <= d1 < 64) ?
5903 blt.b case_2 # yes
5904 bra.w case_3 # (d1 >= 64)
5905
5906#
5907# No normalization necessary
5908#
5909dnrm_no_lp:
5910 mov.l GRS(%a6), %d0 # restore original g,r,s
5911 rts
5912
5913#
5914# case (0<d1<32)
5915#
5916# %d0 = denorm threshold
5917# %d1 = "n" = amt to shift
5918#
5919# ---------------------------------------------------------
5920# | FTEMP_HI | FTEMP_LO |grs000.........000|
5921# ---------------------------------------------------------
5922# <-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)->
5923# \ \ \ \
5924# \ \ \ \
5925# \ \ \ \
5926# \ \ \ \
5927# \ \ \ \
5928# \ \ \ \
5929# \ \ \ \
5930# \ \ \ \
5931# <-(n)-><-(32 - n)-><------(32)-------><------(32)------->
5932# ---------------------------------------------------------
5933# |0.....0| NEW_HI | NEW_FTEMP_LO |grs |
5934# ---------------------------------------------------------
5935#
5936case_1:
5937 mov.l %d2, -(%sp) # create temp storage
5938
5939 mov.w %d0, FTEMP_EX(%a0) # exponent = denorm threshold
5940 mov.l &32, %d0
5941 sub.w %d1, %d0 # %d0 = 32 - %d1
5942
5943 cmpi.w %d1, &29 # is shft amt >= 29
5944 blt.b case1_extract # no; no fix needed
5945 mov.b GRS(%a6), %d2
5946 or.b %d2, 3+FTEMP_LO2(%a6)
5947
5948case1_extract:
5949 bfextu FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_HI
5950 bfextu FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new FTEMP_LO
5951 bfextu FTEMP_LO2(%a6){%d0:&32}, %d0 # %d0 = new G,R,S
5952
5953 mov.l %d2, FTEMP_HI(%a0) # store new FTEMP_HI
5954 mov.l %d1, FTEMP_LO(%a0) # store new FTEMP_LO
5955
5956 bftst %d0{&2:&30} # were bits shifted off?
5957 beq.b case1_sticky_clear # no; go finish
5958 bset &rnd_stky_bit, %d0 # yes; set sticky bit
5959
5960case1_sticky_clear:
5961 and.l &0xe0000000, %d0 # clear all but G,R,S
5962 mov.l (%sp)+, %d2 # restore temp register
5963 rts
5964
5965#
5966# case (32<=d1<64)
5967#
5968# %d0 = denorm threshold
5969# %d1 = "n" = amt to shift
5970#
5971# ---------------------------------------------------------
5972# | FTEMP_HI | FTEMP_LO |grs000.........000|
5973# ---------------------------------------------------------
5974# <-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)->
5975# \ \ \
5976# \ \ \
5977# \ \ -------------------
5978# \ -------------------- \
5979# ------------------- \ \
5980# \ \ \
5981# \ \ \
5982# \ \ \
5983# <-------(32)------><-(n)-><-(32 - n)-><------(32)------->
5984# ---------------------------------------------------------
5985# |0...............0|0....0| NEW_LO |grs |
5986# ---------------------------------------------------------
5987#
5988case_2:
5989 mov.l %d2, -(%sp) # create temp storage
5990
5991 mov.w %d0, FTEMP_EX(%a0) # exponent = denorm threshold
5992 subi.w &0x20, %d1 # %d1 now between 0 and 32
5993 mov.l &0x20, %d0
5994 sub.w %d1, %d0 # %d0 = 32 - %d1
5995
5996# subtle step here; or in the g,r,s at the bottom of FTEMP_LO to minimize
5997# the number of bits to check for the sticky detect.
5998# it only plays a role in shift amounts of 61-63.
5999 mov.b GRS(%a6), %d2
6000 or.b %d2, 3+FTEMP_LO2(%a6)
6001
6002 bfextu FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_LO
6003 bfextu FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new G,R,S
6004
6005 bftst %d1{&2:&30} # were any bits shifted off?
6006 bne.b case2_set_sticky # yes; set sticky bit
6007 bftst FTEMP_LO2(%a6){%d0:&31} # were any bits shifted off?
6008 bne.b case2_set_sticky # yes; set sticky bit
6009
6010 mov.l %d1, %d0 # move new G,R,S to %d0
6011 bra.b case2_end
6012
6013case2_set_sticky:
6014 mov.l %d1, %d0 # move new G,R,S to %d0
6015 bset &rnd_stky_bit, %d0 # set sticky bit
6016
6017case2_end:
6018 clr.l FTEMP_HI(%a0) # store FTEMP_HI = 0
6019 mov.l %d2, FTEMP_LO(%a0) # store FTEMP_LO
6020 and.l &0xe0000000, %d0 # clear all but G,R,S
6021
6022 mov.l (%sp)+,%d2 # restore temp register
6023 rts
6024
6025#
6026# case (d1>=64)
6027#
6028# %d0 = denorm threshold
6029# %d1 = amt to shift
6030#
6031case_3:
6032 mov.w %d0, FTEMP_EX(%a0) # insert denorm threshold
6033
6034 cmpi.w %d1, &65 # is shift amt > 65?
6035 blt.b case3_64 # no; it's == 64
6036 beq.b case3_65 # no; it's == 65
6037
6038#
6039# case (d1>65)
6040#
6041# Shift value is > 65 and out of range. All bits are shifted off.
6042# Return a zero mantissa with the sticky bit set
6043#
6044 clr.l FTEMP_HI(%a0) # clear hi(mantissa)
6045 clr.l FTEMP_LO(%a0) # clear lo(mantissa)
6046 mov.l &0x20000000, %d0 # set sticky bit
6047 rts
6048
6049#
6050# case (d1 == 64)
6051#
6052# ---------------------------------------------------------
6053# | FTEMP_HI | FTEMP_LO |grs000.........000|
6054# ---------------------------------------------------------
6055# <-------(32)------>
6056# \ \
6057# \ \
6058# \ \
6059# \ ------------------------------
6060# ------------------------------- \
6061# \ \
6062# \ \
6063# \ \
6064# <-------(32)------>
6065# ---------------------------------------------------------
6066# |0...............0|0................0|grs |
6067# ---------------------------------------------------------
6068#
6069case3_64:
6070 mov.l FTEMP_HI(%a0), %d0 # fetch hi(mantissa)
6071 mov.l %d0, %d1 # make a copy
6072 and.l &0xc0000000, %d0 # extract G,R
6073 and.l &0x3fffffff, %d1 # extract other bits
6074
6075 bra.b case3_complete
6076
6077#
6078# case (d1 == 65)
6079#
6080# ---------------------------------------------------------
6081# | FTEMP_HI | FTEMP_LO |grs000.........000|
6082# ---------------------------------------------------------
6083# <-------(32)------>
6084# \ \
6085# \ \
6086# \ \
6087# \ ------------------------------
6088# -------------------------------- \
6089# \ \
6090# \ \
6091# \ \
6092# <-------(31)----->
6093# ---------------------------------------------------------
6094# |0...............0|0................0|0rs |
6095# ---------------------------------------------------------
6096#
6097case3_65:
6098 mov.l FTEMP_HI(%a0), %d0 # fetch hi(mantissa)
6099 and.l &0x80000000, %d0 # extract R bit
6100 lsr.l &0x1, %d0 # shift high bit into R bit
6101 and.l &0x7fffffff, %d1 # extract other bits
6102
6103case3_complete:
6104# last operation done was an "and" of the bits shifted off so the condition
6105# codes are already set so branch accordingly.
6106 bne.b case3_set_sticky # yes; go set new sticky
6107 tst.l FTEMP_LO(%a0) # were any bits shifted off?
6108 bne.b case3_set_sticky # yes; go set new sticky
6109 tst.b GRS(%a6) # were any bits shifted off?
6110 bne.b case3_set_sticky # yes; go set new sticky
6111
6112#
6113# no bits were shifted off so don't set the sticky bit.
6114# the guard and
6115# the entire mantissa is zero.
6116#
6117 clr.l FTEMP_HI(%a0) # clear hi(mantissa)
6118 clr.l FTEMP_LO(%a0) # clear lo(mantissa)
6119 rts
6120
6121#
6122# some bits were shifted off so set the sticky bit.
6123# the entire mantissa is zero.
6124#
6125case3_set_sticky:
6126 bset &rnd_stky_bit,%d0 # set new sticky bit
6127 clr.l FTEMP_HI(%a0) # clear hi(mantissa)
6128 clr.l FTEMP_LO(%a0) # clear lo(mantissa)
6129 rts
6130
6131#########################################################################
6132# XDEF **************************************************************** #
6133# _round(): round result according to precision/mode #
6134# #
6135# XREF **************************************************************** #
6136# None #
6137# #
6138# INPUT *************************************************************** #
6139# a0 = ptr to input operand in internal extended format #
6140# d1(hi) = contains rounding precision: #
6141# ext = $0000xxxx #
6142# sgl = $0004xxxx #
6143# dbl = $0008xxxx #
6144# d1(lo) = contains rounding mode: #
6145# RN = $xxxx0000 #
6146# RZ = $xxxx0001 #
6147# RM = $xxxx0002 #
6148# RP = $xxxx0003 #
6149# d0{31:29} = contains the g,r,s bits (extended) #
6150# #
6151# OUTPUT ************************************************************** #
6152# a0 = pointer to rounded result #
6153# #
6154# ALGORITHM *********************************************************** #
6155# On return the value pointed to by a0 is correctly rounded, #
6156# a0 is preserved and the g-r-s bits in d0 are cleared. #
6157# The result is not typed - the tag field is invalid. The #
6158# result is still in the internal extended format. #
6159# #
6160# The INEX bit of USER_FPSR will be set if the rounded result was #
6161# inexact (i.e. if any of the g-r-s bits were set). #
6162# #
6163#########################################################################
6164
6165 global _round
6166_round:
6167#
6168# ext_grs() looks at the rounding precision and sets the appropriate
6169# G,R,S bits.
6170# If (G,R,S == 0) then result is exact and round is done, else set
6171# the inex flag in status reg and continue.
6172#
6173 bsr.l ext_grs # extract G,R,S
6174
6175 tst.l %d0 # are G,R,S zero?
6176 beq.w truncate # yes; round is complete
6177
6178 or.w &inx2a_mask, 2+USER_FPSR(%a6) # set inex2/ainex
6179
6180#
6181# Use rounding mode as an index into a jump table for these modes.
6182# All of the following assumes grs != 0.
6183#
6184 mov.w (tbl_mode.b,%pc,%d1.w*2), %a1 # load jump offset
6185 jmp (tbl_mode.b,%pc,%a1) # jmp to rnd mode handler
6186
6187tbl_mode:
6188 short rnd_near - tbl_mode
6189 short truncate - tbl_mode # RZ always truncates
6190 short rnd_mnus - tbl_mode
6191 short rnd_plus - tbl_mode
6192
6193#################################################################
6194# ROUND PLUS INFINITY #
6195# #
6196# If sign of fp number = 0 (positive), then add 1 to l. #
6197#################################################################
6198rnd_plus:
6199 tst.b FTEMP_SGN(%a0) # check for sign
6200 bmi.w truncate # if positive then truncate
6201
6202 mov.l &0xffffffff, %d0 # force g,r,s to be all f's
6203 swap %d1 # set up d1 for round prec.
6204
6205 cmpi.b %d1, &s_mode # is prec = sgl?
6206 beq.w add_sgl # yes
6207 bgt.w add_dbl # no; it's dbl
6208 bra.w add_ext # no; it's ext
6209
6210#################################################################
6211# ROUND MINUS INFINITY #
6212# #
6213# If sign of fp number = 1 (negative), then add 1 to l. #
6214#################################################################
6215rnd_mnus:
6216 tst.b FTEMP_SGN(%a0) # check for sign
6217 bpl.w truncate # if negative then truncate
6218
6219 mov.l &0xffffffff, %d0 # force g,r,s to be all f's
6220 swap %d1 # set up d1 for round prec.
6221
6222 cmpi.b %d1, &s_mode # is prec = sgl?
6223 beq.w add_sgl # yes
6224 bgt.w add_dbl # no; it's dbl
6225 bra.w add_ext # no; it's ext
6226
6227#################################################################
6228# ROUND NEAREST #
6229# #
6230# If (g=1), then add 1 to l and if (r=s=0), then clear l #
6231# Note that this will round to even in case of a tie. #
6232#################################################################
6233rnd_near:
6234 asl.l &0x1, %d0 # shift g-bit to c-bit
6235 bcc.w truncate # if (g=1) then
6236
6237 swap %d1 # set up d1 for round prec.
6238
6239 cmpi.b %d1, &s_mode # is prec = sgl?
6240 beq.w add_sgl # yes
6241 bgt.w add_dbl # no; it's dbl
6242 bra.w add_ext # no; it's ext
6243
6244# *** LOCAL EQUATES ***
6245set ad_1_sgl, 0x00000100 # constant to add 1 to l-bit in sgl prec
6246set ad_1_dbl, 0x00000800 # constant to add 1 to l-bit in dbl prec
6247
6248#########################
6249# ADD SINGLE #
6250#########################
6251add_sgl:
6252 add.l &ad_1_sgl, FTEMP_HI(%a0)
6253 bcc.b scc_clr # no mantissa overflow
6254 roxr.w FTEMP_HI(%a0) # shift v-bit back in
6255 roxr.w FTEMP_HI+2(%a0) # shift v-bit back in
6256 add.w &0x1, FTEMP_EX(%a0) # and incr exponent
6257scc_clr:
6258 tst.l %d0 # test for rs = 0
6259 bne.b sgl_done
6260 and.w &0xfe00, FTEMP_HI+2(%a0) # clear the l-bit
6261sgl_done:
6262 and.l &0xffffff00, FTEMP_HI(%a0) # truncate bits beyond sgl limit
6263 clr.l FTEMP_LO(%a0) # clear d2
6264 rts
6265
6266#########################
6267# ADD EXTENDED #
6268#########################
6269add_ext:
6270 addq.l &1,FTEMP_LO(%a0) # add 1 to l-bit
6271 bcc.b xcc_clr # test for carry out
6272 addq.l &1,FTEMP_HI(%a0) # propagate carry
6273 bcc.b xcc_clr
6274 roxr.w FTEMP_HI(%a0) # mant is 0 so restore v-bit
6275 roxr.w FTEMP_HI+2(%a0) # mant is 0 so restore v-bit
6276 roxr.w FTEMP_LO(%a0)
6277 roxr.w FTEMP_LO+2(%a0)
6278 add.w &0x1,FTEMP_EX(%a0) # and inc exp
6279xcc_clr:
6280 tst.l %d0 # test rs = 0
6281 bne.b add_ext_done
6282 and.b &0xfe,FTEMP_LO+3(%a0) # clear the l bit
6283add_ext_done:
6284 rts
6285
6286#########################
6287# ADD DOUBLE #
6288#########################
6289add_dbl:
6290 add.l &ad_1_dbl, FTEMP_LO(%a0) # add 1 to lsb
6291 bcc.b dcc_clr # no carry
6292 addq.l &0x1, FTEMP_HI(%a0) # propagate carry
6293 bcc.b dcc_clr # no carry
6294
6295 roxr.w FTEMP_HI(%a0) # mant is 0 so restore v-bit
6296 roxr.w FTEMP_HI+2(%a0) # mant is 0 so restore v-bit
6297 roxr.w FTEMP_LO(%a0)
6298 roxr.w FTEMP_LO+2(%a0)
6299 addq.w &0x1, FTEMP_EX(%a0) # incr exponent
6300dcc_clr:
6301 tst.l %d0 # test for rs = 0
6302 bne.b dbl_done
6303 and.w &0xf000, FTEMP_LO+2(%a0) # clear the l-bit
6304
6305dbl_done:
6306 and.l &0xfffff800,FTEMP_LO(%a0) # truncate bits beyond dbl limit
6307 rts
6308
6309###########################
6310# Truncate all other bits #
6311###########################
6312truncate:
6313 swap %d1 # select rnd prec
6314
6315 cmpi.b %d1, &s_mode # is prec sgl?
6316 beq.w sgl_done # yes
6317 bgt.b dbl_done # no; it's dbl
6318 rts # no; it's ext
6319
6320
6321#
6322# ext_grs(): extract guard, round and sticky bits according to
6323# rounding precision.
6324#
6325# INPUT
6326# d0 = extended precision g,r,s (in d0{31:29})
6327# d1 = {PREC,ROUND}
6328# OUTPUT
6329# d0{31:29} = guard, round, sticky
6330#
6331# The ext_grs extract the guard/round/sticky bits according to the
6332# selected rounding precision. It is called by the round subroutine
6333# only. All registers except d0 are kept intact. d0 becomes an
6334# updated guard,round,sticky in d0{31:29}
6335#
6336# Notes: the ext_grs uses the round PREC, and therefore has to swap d1
6337# prior to usage, and needs to restore d1 to original. this
6338# routine is tightly tied to the round routine and not meant to
6339# uphold standard subroutine calling practices.
6340#
6341
6342ext_grs:
6343 swap %d1 # have d1.w point to round precision
6344 tst.b %d1 # is rnd prec = extended?
6345 bne.b ext_grs_not_ext # no; go handle sgl or dbl
6346
6347#
6348# %d0 actually already hold g,r,s since _round() had it before calling
6349# this function. so, as long as we don't disturb it, we are "returning" it.
6350#
6351ext_grs_ext:
6352 swap %d1 # yes; return to correct positions
6353 rts
6354
6355ext_grs_not_ext:
6356 movm.l &0x3000, -(%sp) # make some temp registers {d2/d3}
6357
6358 cmpi.b %d1, &s_mode # is rnd prec = sgl?
6359 bne.b ext_grs_dbl # no; go handle dbl
6360
6361#
6362# sgl:
6363# 96 64 40 32 0
6364# -----------------------------------------------------
6365# | EXP |XXXXXXX| |xx | |grs|
6366# -----------------------------------------------------
6367# <--(24)--->nn\ /
6368# ee ---------------------
6369# ww |
6370# v
6371# gr new sticky
6372#
6373ext_grs_sgl:
6374 bfextu FTEMP_HI(%a0){&24:&2}, %d3 # sgl prec. g-r are 2 bits right
6375 mov.l &30, %d2 # of the sgl prec. limits
6376 lsl.l %d2, %d3 # shift g-r bits to MSB of d3
6377 mov.l FTEMP_HI(%a0), %d2 # get word 2 for s-bit test
6378 and.l &0x0000003f, %d2 # s bit is the or of all other
6379 bne.b ext_grs_st_stky # bits to the right of g-r
6380 tst.l FTEMP_LO(%a0) # test lower mantissa
6381 bne.b ext_grs_st_stky # if any are set, set sticky
6382 tst.l %d0 # test original g,r,s
6383 bne.b ext_grs_st_stky # if any are set, set sticky
6384 bra.b ext_grs_end_sd # if words 3 and 4 are clr, exit
6385
6386#
6387# dbl:
6388# 96 64 32 11 0
6389# -----------------------------------------------------
6390# | EXP |XXXXXXX| | |xx |grs|
6391# -----------------------------------------------------
6392# nn\ /
6393# ee -------
6394# ww |
6395# v
6396# gr new sticky
6397#
6398ext_grs_dbl:
6399 bfextu FTEMP_LO(%a0){&21:&2}, %d3 # dbl-prec. g-r are 2 bits right
6400 mov.l &30, %d2 # of the dbl prec. limits
6401 lsl.l %d2, %d3 # shift g-r bits to the MSB of d3
6402 mov.l FTEMP_LO(%a0), %d2 # get lower mantissa for s-bit test
6403 and.l &0x000001ff, %d2 # s bit is the or-ing of all
6404 bne.b ext_grs_st_stky # other bits to the right of g-r
6405 tst.l %d0 # test word original g,r,s
6406 bne.b ext_grs_st_stky # if any are set, set sticky
6407 bra.b ext_grs_end_sd # if clear, exit
6408
6409ext_grs_st_stky:
6410 bset &rnd_stky_bit, %d3 # set sticky bit
6411ext_grs_end_sd:
6412 mov.l %d3, %d0 # return grs to d0
6413
6414 movm.l (%sp)+, &0xc # restore scratch registers {d2/d3}
6415
6416 swap %d1 # restore d1 to original
6417 rts
6418
6419#########################################################################
6420# norm(): normalize the mantissa of an extended precision input. the #
6421# input operand should not be normalized already. #
6422# #
6423# XDEF **************************************************************** #
6424# norm() #
6425# #
6426# XREF **************************************************************** #
6427# none #
6428# #
6429# INPUT *************************************************************** #
6430# a0 = pointer fp extended precision operand to normalize #
6431# #
6432# OUTPUT ************************************************************** #
6433# d0 = number of bit positions the mantissa was shifted #
6434# a0 = the input operand's mantissa is normalized; the exponent #
6435# is unchanged. #
6436# #
6437#########################################################################
6438 global norm
6439norm:
6440 mov.l %d2, -(%sp) # create some temp regs
6441 mov.l %d3, -(%sp)
6442
6443 mov.l FTEMP_HI(%a0), %d0 # load hi(mantissa)
6444 mov.l FTEMP_LO(%a0), %d1 # load lo(mantissa)
6445
6446 bfffo %d0{&0:&32}, %d2 # how many places to shift?
6447 beq.b norm_lo # hi(man) is all zeroes!
6448
6449norm_hi:
6450 lsl.l %d2, %d0 # left shift hi(man)
6451 bfextu %d1{&0:%d2}, %d3 # extract lo bits
6452
6453 or.l %d3, %d0 # create hi(man)
6454 lsl.l %d2, %d1 # create lo(man)
6455
6456 mov.l %d0, FTEMP_HI(%a0) # store new hi(man)
6457 mov.l %d1, FTEMP_LO(%a0) # store new lo(man)
6458
6459 mov.l %d2, %d0 # return shift amount
6460
6461 mov.l (%sp)+, %d3 # restore temp regs
6462 mov.l (%sp)+, %d2
6463
6464 rts
6465
6466norm_lo:
6467 bfffo %d1{&0:&32}, %d2 # how many places to shift?
6468 lsl.l %d2, %d1 # shift lo(man)
6469 add.l &32, %d2 # add 32 to shft amount
6470
6471 mov.l %d1, FTEMP_HI(%a0) # store hi(man)
6472 clr.l FTEMP_LO(%a0) # lo(man) is now zero
6473
6474 mov.l %d2, %d0 # return shift amount
6475
6476 mov.l (%sp)+, %d3 # restore temp regs
6477 mov.l (%sp)+, %d2
6478
6479 rts
6480
6481#########################################################################
6482# unnorm_fix(): - changes an UNNORM to one of NORM, DENORM, or ZERO #
6483# - returns corresponding optype tag #
6484# #
6485# XDEF **************************************************************** #
6486# unnorm_fix() #
6487# #
6488# XREF **************************************************************** #
6489# norm() - normalize the mantissa #
6490# #
6491# INPUT *************************************************************** #
6492# a0 = pointer to unnormalized extended precision number #
6493# #
6494# OUTPUT ************************************************************** #
6495# d0 = optype tag - is corrected to one of NORM, DENORM, or ZERO #
6496# a0 = input operand has been converted to a norm, denorm, or #
6497# zero; both the exponent and mantissa are changed. #
6498# #
6499#########################################################################
6500
6501 global unnorm_fix
6502unnorm_fix:
6503 bfffo FTEMP_HI(%a0){&0:&32}, %d0 # how many shifts are needed?
6504 bne.b unnorm_shift # hi(man) is not all zeroes
6505
6506#
6507# hi(man) is all zeroes so see if any bits in lo(man) are set
6508#
6509unnorm_chk_lo:
6510 bfffo FTEMP_LO(%a0){&0:&32}, %d0 # is operand really a zero?
6511 beq.w unnorm_zero # yes
6512
6513 add.w &32, %d0 # no; fix shift distance
6514
6515#
6516# d0 = # shifts needed for complete normalization
6517#
6518unnorm_shift:
6519 clr.l %d1 # clear top word
6520 mov.w FTEMP_EX(%a0), %d1 # extract exponent
6521 and.w &0x7fff, %d1 # strip off sgn
6522
6523 cmp.w %d0, %d1 # will denorm push exp < 0?
6524 bgt.b unnorm_nrm_zero # yes; denorm only until exp = 0
6525
6526#
6527# exponent would not go < 0. therefore, number stays normalized
6528#
6529 sub.w %d0, %d1 # shift exponent value
6530 mov.w FTEMP_EX(%a0), %d0 # load old exponent
6531 and.w &0x8000, %d0 # save old sign
6532 or.w %d0, %d1 # {sgn,new exp}
6533 mov.w %d1, FTEMP_EX(%a0) # insert new exponent
6534
6535 bsr.l norm # normalize UNNORM
6536
6537 mov.b &NORM, %d0 # return new optype tag
6538 rts
6539
6540#
6541# exponent would go < 0, so only denormalize until exp = 0
6542#
6543unnorm_nrm_zero:
6544 cmp.b %d1, &32 # is exp <= 32?
6545 bgt.b unnorm_nrm_zero_lrg # no; go handle large exponent
6546
6547 bfextu FTEMP_HI(%a0){%d1:&32}, %d0 # extract new hi(man)
6548 mov.l %d0, FTEMP_HI(%a0) # save new hi(man)
6549
6550 mov.l FTEMP_LO(%a0), %d0 # fetch old lo(man)
6551 lsl.l %d1, %d0 # extract new lo(man)
6552 mov.l %d0, FTEMP_LO(%a0) # save new lo(man)
6553
6554 and.w &0x8000, FTEMP_EX(%a0) # set exp = 0
6555
6556 mov.b &DENORM, %d0 # return new optype tag
6557 rts
6558
6559#
6560# only mantissa bits set are in lo(man)
6561#
6562unnorm_nrm_zero_lrg:
6563 sub.w &32, %d1 # adjust shft amt by 32
6564
6565 mov.l FTEMP_LO(%a0), %d0 # fetch old lo(man)
6566 lsl.l %d1, %d0 # left shift lo(man)
6567
6568 mov.l %d0, FTEMP_HI(%a0) # store new hi(man)
6569 clr.l FTEMP_LO(%a0) # lo(man) = 0
6570
6571 and.w &0x8000, FTEMP_EX(%a0) # set exp = 0
6572
6573 mov.b &DENORM, %d0 # return new optype tag
6574 rts
6575
6576#
6577# whole mantissa is zero so this UNNORM is actually a zero
6578#
6579unnorm_zero:
6580 and.w &0x8000, FTEMP_EX(%a0) # force exponent to zero
6581
6582 mov.b &ZERO, %d0 # fix optype tag
6583 rts
6584
6585#########################################################################
6586# XDEF **************************************************************** #
6587# set_tag_x(): return the optype of the input ext fp number #
6588# #
6589# XREF **************************************************************** #
6590# None #
6591# #
6592# INPUT *************************************************************** #
6593# a0 = pointer to extended precision operand #
6594# #
6595# OUTPUT ************************************************************** #
6596# d0 = value of type tag #
6597# one of: NORM, INF, QNAN, SNAN, DENORM, UNNORM, ZERO #
6598# #
6599# ALGORITHM *********************************************************** #
6600# Simply test the exponent, j-bit, and mantissa values to #
6601# determine the type of operand. #
6602# If it's an unnormalized zero, alter the operand and force it #
6603# to be a normal zero. #
6604# #
6605#########################################################################
6606
6607 global set_tag_x
6608set_tag_x:
6609 mov.w FTEMP_EX(%a0), %d0 # extract exponent
6610 andi.w &0x7fff, %d0 # strip off sign
6611 cmpi.w %d0, &0x7fff # is (EXP == MAX)?
6612 beq.b inf_or_nan_x
6613not_inf_or_nan_x:
6614 btst &0x7,FTEMP_HI(%a0)
6615 beq.b not_norm_x
6616is_norm_x:
6617 mov.b &NORM, %d0
6618 rts
6619not_norm_x:
6620 tst.w %d0 # is exponent = 0?
6621 bne.b is_unnorm_x
6622not_unnorm_x:
6623 tst.l FTEMP_HI(%a0)
6624 bne.b is_denorm_x
6625 tst.l FTEMP_LO(%a0)
6626 bne.b is_denorm_x
6627is_zero_x:
6628 mov.b &ZERO, %d0
6629 rts
6630is_denorm_x:
6631 mov.b &DENORM, %d0
6632 rts
6633# must distinguish now "Unnormalized zeroes" which we
6634# must convert to zero.
6635is_unnorm_x:
6636 tst.l FTEMP_HI(%a0)
6637 bne.b is_unnorm_reg_x
6638 tst.l FTEMP_LO(%a0)
6639 bne.b is_unnorm_reg_x
6640# it's an "unnormalized zero". let's convert it to an actual zero...
6641 andi.w &0x8000,FTEMP_EX(%a0) # clear exponent
6642 mov.b &ZERO, %d0
6643 rts
6644is_unnorm_reg_x:
6645 mov.b &UNNORM, %d0
6646 rts
6647inf_or_nan_x:
6648 tst.l FTEMP_LO(%a0)
6649 bne.b is_nan_x
6650 mov.l FTEMP_HI(%a0), %d0
6651 and.l &0x7fffffff, %d0 # msb is a don't care!
6652 bne.b is_nan_x
6653is_inf_x:
6654 mov.b &INF, %d0
6655 rts
6656is_nan_x:
6657 btst &0x6, FTEMP_HI(%a0)
6658 beq.b is_snan_x
6659 mov.b &QNAN, %d0
6660 rts
6661is_snan_x:
6662 mov.b &SNAN, %d0
6663 rts
6664
6665#########################################################################
6666# XDEF **************************************************************** #
6667# set_tag_d(): return the optype of the input dbl fp number #
6668# #
6669# XREF **************************************************************** #
6670# None #
6671# #
6672# INPUT *************************************************************** #
6673# a0 = points to double precision operand #
6674# #
6675# OUTPUT ************************************************************** #
6676# d0 = value of type tag #
6677# one of: NORM, INF, QNAN, SNAN, DENORM, ZERO #
6678# #
6679# ALGORITHM *********************************************************** #
6680# Simply test the exponent, j-bit, and mantissa values to #
6681# determine the type of operand. #
6682# #
6683#########################################################################
6684
6685 global set_tag_d
6686set_tag_d:
6687 mov.l FTEMP(%a0), %d0
6688 mov.l %d0, %d1
6689
6690 andi.l &0x7ff00000, %d0
6691 beq.b zero_or_denorm_d
6692
6693 cmpi.l %d0, &0x7ff00000
6694 beq.b inf_or_nan_d
6695
6696is_norm_d:
6697 mov.b &NORM, %d0
6698 rts
6699zero_or_denorm_d:
6700 and.l &0x000fffff, %d1
6701 bne is_denorm_d
6702 tst.l 4+FTEMP(%a0)
6703 bne is_denorm_d
6704is_zero_d:
6705 mov.b &ZERO, %d0
6706 rts
6707is_denorm_d:
6708 mov.b &DENORM, %d0
6709 rts
6710inf_or_nan_d:
6711 and.l &0x000fffff, %d1
6712 bne is_nan_d
6713 tst.l 4+FTEMP(%a0)
6714 bne is_nan_d
6715is_inf_d:
6716 mov.b &INF, %d0
6717 rts
6718is_nan_d:
6719 btst &19, %d1
6720 bne is_qnan_d
6721is_snan_d:
6722 mov.b &SNAN, %d0
6723 rts
6724is_qnan_d:
6725 mov.b &QNAN, %d0
6726 rts
6727
6728#########################################################################
6729# XDEF **************************************************************** #
6730# set_tag_s(): return the optype of the input sgl fp number #
6731# #
6732# XREF **************************************************************** #
6733# None #
6734# #
6735# INPUT *************************************************************** #
6736# a0 = pointer to single precision operand #
6737# #
6738# OUTPUT ************************************************************** #
6739# d0 = value of type tag #
6740# one of: NORM, INF, QNAN, SNAN, DENORM, ZERO #
6741# #
6742# ALGORITHM *********************************************************** #
6743# Simply test the exponent, j-bit, and mantissa values to #
6744# determine the type of operand. #
6745# #
6746#########################################################################
6747
6748 global set_tag_s
6749set_tag_s:
6750 mov.l FTEMP(%a0), %d0
6751 mov.l %d0, %d1
6752
6753 andi.l &0x7f800000, %d0
6754 beq.b zero_or_denorm_s
6755
6756 cmpi.l %d0, &0x7f800000
6757 beq.b inf_or_nan_s
6758
6759is_norm_s:
6760 mov.b &NORM, %d0
6761 rts
6762zero_or_denorm_s:
6763 and.l &0x007fffff, %d1
6764 bne is_denorm_s
6765is_zero_s:
6766 mov.b &ZERO, %d0
6767 rts
6768is_denorm_s:
6769 mov.b &DENORM, %d0
6770 rts
6771inf_or_nan_s:
6772 and.l &0x007fffff, %d1
6773 bne is_nan_s
6774is_inf_s:
6775 mov.b &INF, %d0
6776 rts
6777is_nan_s:
6778 btst &22, %d1
6779 bne is_qnan_s
6780is_snan_s:
6781 mov.b &SNAN, %d0
6782 rts
6783is_qnan_s:
6784 mov.b &QNAN, %d0
6785 rts
6786
6787#########################################################################
6788# XDEF **************************************************************** #
6789# unf_res(): routine to produce default underflow result of a #
6790# scaled extended precision number; this is used by #
6791# fadd/fdiv/fmul/etc. emulation routines. #
6792# unf_res4(): same as above but for fsglmul/fsgldiv which use #
6793# single round prec and extended prec mode. #
6794# #
6795# XREF **************************************************************** #
6796# _denorm() - denormalize according to scale factor #
6797# _round() - round denormalized number according to rnd prec #
6798# #
6799# INPUT *************************************************************** #
6800# a0 = pointer to extended precison operand #
6801# d0 = scale factor #
6802# d1 = rounding precision/mode #
6803# #
6804# OUTPUT ************************************************************** #
6805# a0 = pointer to default underflow result in extended precision #
6806# d0.b = result FPSR_cc which caller may or may not want to save #
6807# #
6808# ALGORITHM *********************************************************** #
6809# Convert the input operand to "internal format" which means the #
6810# exponent is extended to 16 bits and the sign is stored in the unused #
6811# portion of the extended precison operand. Denormalize the number #
6812# according to the scale factor passed in d0. Then, round the #
6813# denormalized result. #
6814# Set the FPSR_exc bits as appropriate but return the cc bits in #
6815# d0 in case the caller doesn't want to save them (as is the case for #
6816# fmove out). #
6817# unf_res4() for fsglmul/fsgldiv forces the denorm to extended #
6818# precision and the rounding mode to single. #
6819# #
6820#########################################################################
6821 global unf_res
6822unf_res:
6823 mov.l %d1, -(%sp) # save rnd prec,mode on stack
6824
6825 btst &0x7, FTEMP_EX(%a0) # make "internal" format
6826 sne FTEMP_SGN(%a0)
6827
6828 mov.w FTEMP_EX(%a0), %d1 # extract exponent
6829 and.w &0x7fff, %d1
6830 sub.w %d0, %d1
6831 mov.w %d1, FTEMP_EX(%a0) # insert 16 bit exponent
6832
6833 mov.l %a0, -(%sp) # save operand ptr during calls
6834
6835 mov.l 0x4(%sp),%d0 # pass rnd prec.
6836 andi.w &0x00c0,%d0
6837 lsr.w &0x4,%d0
6838 bsr.l _denorm # denorm result
6839
6840 mov.l (%sp),%a0
6841 mov.w 0x6(%sp),%d1 # load prec:mode into %d1
6842 andi.w &0xc0,%d1 # extract rnd prec
6843 lsr.w &0x4,%d1
6844 swap %d1
6845 mov.w 0x6(%sp),%d1
6846 andi.w &0x30,%d1
6847 lsr.w &0x4,%d1
6848 bsr.l _round # round the denorm
6849
6850 mov.l (%sp)+, %a0
6851
6852# result is now rounded properly. convert back to normal format
6853 bclr &0x7, FTEMP_EX(%a0) # clear sgn first; may have residue
6854 tst.b FTEMP_SGN(%a0) # is "internal result" sign set?
6855 beq.b unf_res_chkifzero # no; result is positive
6856 bset &0x7, FTEMP_EX(%a0) # set result sgn
6857 clr.b FTEMP_SGN(%a0) # clear temp sign
6858
6859# the number may have become zero after rounding. set ccodes accordingly.
6860unf_res_chkifzero:
6861 clr.l %d0
6862 tst.l FTEMP_HI(%a0) # is value now a zero?
6863 bne.b unf_res_cont # no
6864 tst.l FTEMP_LO(%a0)
6865 bne.b unf_res_cont # no
6866# bset &z_bit, FPSR_CC(%a6) # yes; set zero ccode bit
6867 bset &z_bit, %d0 # yes; set zero ccode bit
6868
6869unf_res_cont:
6870
6871#
6872# can inex1 also be set along with unfl and inex2???
6873#
6874# we know that underflow has occurred. aunfl should be set if INEX2 is also set.
6875#
6876 btst &inex2_bit, FPSR_EXCEPT(%a6) # is INEX2 set?
6877 beq.b unf_res_end # no
6878 bset &aunfl_bit, FPSR_AEXCEPT(%a6) # yes; set aunfl
6879
6880unf_res_end:
6881 add.l &0x4, %sp # clear stack
6882 rts
6883
6884# unf_res() for fsglmul() and fsgldiv().
6885 global unf_res4
6886unf_res4:
6887 mov.l %d1,-(%sp) # save rnd prec,mode on stack
6888
6889 btst &0x7,FTEMP_EX(%a0) # make "internal" format
6890 sne FTEMP_SGN(%a0)
6891
6892 mov.w FTEMP_EX(%a0),%d1 # extract exponent
6893 and.w &0x7fff,%d1
6894 sub.w %d0,%d1
6895 mov.w %d1,FTEMP_EX(%a0) # insert 16 bit exponent
6896
6897 mov.l %a0,-(%sp) # save operand ptr during calls
6898
6899 clr.l %d0 # force rnd prec = ext
6900 bsr.l _denorm # denorm result
6901
6902 mov.l (%sp),%a0
6903 mov.w &s_mode,%d1 # force rnd prec = sgl
6904 swap %d1
6905 mov.w 0x6(%sp),%d1 # load rnd mode
6906 andi.w &0x30,%d1 # extract rnd prec
6907 lsr.w &0x4,%d1
6908 bsr.l _round # round the denorm
6909
6910 mov.l (%sp)+,%a0
6911
6912# result is now rounded properly. convert back to normal format
6913 bclr &0x7,FTEMP_EX(%a0) # clear sgn first; may have residue
6914 tst.b FTEMP_SGN(%a0) # is "internal result" sign set?
6915 beq.b unf_res4_chkifzero # no; result is positive
6916 bset &0x7,FTEMP_EX(%a0) # set result sgn
6917 clr.b FTEMP_SGN(%a0) # clear temp sign
6918
6919# the number may have become zero after rounding. set ccodes accordingly.
6920unf_res4_chkifzero:
6921 clr.l %d0
6922 tst.l FTEMP_HI(%a0) # is value now a zero?
6923 bne.b unf_res4_cont # no
6924 tst.l FTEMP_LO(%a0)
6925 bne.b unf_res4_cont # no
6926# bset &z_bit,FPSR_CC(%a6) # yes; set zero ccode bit
6927 bset &z_bit,%d0 # yes; set zero ccode bit
6928
6929unf_res4_cont:
6930
6931#
6932# can inex1 also be set along with unfl and inex2???
6933#
6934# we know that underflow has occurred. aunfl should be set if INEX2 is also set.
6935#
6936 btst &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
6937 beq.b unf_res4_end # no
6938 bset &aunfl_bit,FPSR_AEXCEPT(%a6) # yes; set aunfl
6939
6940unf_res4_end:
6941 add.l &0x4,%sp # clear stack
6942 rts
6943
6944#########################################################################
6945# XDEF **************************************************************** #
6946# ovf_res(): routine to produce the default overflow result of #
6947# an overflowing number. #
6948# ovf_res2(): same as above but the rnd mode/prec are passed #
6949# differently. #
6950# #
6951# XREF **************************************************************** #
6952# none #
6953# #
6954# INPUT *************************************************************** #
6955# d1.b = '-1' => (-); '0' => (+) #
6956# ovf_res(): #
6957# d0 = rnd mode/prec #
6958# ovf_res2(): #
6959# hi(d0) = rnd prec #
6960# lo(d0) = rnd mode #
6961# #
6962# OUTPUT ************************************************************** #
6963# a0 = points to extended precision result #
6964# d0.b = condition code bits #
6965# #
6966# ALGORITHM *********************************************************** #
6967# The default overflow result can be determined by the sign of #
6968# the result and the rounding mode/prec in effect. These bits are #
6969# concatenated together to create an index into the default result #
6970# table. A pointer to the correct result is returned in a0. The #
6971# resulting condition codes are returned in d0 in case the caller #
6972# doesn't want FPSR_cc altered (as is the case for fmove out). #
6973# #
6974#########################################################################
6975
6976 global ovf_res
6977ovf_res:
6978 andi.w &0x10,%d1 # keep result sign
6979 lsr.b &0x4,%d0 # shift prec/mode
6980 or.b %d0,%d1 # concat the two
6981 mov.w %d1,%d0 # make a copy
6982 lsl.b &0x1,%d1 # multiply d1 by 2
6983 bra.b ovf_res_load
6984
6985 global ovf_res2
6986ovf_res2:
6987 and.w &0x10, %d1 # keep result sign
6988 or.b %d0, %d1 # insert rnd mode
6989 swap %d0
6990 or.b %d0, %d1 # insert rnd prec
6991 mov.w %d1, %d0 # make a copy
6992 lsl.b &0x1, %d1 # shift left by 1
6993
6994#
6995# use the rounding mode, precision, and result sign as in index into the
6996# two tables below to fetch the default result and the result ccodes.
6997#
6998ovf_res_load:
6999 mov.b (tbl_ovfl_cc.b,%pc,%d0.w*1), %d0 # fetch result ccodes
7000 lea (tbl_ovfl_result.b,%pc,%d1.w*8), %a0 # return result ptr
7001
7002 rts
7003
7004tbl_ovfl_cc:
7005 byte 0x2, 0x0, 0x0, 0x2
7006 byte 0x2, 0x0, 0x0, 0x2
7007 byte 0x2, 0x0, 0x0, 0x2
7008 byte 0x0, 0x0, 0x0, 0x0
7009 byte 0x2+0x8, 0x8, 0x2+0x8, 0x8
7010 byte 0x2+0x8, 0x8, 0x2+0x8, 0x8
7011 byte 0x2+0x8, 0x8, 0x2+0x8, 0x8
7012
7013tbl_ovfl_result:
7014 long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
7015 long 0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RZ
7016 long 0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RM
7017 long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP
7018
7019 long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
7020 long 0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RZ
7021 long 0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RM
7022 long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP
7023
7024 long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
7025 long 0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RZ
7026 long 0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RM
7027 long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP
7028
7029 long 0x00000000,0x00000000,0x00000000,0x00000000
7030 long 0x00000000,0x00000000,0x00000000,0x00000000
7031 long 0x00000000,0x00000000,0x00000000,0x00000000
7032 long 0x00000000,0x00000000,0x00000000,0x00000000
7033
7034 long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
7035 long 0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RZ
7036 long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
7037 long 0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RP
7038
7039 long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
7040 long 0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RZ
7041 long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
7042 long 0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RP
7043
7044 long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
7045 long 0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RZ
7046 long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
7047 long 0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RP
7048
7049#########################################################################
7050# XDEF **************************************************************** #
7051# fout(): move from fp register to memory or data register #
7052# #
7053# XREF **************************************************************** #
7054# _round() - needed to create EXOP for sgl/dbl precision #
7055# norm() - needed to create EXOP for extended precision #
7056# ovf_res() - create default overflow result for sgl/dbl precision#
7057# unf_res() - create default underflow result for sgl/dbl prec. #
7058# dst_dbl() - create rounded dbl precision result. #
7059# dst_sgl() - create rounded sgl precision result. #
7060# fetch_dreg() - fetch dynamic k-factor reg for packed. #
7061# bindec() - convert FP binary number to packed number. #
7062# _mem_write() - write data to memory. #
7063# _mem_write2() - write data to memory unless supv mode -(a7) exc.#
7064# _dmem_write_{byte,word,long}() - write data to memory. #
7065# store_dreg_{b,w,l}() - store data to data register file. #
7066# facc_out_{b,w,l,d,x}() - data access error occurred. #
7067# #
7068# INPUT *************************************************************** #
7069# a0 = pointer to extended precision source operand #
7070# d0 = round prec,mode #
7071# #
7072# OUTPUT ************************************************************** #
7073# fp0 : intermediate underflow or overflow result if #
7074# OVFL/UNFL occurred for a sgl or dbl operand #
7075# #
7076# ALGORITHM *********************************************************** #
7077# This routine is accessed by many handlers that need to do an #
7078# opclass three move of an operand out to memory. #
7079# Decode an fmove out (opclass 3) instruction to determine if #
7080# it's b,w,l,s,d,x, or p in size. b,w,l can be stored to either a data #
7081# register or memory. The algorithm uses a standard "fmove" to create #
7082# the rounded result. Also, since exceptions are disabled, this also #
7083# create the correct OPERR default result if appropriate. #
7084# For sgl or dbl precision, overflow or underflow can occur. If #
7085# either occurs and is enabled, the EXOP. #
7086# For extended precision, the stacked <ea> must be fixed along #
7087# w/ the address index register as appropriate w/ _calc_ea_fout(). If #
7088# the source is a denorm and if underflow is enabled, an EXOP must be #
7089# created. #
7090# For packed, the k-factor must be fetched from the instruction #
7091# word or a data register. The <ea> must be fixed as w/ extended #
7092# precision. Then, bindec() is called to create the appropriate #
7093# packed result. #
7094# If at any time an access error is flagged by one of the move- #
7095# to-memory routines, then a special exit must be made so that the #
7096# access error can be handled properly. #
7097# #
7098#########################################################################
7099
7100 global fout
7101fout:
7102 bfextu EXC_CMDREG(%a6){&3:&3},%d1 # extract dst fmt
7103 mov.w (tbl_fout.b,%pc,%d1.w*2),%a1 # use as index
7104 jmp (tbl_fout.b,%pc,%a1) # jump to routine
7105
7106 swbeg &0x8
7107tbl_fout:
7108 short fout_long - tbl_fout
7109 short fout_sgl - tbl_fout
7110 short fout_ext - tbl_fout
7111 short fout_pack - tbl_fout
7112 short fout_word - tbl_fout
7113 short fout_dbl - tbl_fout
7114 short fout_byte - tbl_fout
7115 short fout_pack - tbl_fout
7116
7117#################################################################
7118# fmove.b out ###################################################
7119#################################################################
7120
7121# Only "Unimplemented Data Type" exceptions enter here. The operand
7122# is either a DENORM or a NORM.
7123fout_byte:
7124 tst.b STAG(%a6) # is operand normalized?
7125 bne.b fout_byte_denorm # no
7126
7127 fmovm.x SRC(%a0),&0x80 # load value
7128
7129fout_byte_norm:
7130 fmov.l %d0,%fpcr # insert rnd prec,mode
7131
7132 fmov.b %fp0,%d0 # exec move out w/ correct rnd mode
7133
7134 fmov.l &0x0,%fpcr # clear FPCR
7135 fmov.l %fpsr,%d1 # fetch FPSR
7136 or.w %d1,2+USER_FPSR(%a6) # save new exc,accrued bits
7137
7138 mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode
7139 andi.b &0x38,%d1 # is mode == 0? (Dreg dst)
7140 beq.b fout_byte_dn # must save to integer regfile
7141
7142 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
7143 bsr.l _dmem_write_byte # write byte
7144
7145 tst.l %d1 # did dstore fail?
7146 bne.l facc_out_b # yes
7147
7148 rts
7149
7150fout_byte_dn:
7151 mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn
7152 andi.w &0x7,%d1
7153 bsr.l store_dreg_b
7154 rts
7155
7156fout_byte_denorm:
7157 mov.l SRC_EX(%a0),%d1
7158 andi.l &0x80000000,%d1 # keep DENORM sign
7159 ori.l &0x00800000,%d1 # make smallest sgl
7160 fmov.s %d1,%fp0
7161 bra.b fout_byte_norm
7162
7163#################################################################
7164# fmove.w out ###################################################
7165#################################################################
7166
7167# Only "Unimplemented Data Type" exceptions enter here. The operand
7168# is either a DENORM or a NORM.
7169fout_word:
7170 tst.b STAG(%a6) # is operand normalized?
7171 bne.b fout_word_denorm # no
7172
7173 fmovm.x SRC(%a0),&0x80 # load value
7174
7175fout_word_norm:
7176 fmov.l %d0,%fpcr # insert rnd prec:mode
7177
7178 fmov.w %fp0,%d0 # exec move out w/ correct rnd mode
7179
7180 fmov.l &0x0,%fpcr # clear FPCR
7181 fmov.l %fpsr,%d1 # fetch FPSR
7182 or.w %d1,2+USER_FPSR(%a6) # save new exc,accrued bits
7183
7184 mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode
7185 andi.b &0x38,%d1 # is mode == 0? (Dreg dst)
7186 beq.b fout_word_dn # must save to integer regfile
7187
7188 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
7189 bsr.l _dmem_write_word # write word
7190
7191 tst.l %d1 # did dstore fail?
7192 bne.l facc_out_w # yes
7193
7194 rts
7195
7196fout_word_dn:
7197 mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn
7198 andi.w &0x7,%d1
7199 bsr.l store_dreg_w
7200 rts
7201
7202fout_word_denorm:
7203 mov.l SRC_EX(%a0),%d1
7204 andi.l &0x80000000,%d1 # keep DENORM sign
7205 ori.l &0x00800000,%d1 # make smallest sgl
7206 fmov.s %d1,%fp0
7207 bra.b fout_word_norm
7208
7209#################################################################
7210# fmove.l out ###################################################
7211#################################################################
7212
7213# Only "Unimplemented Data Type" exceptions enter here. The operand
7214# is either a DENORM or a NORM.
7215fout_long:
7216 tst.b STAG(%a6) # is operand normalized?
7217 bne.b fout_long_denorm # no
7218
7219 fmovm.x SRC(%a0),&0x80 # load value
7220
7221fout_long_norm:
7222 fmov.l %d0,%fpcr # insert rnd prec:mode
7223
7224 fmov.l %fp0,%d0 # exec move out w/ correct rnd mode
7225
7226 fmov.l &0x0,%fpcr # clear FPCR
7227 fmov.l %fpsr,%d1 # fetch FPSR
7228 or.w %d1,2+USER_FPSR(%a6) # save new exc,accrued bits
7229
7230fout_long_write:
7231 mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode
7232 andi.b &0x38,%d1 # is mode == 0? (Dreg dst)
7233 beq.b fout_long_dn # must save to integer regfile
7234
7235 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
7236 bsr.l _dmem_write_long # write long
7237
7238 tst.l %d1 # did dstore fail?
7239 bne.l facc_out_l # yes
7240
7241 rts
7242
7243fout_long_dn:
7244 mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn
7245 andi.w &0x7,%d1
7246 bsr.l store_dreg_l
7247 rts
7248
7249fout_long_denorm:
7250 mov.l SRC_EX(%a0),%d1
7251 andi.l &0x80000000,%d1 # keep DENORM sign
7252 ori.l &0x00800000,%d1 # make smallest sgl
7253 fmov.s %d1,%fp0
7254 bra.b fout_long_norm
7255
7256#################################################################
7257# fmove.x out ###################################################
7258#################################################################
7259
7260# Only "Unimplemented Data Type" exceptions enter here. The operand
7261# is either a DENORM or a NORM.
7262# The DENORM causes an Underflow exception.
7263fout_ext:
7264
7265# we copy the extended precision result to FP_SCR0 so that the reserved
7266# 16-bit field gets zeroed. we do this since we promise not to disturb
7267# what's at SRC(a0).
7268 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
7269 clr.w 2+FP_SCR0_EX(%a6) # clear reserved field
7270 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
7271 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
7272
7273 fmovm.x SRC(%a0),&0x80 # return result
7274
7275 bsr.l _calc_ea_fout # fix stacked <ea>
7276
7277 mov.l %a0,%a1 # pass: dst addr
7278 lea FP_SCR0(%a6),%a0 # pass: src addr
7279 mov.l &0xc,%d0 # pass: opsize is 12 bytes
7280
7281# we must not yet write the extended precision data to the stack
7282# in the pre-decrement case from supervisor mode or else we'll corrupt
7283# the stack frame. so, leave it in FP_SRC for now and deal with it later...
7284 cmpi.b SPCOND_FLG(%a6),&mda7_flg
7285 beq.b fout_ext_a7
7286
7287 bsr.l _dmem_write # write ext prec number to memory
7288
7289 tst.l %d1 # did dstore fail?
7290 bne.w fout_ext_err # yes
7291
7292 tst.b STAG(%a6) # is operand normalized?
7293 bne.b fout_ext_denorm # no
7294 rts
7295
7296# the number is a DENORM. must set the underflow exception bit
7297fout_ext_denorm:
7298 bset &unfl_bit,FPSR_EXCEPT(%a6) # set underflow exc bit
7299
7300 mov.b FPCR_ENABLE(%a6),%d0
7301 andi.b &0x0a,%d0 # is UNFL or INEX enabled?
7302 bne.b fout_ext_exc # yes
7303 rts
7304
7305# we don't want to do the write if the exception occurred in supervisor mode
7306# so _mem_write2() handles this for us.
7307fout_ext_a7:
7308 bsr.l _mem_write2 # write ext prec number to memory
7309
7310 tst.l %d1 # did dstore fail?
7311 bne.w fout_ext_err # yes
7312
7313 tst.b STAG(%a6) # is operand normalized?
7314 bne.b fout_ext_denorm # no
7315 rts
7316
7317fout_ext_exc:
7318 lea FP_SCR0(%a6),%a0
7319 bsr.l norm # normalize the mantissa
7320 neg.w %d0 # new exp = -(shft amt)
7321 andi.w &0x7fff,%d0
7322 andi.w &0x8000,FP_SCR0_EX(%a6) # keep only old sign
7323 or.w %d0,FP_SCR0_EX(%a6) # insert new exponent
7324 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
7325 rts
7326
7327fout_ext_err:
7328 mov.l EXC_A6(%a6),(%a6) # fix stacked a6
7329 bra.l facc_out_x
7330
7331#########################################################################
7332# fmove.s out ###########################################################
7333#########################################################################
7334fout_sgl:
7335 andi.b &0x30,%d0 # clear rnd prec
7336 ori.b &s_mode*0x10,%d0 # insert sgl prec
7337 mov.l %d0,L_SCR3(%a6) # save rnd prec,mode on stack
7338
7339#
7340# operand is a normalized number. first, we check to see if the move out
7341# would cause either an underflow or overflow. these cases are handled
7342# separately. otherwise, set the FPCR to the proper rounding mode and
7343# execute the move.
7344#
7345 mov.w SRC_EX(%a0),%d0 # extract exponent
7346 andi.w &0x7fff,%d0 # strip sign
7347
7348 cmpi.w %d0,&SGL_HI # will operand overflow?
7349 bgt.w fout_sgl_ovfl # yes; go handle OVFL
7350 beq.w fout_sgl_may_ovfl # maybe; go handle possible OVFL
7351 cmpi.w %d0,&SGL_LO # will operand underflow?
7352 blt.w fout_sgl_unfl # yes; go handle underflow
7353
7354#
7355# NORMs(in range) can be stored out by a simple "fmov.s"
7356# Unnormalized inputs can come through this point.
7357#
7358fout_sgl_exg:
7359 fmovm.x SRC(%a0),&0x80 # fetch fop from stack
7360
7361 fmov.l L_SCR3(%a6),%fpcr # set FPCR
7362 fmov.l &0x0,%fpsr # clear FPSR
7363
7364 fmov.s %fp0,%d0 # store does convert and round
7365
7366 fmov.l &0x0,%fpcr # clear FPCR
7367 fmov.l %fpsr,%d1 # save FPSR
7368
7369 or.w %d1,2+USER_FPSR(%a6) # set possible inex2/ainex
7370
7371fout_sgl_exg_write:
7372 mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode
7373 andi.b &0x38,%d1 # is mode == 0? (Dreg dst)
7374 beq.b fout_sgl_exg_write_dn # must save to integer regfile
7375
7376 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
7377 bsr.l _dmem_write_long # write long
7378
7379 tst.l %d1 # did dstore fail?
7380 bne.l facc_out_l # yes
7381
7382 rts
7383
7384fout_sgl_exg_write_dn:
7385 mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn
7386 andi.w &0x7,%d1
7387 bsr.l store_dreg_l
7388 rts
7389
7390#
7391# here, we know that the operand would UNFL if moved out to single prec,
7392# so, denorm and round and then use generic store single routine to
7393# write the value to memory.
7394#
7395fout_sgl_unfl:
7396 bset &unfl_bit,FPSR_EXCEPT(%a6) # set UNFL
7397
7398 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
7399 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
7400 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
7401 mov.l %a0,-(%sp)
7402
7403 clr.l %d0 # pass: S.F. = 0
7404
7405 cmpi.b STAG(%a6),&DENORM # fetch src optype tag
7406 bne.b fout_sgl_unfl_cont # let DENORMs fall through
7407
7408 lea FP_SCR0(%a6),%a0
7409 bsr.l norm # normalize the DENORM
7410
7411fout_sgl_unfl_cont:
7412 lea FP_SCR0(%a6),%a0 # pass: ptr to operand
7413 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
7414 bsr.l unf_res # calc default underflow result
7415
7416 lea FP_SCR0(%a6),%a0 # pass: ptr to fop
7417 bsr.l dst_sgl # convert to single prec
7418
7419 mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode
7420 andi.b &0x38,%d1 # is mode == 0? (Dreg dst)
7421 beq.b fout_sgl_unfl_dn # must save to integer regfile
7422
7423 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
7424 bsr.l _dmem_write_long # write long
7425
7426 tst.l %d1 # did dstore fail?
7427 bne.l facc_out_l # yes
7428
7429 bra.b fout_sgl_unfl_chkexc
7430
7431fout_sgl_unfl_dn:
7432 mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn
7433 andi.w &0x7,%d1
7434 bsr.l store_dreg_l
7435
7436fout_sgl_unfl_chkexc:
7437 mov.b FPCR_ENABLE(%a6),%d1
7438 andi.b &0x0a,%d1 # is UNFL or INEX enabled?
7439 bne.w fout_sd_exc_unfl # yes
7440 addq.l &0x4,%sp
7441 rts
7442
7443#
7444# it's definitely an overflow so call ovf_res to get the correct answer
7445#
7446fout_sgl_ovfl:
7447 tst.b 3+SRC_HI(%a0) # is result inexact?
7448 bne.b fout_sgl_ovfl_inex2
7449 tst.l SRC_LO(%a0) # is result inexact?
7450 bne.b fout_sgl_ovfl_inex2
7451 ori.w &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex
7452 bra.b fout_sgl_ovfl_cont
7453fout_sgl_ovfl_inex2:
7454 ori.w &ovfinx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex/inex2
7455
7456fout_sgl_ovfl_cont:
7457 mov.l %a0,-(%sp)
7458
7459# call ovf_res() w/ sgl prec and the correct rnd mode to create the default
7460# overflow result. DON'T save the returned ccodes from ovf_res() since
7461# fmove out doesn't alter them.
7462 tst.b SRC_EX(%a0) # is operand negative?
7463 smi %d1 # set if so
7464 mov.l L_SCR3(%a6),%d0 # pass: sgl prec,rnd mode
7465 bsr.l ovf_res # calc OVFL result
7466 fmovm.x (%a0),&0x80 # load default overflow result
7467 fmov.s %fp0,%d0 # store to single
7468
7469 mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode
7470 andi.b &0x38,%d1 # is mode == 0? (Dreg dst)
7471 beq.b fout_sgl_ovfl_dn # must save to integer regfile
7472
7473 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct
7474 bsr.l _dmem_write_long # write long
7475
7476 tst.l %d1 # did dstore fail?
7477 bne.l facc_out_l # yes
7478
7479 bra.b fout_sgl_ovfl_chkexc
7480
7481fout_sgl_ovfl_dn:
7482 mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn
7483 andi.w &0x7,%d1
7484 bsr.l store_dreg_l
7485
7486fout_sgl_ovfl_chkexc:
7487 mov.b FPCR_ENABLE(%a6),%d1
7488 andi.b &0x0a,%d1 # is UNFL or INEX enabled?
7489 bne.w fout_sd_exc_ovfl # yes
7490 addq.l &0x4,%sp
7491 rts
7492
7493#
7494# move out MAY overflow:
7495# (1) force the exp to 0x3fff
7496# (2) do a move w/ appropriate rnd mode
7497# (3) if exp still equals zero, then insert original exponent
7498# for the correct result.
7499# if exp now equals one, then it overflowed so call ovf_res.
7500#
7501fout_sgl_may_ovfl:
7502 mov.w SRC_EX(%a0),%d1 # fetch current sign
7503 andi.w &0x8000,%d1 # keep it,clear exp
7504 ori.w &0x3fff,%d1 # insert exp = 0
7505 mov.w %d1,FP_SCR0_EX(%a6) # insert scaled exp
7506 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) # copy hi(man)
7507 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) # copy lo(man)
7508
7509 fmov.l L_SCR3(%a6),%fpcr # set FPCR
7510
7511 fmov.x FP_SCR0(%a6),%fp0 # force fop to be rounded
7512 fmov.l &0x0,%fpcr # clear FPCR
7513
7514 fabs.x %fp0 # need absolute value
7515 fcmp.b %fp0,&0x2 # did exponent increase?
7516 fblt.w fout_sgl_exg # no; go finish NORM
7517 bra.w fout_sgl_ovfl # yes; go handle overflow
7518
7519################
7520
7521fout_sd_exc_unfl:
7522 mov.l (%sp)+,%a0
7523
7524 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
7525 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
7526 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
7527
7528 cmpi.b STAG(%a6),&DENORM # was src a DENORM?
7529 bne.b fout_sd_exc_cont # no
7530
7531 lea FP_SCR0(%a6),%a0
7532 bsr.l norm
7533 neg.l %d0
7534 andi.w &0x7fff,%d0
7535 bfins %d0,FP_SCR0_EX(%a6){&1:&15}
7536 bra.b fout_sd_exc_cont
7537
7538fout_sd_exc:
7539fout_sd_exc_ovfl:
7540 mov.l (%sp)+,%a0 # restore a0
7541
7542 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
7543 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
7544 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
7545
7546fout_sd_exc_cont:
7547 bclr &0x7,FP_SCR0_EX(%a6) # clear sign bit
7548 sne.b 2+FP_SCR0_EX(%a6) # set internal sign bit
7549 lea FP_SCR0(%a6),%a0 # pass: ptr to DENORM
7550
7551 mov.b 3+L_SCR3(%a6),%d1
7552 lsr.b &0x4,%d1
7553 andi.w &0x0c,%d1
7554 swap %d1
7555 mov.b 3+L_SCR3(%a6),%d1
7556 lsr.b &0x4,%d1
7557 andi.w &0x03,%d1
7558 clr.l %d0 # pass: zero g,r,s
7559 bsr.l _round # round the DENORM
7560
7561 tst.b 2+FP_SCR0_EX(%a6) # is EXOP negative?
7562 beq.b fout_sd_exc_done # no
7563 bset &0x7,FP_SCR0_EX(%a6) # yes
7564
7565fout_sd_exc_done:
7566 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
7567 rts
7568
7569#################################################################
7570# fmove.d out ###################################################
7571#################################################################
7572fout_dbl:
7573 andi.b &0x30,%d0 # clear rnd prec
7574 ori.b &d_mode*0x10,%d0 # insert dbl prec
7575 mov.l %d0,L_SCR3(%a6) # save rnd prec,mode on stack
7576
7577#
7578# operand is a normalized number. first, we check to see if the move out
7579# would cause either an underflow or overflow. these cases are handled
7580# separately. otherwise, set the FPCR to the proper rounding mode and
7581# execute the move.
7582#
7583 mov.w SRC_EX(%a0),%d0 # extract exponent
7584 andi.w &0x7fff,%d0 # strip sign
7585
7586 cmpi.w %d0,&DBL_HI # will operand overflow?
7587 bgt.w fout_dbl_ovfl # yes; go handle OVFL
7588 beq.w fout_dbl_may_ovfl # maybe; go handle possible OVFL
7589 cmpi.w %d0,&DBL_LO # will operand underflow?
7590 blt.w fout_dbl_unfl # yes; go handle underflow
7591
7592#
7593# NORMs(in range) can be stored out by a simple "fmov.d"
7594# Unnormalized inputs can come through this point.
7595#
7596fout_dbl_exg:
7597 fmovm.x SRC(%a0),&0x80 # fetch fop from stack
7598
7599 fmov.l L_SCR3(%a6),%fpcr # set FPCR
7600 fmov.l &0x0,%fpsr # clear FPSR
7601
7602 fmov.d %fp0,L_SCR1(%a6) # store does convert and round
7603
7604 fmov.l &0x0,%fpcr # clear FPCR
7605 fmov.l %fpsr,%d0 # save FPSR
7606
7607 or.w %d0,2+USER_FPSR(%a6) # set possible inex2/ainex
7608
7609 mov.l EXC_EA(%a6),%a1 # pass: dst addr
7610 lea L_SCR1(%a6),%a0 # pass: src addr
7611 movq.l &0x8,%d0 # pass: opsize is 8 bytes
7612 bsr.l _dmem_write # store dbl fop to memory
7613
7614 tst.l %d1 # did dstore fail?
7615 bne.l facc_out_d # yes
7616
7617 rts # no; so we're finished
7618
7619#
7620# here, we know that the operand would UNFL if moved out to double prec,
7621# so, denorm and round and then use generic store double routine to
7622# write the value to memory.
7623#
7624fout_dbl_unfl:
7625 bset &unfl_bit,FPSR_EXCEPT(%a6) # set UNFL
7626
7627 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
7628 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
7629 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
7630 mov.l %a0,-(%sp)
7631
7632 clr.l %d0 # pass: S.F. = 0
7633
7634 cmpi.b STAG(%a6),&DENORM # fetch src optype tag
7635 bne.b fout_dbl_unfl_cont # let DENORMs fall through
7636
7637 lea FP_SCR0(%a6),%a0
7638 bsr.l norm # normalize the DENORM
7639
7640fout_dbl_unfl_cont:
7641 lea FP_SCR0(%a6),%a0 # pass: ptr to operand
7642 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
7643 bsr.l unf_res # calc default underflow result
7644
7645 lea FP_SCR0(%a6),%a0 # pass: ptr to fop
7646 bsr.l dst_dbl # convert to single prec
7647 mov.l %d0,L_SCR1(%a6)
7648 mov.l %d1,L_SCR2(%a6)
7649
7650 mov.l EXC_EA(%a6),%a1 # pass: dst addr
7651 lea L_SCR1(%a6),%a0 # pass: src addr
7652 movq.l &0x8,%d0 # pass: opsize is 8 bytes
7653 bsr.l _dmem_write # store dbl fop to memory
7654
7655 tst.l %d1 # did dstore fail?
7656 bne.l facc_out_d # yes
7657
7658 mov.b FPCR_ENABLE(%a6),%d1
7659 andi.b &0x0a,%d1 # is UNFL or INEX enabled?
7660 bne.w fout_sd_exc_unfl # yes
7661 addq.l &0x4,%sp
7662 rts
7663
7664#
7665# it's definitely an overflow so call ovf_res to get the correct answer
7666#
7667fout_dbl_ovfl:
7668 mov.w 2+SRC_LO(%a0),%d0
7669 andi.w &0x7ff,%d0
7670 bne.b fout_dbl_ovfl_inex2
7671
7672 ori.w &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex
7673 bra.b fout_dbl_ovfl_cont
7674fout_dbl_ovfl_inex2:
7675 ori.w &ovfinx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex/inex2
7676
7677fout_dbl_ovfl_cont:
7678 mov.l %a0,-(%sp)
7679
7680# call ovf_res() w/ dbl prec and the correct rnd mode to create the default
7681# overflow result. DON'T save the returned ccodes from ovf_res() since
7682# fmove out doesn't alter them.
7683 tst.b SRC_EX(%a0) # is operand negative?
7684 smi %d1 # set if so
7685 mov.l L_SCR3(%a6),%d0 # pass: dbl prec,rnd mode
7686 bsr.l ovf_res # calc OVFL result
7687 fmovm.x (%a0),&0x80 # load default overflow result
7688 fmov.d %fp0,L_SCR1(%a6) # store to double
7689
7690 mov.l EXC_EA(%a6),%a1 # pass: dst addr
7691 lea L_SCR1(%a6),%a0 # pass: src addr
7692 movq.l &0x8,%d0 # pass: opsize is 8 bytes
7693 bsr.l _dmem_write # store dbl fop to memory
7694
7695 tst.l %d1 # did dstore fail?
7696 bne.l facc_out_d # yes
7697
7698 mov.b FPCR_ENABLE(%a6),%d1
7699 andi.b &0x0a,%d1 # is UNFL or INEX enabled?
7700 bne.w fout_sd_exc_ovfl # yes
7701 addq.l &0x4,%sp
7702 rts
7703
7704#
7705# move out MAY overflow:
7706# (1) force the exp to 0x3fff
7707# (2) do a move w/ appropriate rnd mode
7708# (3) if exp still equals zero, then insert original exponent
7709# for the correct result.
7710# if exp now equals one, then it overflowed so call ovf_res.
7711#
7712fout_dbl_may_ovfl:
7713 mov.w SRC_EX(%a0),%d1 # fetch current sign
7714 andi.w &0x8000,%d1 # keep it,clear exp
7715 ori.w &0x3fff,%d1 # insert exp = 0
7716 mov.w %d1,FP_SCR0_EX(%a6) # insert scaled exp
7717 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) # copy hi(man)
7718 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) # copy lo(man)
7719
7720 fmov.l L_SCR3(%a6),%fpcr # set FPCR
7721
7722 fmov.x FP_SCR0(%a6),%fp0 # force fop to be rounded
7723 fmov.l &0x0,%fpcr # clear FPCR
7724
7725 fabs.x %fp0 # need absolute value
7726 fcmp.b %fp0,&0x2 # did exponent increase?
7727 fblt.w fout_dbl_exg # no; go finish NORM
7728 bra.w fout_dbl_ovfl # yes; go handle overflow
7729
7730#########################################################################
7731# XDEF **************************************************************** #
7732# dst_dbl(): create double precision value from extended prec. #
7733# #
7734# XREF **************************************************************** #
7735# None #
7736# #
7737# INPUT *************************************************************** #
7738# a0 = pointer to source operand in extended precision #
7739# #
7740# OUTPUT ************************************************************** #
7741# d0 = hi(double precision result) #
7742# d1 = lo(double precision result) #
7743# #
7744# ALGORITHM *********************************************************** #
7745# #
7746# Changes extended precision to double precision. #
7747# Note: no attempt is made to round the extended value to double. #
7748# dbl_sign = ext_sign #
7749# dbl_exp = ext_exp - $3fff(ext bias) + $7ff(dbl bias) #
7750# get rid of ext integer bit #
7751# dbl_mant = ext_mant{62:12} #
7752# #
7753# --------------- --------------- --------------- #
7754# extended -> |s| exp | |1| ms mant | | ls mant | #
7755# --------------- --------------- --------------- #
7756# 95 64 63 62 32 31 11 0 #
7757# | | #
7758# | | #
7759# | | #
7760# v v #
7761# --------------- --------------- #
7762# double -> |s|exp| mant | | mant | #
7763# --------------- --------------- #
7764# 63 51 32 31 0 #
7765# #
7766#########################################################################
7767
7768dst_dbl:
7769 clr.l %d0 # clear d0
7770 mov.w FTEMP_EX(%a0),%d0 # get exponent
7771 subi.w &EXT_BIAS,%d0 # subtract extended precision bias
7772 addi.w &DBL_BIAS,%d0 # add double precision bias
7773 tst.b FTEMP_HI(%a0) # is number a denorm?
7774 bmi.b dst_get_dupper # no
7775 subq.w &0x1,%d0 # yes; denorm bias = DBL_BIAS - 1
7776dst_get_dupper:
7777 swap %d0 # d0 now in upper word
7778 lsl.l &0x4,%d0 # d0 in proper place for dbl prec exp
7779 tst.b FTEMP_EX(%a0) # test sign
7780 bpl.b dst_get_dman # if postive, go process mantissa
7781 bset &0x1f,%d0 # if negative, set sign
7782dst_get_dman:
7783 mov.l FTEMP_HI(%a0),%d1 # get ms mantissa
7784 bfextu %d1{&1:&20},%d1 # get upper 20 bits of ms
7785 or.l %d1,%d0 # put these bits in ms word of double
7786 mov.l %d0,L_SCR1(%a6) # put the new exp back on the stack
7787 mov.l FTEMP_HI(%a0),%d1 # get ms mantissa
7788 mov.l &21,%d0 # load shift count
7789 lsl.l %d0,%d1 # put lower 11 bits in upper bits
7790 mov.l %d1,L_SCR2(%a6) # build lower lword in memory
7791 mov.l FTEMP_LO(%a0),%d1 # get ls mantissa
7792 bfextu %d1{&0:&21},%d0 # get ls 21 bits of double
7793 mov.l L_SCR2(%a6),%d1
7794 or.l %d0,%d1 # put them in double result
7795 mov.l L_SCR1(%a6),%d0
7796 rts
7797
7798#########################################################################
7799# XDEF **************************************************************** #
7800# dst_sgl(): create single precision value from extended prec #
7801# #
7802# XREF **************************************************************** #
7803# #
7804# INPUT *************************************************************** #
7805# a0 = pointer to source operand in extended precision #
7806# #
7807# OUTPUT ************************************************************** #
7808# d0 = single precision result #
7809# #
7810# ALGORITHM *********************************************************** #
7811# #
7812# Changes extended precision to single precision. #
7813# sgl_sign = ext_sign #
7814# sgl_exp = ext_exp - $3fff(ext bias) + $7f(sgl bias) #
7815# get rid of ext integer bit #
7816# sgl_mant = ext_mant{62:12} #
7817# #
7818# --------------- --------------- --------------- #
7819# extended -> |s| exp | |1| ms mant | | ls mant | #
7820# --------------- --------------- --------------- #
7821# 95 64 63 62 40 32 31 12 0 #
7822# | | #
7823# | | #
7824# | | #
7825# v v #
7826# --------------- #
7827# single -> |s|exp| mant | #
7828# --------------- #
7829# 31 22 0 #
7830# #
7831#########################################################################
7832
7833dst_sgl:
7834 clr.l %d0
7835 mov.w FTEMP_EX(%a0),%d0 # get exponent
7836 subi.w &EXT_BIAS,%d0 # subtract extended precision bias
7837 addi.w &SGL_BIAS,%d0 # add single precision bias
7838 tst.b FTEMP_HI(%a0) # is number a denorm?
7839 bmi.b dst_get_supper # no
7840 subq.w &0x1,%d0 # yes; denorm bias = SGL_BIAS - 1
7841dst_get_supper:
7842 swap %d0 # put exp in upper word of d0
7843 lsl.l &0x7,%d0 # shift it into single exp bits
7844 tst.b FTEMP_EX(%a0) # test sign
7845 bpl.b dst_get_sman # if positive, continue
7846 bset &0x1f,%d0 # if negative, put in sign first
7847dst_get_sman:
7848 mov.l FTEMP_HI(%a0),%d1 # get ms mantissa
7849 andi.l &0x7fffff00,%d1 # get upper 23 bits of ms
7850 lsr.l &0x8,%d1 # and put them flush right
7851 or.l %d1,%d0 # put these bits in ms word of single
7852 rts
7853
7854##############################################################################
7855fout_pack:
7856 bsr.l _calc_ea_fout # fetch the <ea>
7857 mov.l %a0,-(%sp)
7858
7859 mov.b STAG(%a6),%d0 # fetch input type
7860 bne.w fout_pack_not_norm # input is not NORM
7861
7862fout_pack_norm:
7863 btst &0x4,EXC_CMDREG(%a6) # static or dynamic?
7864 beq.b fout_pack_s # static
7865
7866fout_pack_d:
7867 mov.b 1+EXC_CMDREG(%a6),%d1 # fetch dynamic reg
7868 lsr.b &0x4,%d1
7869 andi.w &0x7,%d1
7870
7871 bsr.l fetch_dreg # fetch Dn w/ k-factor
7872
7873 bra.b fout_pack_type
7874fout_pack_s:
7875 mov.b 1+EXC_CMDREG(%a6),%d0 # fetch static field
7876
7877fout_pack_type:
7878 bfexts %d0{&25:&7},%d0 # extract k-factor
7879 mov.l %d0,-(%sp)
7880
7881 lea FP_SRC(%a6),%a0 # pass: ptr to input
7882
7883# bindec is currently scrambling FP_SRC for denorm inputs.
7884# we'll have to change this, but for now, tough luck!!!
7885 bsr.l bindec # convert xprec to packed
7886
7887# andi.l &0xcfff000f,FP_SCR0(%a6) # clear unused fields
7888 andi.l &0xcffff00f,FP_SCR0(%a6) # clear unused fields
7889
7890 mov.l (%sp)+,%d0
7891
7892 tst.b 3+FP_SCR0_EX(%a6)
7893 bne.b fout_pack_set
7894 tst.l FP_SCR0_HI(%a6)
7895 bne.b fout_pack_set
7896 tst.l FP_SCR0_LO(%a6)
7897 bne.b fout_pack_set
7898
7899# add the extra condition that only if the k-factor was zero, too, should
7900# we zero the exponent
7901 tst.l %d0
7902 bne.b fout_pack_set
7903# "mantissa" is all zero which means that the answer is zero. but, the '040
7904# algorithm allows the exponent to be non-zero. the 881/2 do not. therefore,
7905# if the mantissa is zero, I will zero the exponent, too.
7906# the question now is whether the exponents sign bit is allowed to be non-zero
7907# for a zero, also...
7908 andi.w &0xf000,FP_SCR0(%a6)
7909
7910fout_pack_set:
7911
7912 lea FP_SCR0(%a6),%a0 # pass: src addr
7913
7914fout_pack_write:
7915 mov.l (%sp)+,%a1 # pass: dst addr
7916 mov.l &0xc,%d0 # pass: opsize is 12 bytes
7917
7918 cmpi.b SPCOND_FLG(%a6),&mda7_flg
7919 beq.b fout_pack_a7
7920
7921 bsr.l _dmem_write # write ext prec number to memory
7922
7923 tst.l %d1 # did dstore fail?
7924 bne.w fout_ext_err # yes
7925
7926 rts
7927
7928# we don't want to do the write if the exception occurred in supervisor mode
7929# so _mem_write2() handles this for us.
7930fout_pack_a7:
7931 bsr.l _mem_write2 # write ext prec number to memory
7932
7933 tst.l %d1 # did dstore fail?
7934 bne.w fout_ext_err # yes
7935
7936 rts
7937
7938fout_pack_not_norm:
7939 cmpi.b %d0,&DENORM # is it a DENORM?
7940 beq.w fout_pack_norm # yes
7941 lea FP_SRC(%a6),%a0
7942 clr.w 2+FP_SRC_EX(%a6)
7943 cmpi.b %d0,&SNAN # is it an SNAN?
7944 beq.b fout_pack_snan # yes
7945 bra.b fout_pack_write # no
7946
7947fout_pack_snan:
7948 ori.w &snaniop2_mask,FPSR_EXCEPT(%a6) # set SNAN/AIOP
7949 bset &0x6,FP_SRC_HI(%a6) # set snan bit
7950 bra.b fout_pack_write
7951
7952#########################################################################
7953# XDEF **************************************************************** #
7954# fmul(): emulates the fmul instruction #
7955# fsmul(): emulates the fsmul instruction #
7956# fdmul(): emulates the fdmul instruction #
7957# #
7958# XREF **************************************************************** #
7959# scale_to_zero_src() - scale src exponent to zero #
7960# scale_to_zero_dst() - scale dst exponent to zero #
7961# unf_res() - return default underflow result #
7962# ovf_res() - return default overflow result #
7963# res_qnan() - return QNAN result #
7964# res_snan() - return SNAN result #
7965# #
7966# INPUT *************************************************************** #
7967# a0 = pointer to extended precision source operand #
7968# a1 = pointer to extended precision destination operand #
7969# d0 rnd prec,mode #
7970# #
7971# OUTPUT ************************************************************** #
7972# fp0 = result #
7973# fp1 = EXOP (if exception occurred) #
7974# #
7975# ALGORITHM *********************************************************** #
7976# Handle NANs, infinities, and zeroes as special cases. Divide #
7977# norms/denorms into ext/sgl/dbl precision. #
7978# For norms/denorms, scale the exponents such that a multiply #
7979# instruction won't cause an exception. Use the regular fmul to #
7980# compute a result. Check if the regular operands would have taken #
7981# an exception. If so, return the default overflow/underflow result #
7982# and return the EXOP if exceptions are enabled. Else, scale the #
7983# result operand to the proper exponent. #
7984# #
7985#########################################################################
7986
7987 align 0x10
7988tbl_fmul_ovfl:
7989 long 0x3fff - 0x7ffe # ext_max
7990 long 0x3fff - 0x407e # sgl_max
7991 long 0x3fff - 0x43fe # dbl_max
7992tbl_fmul_unfl:
7993 long 0x3fff + 0x0001 # ext_unfl
7994 long 0x3fff - 0x3f80 # sgl_unfl
7995 long 0x3fff - 0x3c00 # dbl_unfl
7996
7997 global fsmul
7998fsmul:
7999 andi.b &0x30,%d0 # clear rnd prec
8000 ori.b &s_mode*0x10,%d0 # insert sgl prec
8001 bra.b fmul
8002
8003 global fdmul
8004fdmul:
8005 andi.b &0x30,%d0
8006 ori.b &d_mode*0x10,%d0 # insert dbl prec
8007
8008 global fmul
8009fmul:
8010 mov.l %d0,L_SCR3(%a6) # store rnd info
8011
8012 clr.w %d1
8013 mov.b DTAG(%a6),%d1
8014 lsl.b &0x3,%d1
8015 or.b STAG(%a6),%d1 # combine src tags
8016 bne.w fmul_not_norm # optimize on non-norm input
8017
8018fmul_norm:
8019 mov.w DST_EX(%a1),FP_SCR1_EX(%a6)
8020 mov.l DST_HI(%a1),FP_SCR1_HI(%a6)
8021 mov.l DST_LO(%a1),FP_SCR1_LO(%a6)
8022
8023 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
8024 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
8025 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
8026
8027 bsr.l scale_to_zero_src # scale src exponent
8028 mov.l %d0,-(%sp) # save scale factor 1
8029
8030 bsr.l scale_to_zero_dst # scale dst exponent
8031
8032 add.l %d0,(%sp) # SCALE_FACTOR = scale1 + scale2
8033
8034 mov.w 2+L_SCR3(%a6),%d1 # fetch precision
8035 lsr.b &0x6,%d1 # shift to lo bits
8036 mov.l (%sp)+,%d0 # load S.F.
8037 cmp.l %d0,(tbl_fmul_ovfl.w,%pc,%d1.w*4) # would result ovfl?
8038 beq.w fmul_may_ovfl # result may rnd to overflow
8039 blt.w fmul_ovfl # result will overflow
8040
8041 cmp.l %d0,(tbl_fmul_unfl.w,%pc,%d1.w*4) # would result unfl?
8042 beq.w fmul_may_unfl # result may rnd to no unfl
8043 bgt.w fmul_unfl # result will underflow
8044
8045#
8046# NORMAL:
8047# - the result of the multiply operation will neither overflow nor underflow.
8048# - do the multiply to the proper precision and rounding mode.
8049# - scale the result exponent using the scale factor. if both operands were
8050# normalized then we really don't need to go through this scaling. but for now,
8051# this will do.
8052#
8053fmul_normal:
8054 fmovm.x FP_SCR1(%a6),&0x80 # load dst operand
8055
8056 fmov.l L_SCR3(%a6),%fpcr # set FPCR
8057 fmov.l &0x0,%fpsr # clear FPSR
8058
8059 fmul.x FP_SCR0(%a6),%fp0 # execute multiply
8060
8061 fmov.l %fpsr,%d1 # save status
8062 fmov.l &0x0,%fpcr # clear FPCR
8063
8064 or.l %d1,USER_FPSR(%a6) # save INEX2,N
8065
8066fmul_normal_exit:
8067 fmovm.x &0x80,FP_SCR0(%a6) # store out result
8068 mov.l %d2,-(%sp) # save d2
8069 mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp}
8070 mov.l %d1,%d2 # make a copy
8071 andi.l &0x7fff,%d1 # strip sign
8072 andi.w &0x8000,%d2 # keep old sign
8073 sub.l %d0,%d1 # add scale factor
8074 or.w %d2,%d1 # concat old sign,new exp
8075 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
8076 mov.l (%sp)+,%d2 # restore d2
8077 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
8078 rts
8079
8080#
8081# OVERFLOW:
8082# - the result of the multiply operation is an overflow.
8083# - do the multiply to the proper precision and rounding mode in order to
8084# set the inexact bits.
8085# - calculate the default result and return it in fp0.
8086# - if overflow or inexact is enabled, we need a multiply result rounded to
8087# extended precision. if the original operation was extended, then we have this
8088# result. if the original operation was single or double, we have to do another
8089# multiply using extended precision and the correct rounding mode. the result
8090# of this operation then has its exponent scaled by -0x6000 to create the
8091# exceptional operand.
8092#
8093fmul_ovfl:
8094 fmovm.x FP_SCR1(%a6),&0x80 # load dst operand
8095
8096 fmov.l L_SCR3(%a6),%fpcr # set FPCR
8097 fmov.l &0x0,%fpsr # clear FPSR
8098
8099 fmul.x FP_SCR0(%a6),%fp0 # execute multiply
8100
8101 fmov.l %fpsr,%d1 # save status
8102 fmov.l &0x0,%fpcr # clear FPCR
8103
8104 or.l %d1,USER_FPSR(%a6) # save INEX2,N
8105
8106# save setting this until now because this is where fmul_may_ovfl may jump in
8107fmul_ovfl_tst:
8108 or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
8109
8110 mov.b FPCR_ENABLE(%a6),%d1
8111 andi.b &0x13,%d1 # is OVFL or INEX enabled?
8112 bne.b fmul_ovfl_ena # yes
8113
8114# calculate the default result
8115fmul_ovfl_dis:
8116 btst &neg_bit,FPSR_CC(%a6) # is result negative?
8117 sne %d1 # set sign param accordingly
8118 mov.l L_SCR3(%a6),%d0 # pass rnd prec,mode
8119 bsr.l ovf_res # calculate default result
8120 or.b %d0,FPSR_CC(%a6) # set INF,N if applicable
8121 fmovm.x (%a0),&0x80 # return default result in fp0
8122 rts
8123
8124#
8125# OVFL is enabled; Create EXOP:
8126# - if precision is extended, then we have the EXOP. simply bias the exponent
8127# with an extra -0x6000. if the precision is single or double, we need to
8128# calculate a result rounded to extended precision.
8129#
8130fmul_ovfl_ena:
8131 mov.l L_SCR3(%a6),%d1
8132 andi.b &0xc0,%d1 # test the rnd prec
8133 bne.b fmul_ovfl_ena_sd # it's sgl or dbl
8134
8135fmul_ovfl_ena_cont:
8136 fmovm.x &0x80,FP_SCR0(%a6) # move result to stack
8137
8138 mov.l %d2,-(%sp) # save d2
8139 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
8140 mov.w %d1,%d2 # make a copy
8141 andi.l &0x7fff,%d1 # strip sign
8142 sub.l %d0,%d1 # add scale factor
8143 subi.l &0x6000,%d1 # subtract bias
8144 andi.w &0x7fff,%d1 # clear sign bit
8145 andi.w &0x8000,%d2 # keep old sign
8146 or.w %d2,%d1 # concat old sign,new exp
8147 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
8148 mov.l (%sp)+,%d2 # restore d2
8149 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
8150 bra.b fmul_ovfl_dis
8151
8152fmul_ovfl_ena_sd:
8153 fmovm.x FP_SCR1(%a6),&0x80 # load dst operand
8154
8155 mov.l L_SCR3(%a6),%d1
8156 andi.b &0x30,%d1 # keep rnd mode only
8157 fmov.l %d1,%fpcr # set FPCR
8158
8159 fmul.x FP_SCR0(%a6),%fp0 # execute multiply
8160
8161 fmov.l &0x0,%fpcr # clear FPCR
8162 bra.b fmul_ovfl_ena_cont
8163
8164#
8165# may OVERFLOW:
8166# - the result of the multiply operation MAY overflow.
8167# - do the multiply to the proper precision and rounding mode in order to
8168# set the inexact bits.
8169# - calculate the default result and return it in fp0.
8170#
8171fmul_may_ovfl:
8172 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
8173
8174 fmov.l L_SCR3(%a6),%fpcr # set FPCR
8175 fmov.l &0x0,%fpsr # clear FPSR
8176
8177 fmul.x FP_SCR0(%a6),%fp0 # execute multiply
8178
8179 fmov.l %fpsr,%d1 # save status
8180 fmov.l &0x0,%fpcr # clear FPCR
8181
8182 or.l %d1,USER_FPSR(%a6) # save INEX2,N
8183
8184 fabs.x %fp0,%fp1 # make a copy of result
8185 fcmp.b %fp1,&0x2 # is |result| >= 2.b?
8186 fbge.w fmul_ovfl_tst # yes; overflow has occurred
8187
8188# no, it didn't overflow; we have correct result
8189 bra.w fmul_normal_exit
8190
8191#
8192# UNDERFLOW:
8193# - the result of the multiply operation is an underflow.
8194# - do the multiply to the proper precision and rounding mode in order to
8195# set the inexact bits.
8196# - calculate the default result and return it in fp0.
8197# - if overflow or inexact is enabled, we need a multiply result rounded to
8198# extended precision. if the original operation was extended, then we have this
8199# result. if the original operation was single or double, we have to do another
8200# multiply using extended precision and the correct rounding mode. the result
8201# of this operation then has its exponent scaled by -0x6000 to create the
8202# exceptional operand.
8203#
8204fmul_unfl:
8205 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
8206
8207# for fun, let's use only extended precision, round to zero. then, let
8208# the unf_res() routine figure out all the rest.
8209# will we get the correct answer.
8210 fmovm.x FP_SCR1(%a6),&0x80 # load dst operand
8211
8212 fmov.l &rz_mode*0x10,%fpcr # set FPCR
8213 fmov.l &0x0,%fpsr # clear FPSR
8214
8215 fmul.x FP_SCR0(%a6),%fp0 # execute multiply
8216
8217 fmov.l %fpsr,%d1 # save status
8218 fmov.l &0x0,%fpcr # clear FPCR
8219
8220 or.l %d1,USER_FPSR(%a6) # save INEX2,N
8221
8222 mov.b FPCR_ENABLE(%a6),%d1
8223 andi.b &0x0b,%d1 # is UNFL or INEX enabled?
8224 bne.b fmul_unfl_ena # yes
8225
8226fmul_unfl_dis:
8227 fmovm.x &0x80,FP_SCR0(%a6) # store out result
8228
8229 lea FP_SCR0(%a6),%a0 # pass: result addr
8230 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
8231 bsr.l unf_res # calculate default result
8232 or.b %d0,FPSR_CC(%a6) # unf_res2 may have set 'Z'
8233 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
8234 rts
8235
8236#
8237# UNFL is enabled.
8238#
8239fmul_unfl_ena:
8240 fmovm.x FP_SCR1(%a6),&0x40 # load dst op
8241
8242 mov.l L_SCR3(%a6),%d1
8243 andi.b &0xc0,%d1 # is precision extended?
8244 bne.b fmul_unfl_ena_sd # no, sgl or dbl
8245
8246# if the rnd mode is anything but RZ, then we have to re-do the above
8247# multiplication becuase we used RZ for all.
8248 fmov.l L_SCR3(%a6),%fpcr # set FPCR
8249
8250fmul_unfl_ena_cont:
8251 fmov.l &0x0,%fpsr # clear FPSR
8252
8253 fmul.x FP_SCR0(%a6),%fp1 # execute multiply
8254
8255 fmov.l &0x0,%fpcr # clear FPCR
8256
8257 fmovm.x &0x40,FP_SCR0(%a6) # save result to stack
8258 mov.l %d2,-(%sp) # save d2
8259 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
8260 mov.l %d1,%d2 # make a copy
8261 andi.l &0x7fff,%d1 # strip sign
8262 andi.w &0x8000,%d2 # keep old sign
8263 sub.l %d0,%d1 # add scale factor
8264 addi.l &0x6000,%d1 # add bias
8265 andi.w &0x7fff,%d1
8266 or.w %d2,%d1 # concat old sign,new exp
8267 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
8268 mov.l (%sp)+,%d2 # restore d2
8269 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
8270 bra.w fmul_unfl_dis
8271
8272fmul_unfl_ena_sd:
8273 mov.l L_SCR3(%a6),%d1
8274 andi.b &0x30,%d1 # use only rnd mode
8275 fmov.l %d1,%fpcr # set FPCR
8276
8277 bra.b fmul_unfl_ena_cont
8278
8279# MAY UNDERFLOW:
8280# -use the correct rounding mode and precision. this code favors operations
8281# that do not underflow.
8282fmul_may_unfl:
8283 fmovm.x FP_SCR1(%a6),&0x80 # load dst operand
8284
8285 fmov.l L_SCR3(%a6),%fpcr # set FPCR
8286 fmov.l &0x0,%fpsr # clear FPSR
8287
8288 fmul.x FP_SCR0(%a6),%fp0 # execute multiply
8289
8290 fmov.l %fpsr,%d1 # save status
8291 fmov.l &0x0,%fpcr # clear FPCR
8292
8293 or.l %d1,USER_FPSR(%a6) # save INEX2,N
8294
8295 fabs.x %fp0,%fp1 # make a copy of result
8296 fcmp.b %fp1,&0x2 # is |result| > 2.b?
8297 fbgt.w fmul_normal_exit # no; no underflow occurred
8298 fblt.w fmul_unfl # yes; underflow occurred
8299
8300#
8301# we still don't know if underflow occurred. result is ~ equal to 2. but,
8302# we don't know if the result was an underflow that rounded up to a 2 or
8303# a normalized number that rounded down to a 2. so, redo the entire operation
8304# using RZ as the rounding mode to see what the pre-rounded result is.
8305# this case should be relatively rare.
8306#
8307 fmovm.x FP_SCR1(%a6),&0x40 # load dst operand
8308
8309 mov.l L_SCR3(%a6),%d1
8310 andi.b &0xc0,%d1 # keep rnd prec
8311 ori.b &rz_mode*0x10,%d1 # insert RZ
8312
8313 fmov.l %d1,%fpcr # set FPCR
8314 fmov.l &0x0,%fpsr # clear FPSR
8315
8316 fmul.x FP_SCR0(%a6),%fp1 # execute multiply
8317
8318 fmov.l &0x0,%fpcr # clear FPCR
8319 fabs.x %fp1 # make absolute value
8320 fcmp.b %fp1,&0x2 # is |result| < 2.b?
8321 fbge.w fmul_normal_exit # no; no underflow occurred
8322 bra.w fmul_unfl # yes, underflow occurred
8323
8324################################################################################
8325
8326#
8327# Multiply: inputs are not both normalized; what are they?
8328#
8329fmul_not_norm:
8330 mov.w (tbl_fmul_op.b,%pc,%d1.w*2),%d1
8331 jmp (tbl_fmul_op.b,%pc,%d1.w)
8332
8333 swbeg &48
8334tbl_fmul_op:
8335 short fmul_norm - tbl_fmul_op # NORM x NORM
8336 short fmul_zero - tbl_fmul_op # NORM x ZERO
8337 short fmul_inf_src - tbl_fmul_op # NORM x INF
8338 short fmul_res_qnan - tbl_fmul_op # NORM x QNAN
8339 short fmul_norm - tbl_fmul_op # NORM x DENORM
8340 short fmul_res_snan - tbl_fmul_op # NORM x SNAN
8341 short tbl_fmul_op - tbl_fmul_op #
8342 short tbl_fmul_op - tbl_fmul_op #
8343
8344 short fmul_zero - tbl_fmul_op # ZERO x NORM
8345 short fmul_zero - tbl_fmul_op # ZERO x ZERO
8346 short fmul_res_operr - tbl_fmul_op # ZERO x INF
8347 short fmul_res_qnan - tbl_fmul_op # ZERO x QNAN
8348 short fmul_zero - tbl_fmul_op # ZERO x DENORM
8349 short fmul_res_snan - tbl_fmul_op # ZERO x SNAN
8350 short tbl_fmul_op - tbl_fmul_op #
8351 short tbl_fmul_op - tbl_fmul_op #
8352
8353 short fmul_inf_dst - tbl_fmul_op # INF x NORM
8354 short fmul_res_operr - tbl_fmul_op # INF x ZERO
8355 short fmul_inf_dst - tbl_fmul_op # INF x INF
8356 short fmul_res_qnan - tbl_fmul_op # INF x QNAN
8357 short fmul_inf_dst - tbl_fmul_op # INF x DENORM
8358 short fmul_res_snan - tbl_fmul_op # INF x SNAN
8359 short tbl_fmul_op - tbl_fmul_op #
8360 short tbl_fmul_op - tbl_fmul_op #
8361
8362 short fmul_res_qnan - tbl_fmul_op # QNAN x NORM
8363 short fmul_res_qnan - tbl_fmul_op # QNAN x ZERO
8364 short fmul_res_qnan - tbl_fmul_op # QNAN x INF
8365 short fmul_res_qnan - tbl_fmul_op # QNAN x QNAN
8366 short fmul_res_qnan - tbl_fmul_op # QNAN x DENORM
8367 short fmul_res_snan - tbl_fmul_op # QNAN x SNAN
8368 short tbl_fmul_op - tbl_fmul_op #
8369 short tbl_fmul_op - tbl_fmul_op #
8370
8371 short fmul_norm - tbl_fmul_op # NORM x NORM
8372 short fmul_zero - tbl_fmul_op # NORM x ZERO
8373 short fmul_inf_src - tbl_fmul_op # NORM x INF
8374 short fmul_res_qnan - tbl_fmul_op # NORM x QNAN
8375 short fmul_norm - tbl_fmul_op # NORM x DENORM
8376 short fmul_res_snan - tbl_fmul_op # NORM x SNAN
8377 short tbl_fmul_op - tbl_fmul_op #
8378 short tbl_fmul_op - tbl_fmul_op #
8379
8380 short fmul_res_snan - tbl_fmul_op # SNAN x NORM
8381 short fmul_res_snan - tbl_fmul_op # SNAN x ZERO
8382 short fmul_res_snan - tbl_fmul_op # SNAN x INF
8383 short fmul_res_snan - tbl_fmul_op # SNAN x QNAN
8384 short fmul_res_snan - tbl_fmul_op # SNAN x DENORM
8385 short fmul_res_snan - tbl_fmul_op # SNAN x SNAN
8386 short tbl_fmul_op - tbl_fmul_op #
8387 short tbl_fmul_op - tbl_fmul_op #
8388
8389fmul_res_operr:
8390 bra.l res_operr
8391fmul_res_snan:
8392 bra.l res_snan
8393fmul_res_qnan:
8394 bra.l res_qnan
8395
8396#
8397# Multiply: (Zero x Zero) || (Zero x norm) || (Zero x denorm)
8398#
8399 global fmul_zero # global for fsglmul
8400fmul_zero:
8401 mov.b SRC_EX(%a0),%d0 # exclusive or the signs
8402 mov.b DST_EX(%a1),%d1
8403 eor.b %d0,%d1
8404 bpl.b fmul_zero_p # result ZERO is pos.
8405fmul_zero_n:
8406 fmov.s &0x80000000,%fp0 # load -ZERO
8407 mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/N
8408 rts
8409fmul_zero_p:
8410 fmov.s &0x00000000,%fp0 # load +ZERO
8411 mov.b &z_bmask,FPSR_CC(%a6) # set Z
8412 rts
8413
8414#
8415# Multiply: (inf x inf) || (inf x norm) || (inf x denorm)
8416#
8417# Note: The j-bit for an infinity is a don't-care. However, to be
8418# strictly compatible w/ the 68881/882, we make sure to return an
8419# INF w/ the j-bit set if the input INF j-bit was set. Destination
8420# INFs take priority.
8421#
8422 global fmul_inf_dst # global for fsglmul
8423fmul_inf_dst:
8424 fmovm.x DST(%a1),&0x80 # return INF result in fp0
8425 mov.b SRC_EX(%a0),%d0 # exclusive or the signs
8426 mov.b DST_EX(%a1),%d1
8427 eor.b %d0,%d1
8428 bpl.b fmul_inf_dst_p # result INF is pos.
8429fmul_inf_dst_n:
8430 fabs.x %fp0 # clear result sign
8431 fneg.x %fp0 # set result sign
8432 mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/N
8433 rts
8434fmul_inf_dst_p:
8435 fabs.x %fp0 # clear result sign
8436 mov.b &inf_bmask,FPSR_CC(%a6) # set INF
8437 rts
8438
8439 global fmul_inf_src # global for fsglmul
8440fmul_inf_src:
8441 fmovm.x SRC(%a0),&0x80 # return INF result in fp0
8442 mov.b SRC_EX(%a0),%d0 # exclusive or the signs
8443 mov.b DST_EX(%a1),%d1
8444 eor.b %d0,%d1
8445 bpl.b fmul_inf_dst_p # result INF is pos.
8446 bra.b fmul_inf_dst_n
8447
8448#########################################################################
8449# XDEF **************************************************************** #
8450# fin(): emulates the fmove instruction #
8451# fsin(): emulates the fsmove instruction #
8452# fdin(): emulates the fdmove instruction #
8453# #
8454# XREF **************************************************************** #
8455# norm() - normalize mantissa for EXOP on denorm #
8456# scale_to_zero_src() - scale src exponent to zero #
8457# ovf_res() - return default overflow result #
8458# unf_res() - return default underflow result #
8459# res_qnan_1op() - return QNAN result #
8460# res_snan_1op() - return SNAN result #
8461# #
8462# INPUT *************************************************************** #
8463# a0 = pointer to extended precision source operand #
8464# d0 = round prec/mode #
8465# #
8466# OUTPUT ************************************************************** #
8467# fp0 = result #
8468# fp1 = EXOP (if exception occurred) #
8469# #
8470# ALGORITHM *********************************************************** #
8471# Handle NANs, infinities, and zeroes as special cases. Divide #
8472# norms into extended, single, and double precision. #
8473# Norms can be emulated w/ a regular fmove instruction. For #
8474# sgl/dbl, must scale exponent and perform an "fmove". Check to see #
8475# if the result would have overflowed/underflowed. If so, use unf_res() #
8476# or ovf_res() to return the default result. Also return EXOP if #
8477# exception is enabled. If no exception, return the default result. #
8478# Unnorms don't pass through here. #
8479# #
8480#########################################################################
8481
8482 global fsin
8483fsin:
8484 andi.b &0x30,%d0 # clear rnd prec
8485 ori.b &s_mode*0x10,%d0 # insert sgl precision
8486 bra.b fin
8487
8488 global fdin
8489fdin:
8490 andi.b &0x30,%d0 # clear rnd prec
8491 ori.b &d_mode*0x10,%d0 # insert dbl precision
8492
8493 global fin
8494fin:
8495 mov.l %d0,L_SCR3(%a6) # store rnd info
8496
8497 mov.b STAG(%a6),%d1 # fetch src optype tag
8498 bne.w fin_not_norm # optimize on non-norm input
8499
8500#
8501# FP MOVE IN: NORMs and DENORMs ONLY!
8502#
8503fin_norm:
8504 andi.b &0xc0,%d0 # is precision extended?
8505 bne.w fin_not_ext # no, so go handle dbl or sgl
8506
8507#
8508# precision selected is extended. so...we cannot get an underflow
8509# or overflow because of rounding to the correct precision. so...
8510# skip the scaling and unscaling...
8511#
8512 tst.b SRC_EX(%a0) # is the operand negative?
8513 bpl.b fin_norm_done # no
8514 bset &neg_bit,FPSR_CC(%a6) # yes, so set 'N' ccode bit
8515fin_norm_done:
8516 fmovm.x SRC(%a0),&0x80 # return result in fp0
8517 rts
8518
8519#
8520# for an extended precision DENORM, the UNFL exception bit is set
8521# the accrued bit is NOT set in this instance(no inexactness!)
8522#
8523fin_denorm:
8524 andi.b &0xc0,%d0 # is precision extended?
8525 bne.w fin_not_ext # no, so go handle dbl or sgl
8526
8527 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
8528 tst.b SRC_EX(%a0) # is the operand negative?
8529 bpl.b fin_denorm_done # no
8530 bset &neg_bit,FPSR_CC(%a6) # yes, so set 'N' ccode bit
8531fin_denorm_done:
8532 fmovm.x SRC(%a0),&0x80 # return result in fp0
8533 btst &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled?
8534 bne.b fin_denorm_unfl_ena # yes
8535 rts
8536
8537#
8538# the input is an extended DENORM and underflow is enabled in the FPCR.
8539# normalize the mantissa and add the bias of 0x6000 to the resulting negative
8540# exponent and insert back into the operand.
8541#
8542fin_denorm_unfl_ena:
8543 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
8544 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
8545 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
8546 lea FP_SCR0(%a6),%a0 # pass: ptr to operand
8547 bsr.l norm # normalize result
8548 neg.w %d0 # new exponent = -(shft val)
8549 addi.w &0x6000,%d0 # add new bias to exponent
8550 mov.w FP_SCR0_EX(%a6),%d1 # fetch old sign,exp
8551 andi.w &0x8000,%d1 # keep old sign
8552 andi.w &0x7fff,%d0 # clear sign position
8553 or.w %d1,%d0 # concat new exo,old sign
8554 mov.w %d0,FP_SCR0_EX(%a6) # insert new exponent
8555 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
8556 rts
8557
8558#
8559# operand is to be rounded to single or double precision
8560#
8561fin_not_ext:
8562 cmpi.b %d0,&s_mode*0x10 # separate sgl/dbl prec
8563 bne.b fin_dbl
8564
8565#
8566# operand is to be rounded to single precision
8567#
8568fin_sgl:
8569 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
8570 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
8571 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
8572 bsr.l scale_to_zero_src # calculate scale factor
8573
8574 cmpi.l %d0,&0x3fff-0x3f80 # will move in underflow?
8575 bge.w fin_sd_unfl # yes; go handle underflow
8576 cmpi.l %d0,&0x3fff-0x407e # will move in overflow?
8577 beq.w fin_sd_may_ovfl # maybe; go check
8578 blt.w fin_sd_ovfl # yes; go handle overflow
8579
8580#
8581# operand will NOT overflow or underflow when moved into the fp reg file
8582#
8583fin_sd_normal:
8584 fmov.l &0x0,%fpsr # clear FPSR
8585 fmov.l L_SCR3(%a6),%fpcr # set FPCR
8586
8587 fmov.x FP_SCR0(%a6),%fp0 # perform move
8588
8589 fmov.l %fpsr,%d1 # save FPSR
8590 fmov.l &0x0,%fpcr # clear FPCR
8591
8592 or.l %d1,USER_FPSR(%a6) # save INEX2,N
8593
8594fin_sd_normal_exit:
8595 mov.l %d2,-(%sp) # save d2
8596 fmovm.x &0x80,FP_SCR0(%a6) # store out result
8597 mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp}
8598 mov.w %d1,%d2 # make a copy
8599 andi.l &0x7fff,%d1 # strip sign
8600 sub.l %d0,%d1 # add scale factor
8601 andi.w &0x8000,%d2 # keep old sign
8602 or.w %d1,%d2 # concat old sign,new exponent
8603 mov.w %d2,FP_SCR0_EX(%a6) # insert new exponent
8604 mov.l (%sp)+,%d2 # restore d2
8605 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
8606 rts
8607
8608#
8609# operand is to be rounded to double precision
8610#
8611fin_dbl:
8612 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
8613 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
8614 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
8615 bsr.l scale_to_zero_src # calculate scale factor
8616
8617 cmpi.l %d0,&0x3fff-0x3c00 # will move in underflow?
8618 bge.w fin_sd_unfl # yes; go handle underflow
8619 cmpi.l %d0,&0x3fff-0x43fe # will move in overflow?
8620 beq.w fin_sd_may_ovfl # maybe; go check
8621 blt.w fin_sd_ovfl # yes; go handle overflow
8622 bra.w fin_sd_normal # no; ho handle normalized op
8623
8624#
8625# operand WILL underflow when moved in to the fp register file
8626#
8627fin_sd_unfl:
8628 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
8629
8630 tst.b FP_SCR0_EX(%a6) # is operand negative?
8631 bpl.b fin_sd_unfl_tst
8632 bset &neg_bit,FPSR_CC(%a6) # set 'N' ccode bit
8633
8634# if underflow or inexact is enabled, then go calculate the EXOP first.
8635fin_sd_unfl_tst:
8636 mov.b FPCR_ENABLE(%a6),%d1
8637 andi.b &0x0b,%d1 # is UNFL or INEX enabled?
8638 bne.b fin_sd_unfl_ena # yes
8639
8640fin_sd_unfl_dis:
8641 lea FP_SCR0(%a6),%a0 # pass: result addr
8642 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
8643 bsr.l unf_res # calculate default result
8644 or.b %d0,FPSR_CC(%a6) # unf_res may have set 'Z'
8645 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
8646 rts
8647
8648#
8649# operand will underflow AND underflow or inexact is enabled.
8650# therefore, we must return the result rounded to extended precision.
8651#
8652fin_sd_unfl_ena:
8653 mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
8654 mov.l FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
8655 mov.w FP_SCR0_EX(%a6),%d1 # load current exponent
8656
8657 mov.l %d2,-(%sp) # save d2
8658 mov.w %d1,%d2 # make a copy
8659 andi.l &0x7fff,%d1 # strip sign
8660 sub.l %d0,%d1 # subtract scale factor
8661 andi.w &0x8000,%d2 # extract old sign
8662 addi.l &0x6000,%d1 # add new bias
8663 andi.w &0x7fff,%d1
8664 or.w %d1,%d2 # concat old sign,new exp
8665 mov.w %d2,FP_SCR1_EX(%a6) # insert new exponent
8666 fmovm.x FP_SCR1(%a6),&0x40 # return EXOP in fp1
8667 mov.l (%sp)+,%d2 # restore d2
8668 bra.b fin_sd_unfl_dis
8669
8670#
8671# operand WILL overflow.
8672#
8673fin_sd_ovfl:
8674 fmov.l &0x0,%fpsr # clear FPSR
8675 fmov.l L_SCR3(%a6),%fpcr # set FPCR
8676
8677 fmov.x FP_SCR0(%a6),%fp0 # perform move
8678
8679 fmov.l &0x0,%fpcr # clear FPCR
8680 fmov.l %fpsr,%d1 # save FPSR
8681
8682 or.l %d1,USER_FPSR(%a6) # save INEX2,N
8683
8684fin_sd_ovfl_tst:
8685 or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
8686
8687 mov.b FPCR_ENABLE(%a6),%d1
8688 andi.b &0x13,%d1 # is OVFL or INEX enabled?
8689 bne.b fin_sd_ovfl_ena # yes
8690
8691#
8692# OVFL is not enabled; therefore, we must create the default result by
8693# calling ovf_res().
8694#
8695fin_sd_ovfl_dis:
8696 btst &neg_bit,FPSR_CC(%a6) # is result negative?
8697 sne %d1 # set sign param accordingly
8698 mov.l L_SCR3(%a6),%d0 # pass: prec,mode
8699 bsr.l ovf_res # calculate default result
8700 or.b %d0,FPSR_CC(%a6) # set INF,N if applicable
8701 fmovm.x (%a0),&0x80 # return default result in fp0
8702 rts
8703
8704#
8705# OVFL is enabled.
8706# the INEX2 bit has already been updated by the round to the correct precision.
8707# now, round to extended(and don't alter the FPSR).
8708#
8709fin_sd_ovfl_ena:
8710 mov.l %d2,-(%sp) # save d2
8711 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
8712 mov.l %d1,%d2 # make a copy
8713 andi.l &0x7fff,%d1 # strip sign
8714 andi.w &0x8000,%d2 # keep old sign
8715 sub.l %d0,%d1 # add scale factor
8716 sub.l &0x6000,%d1 # subtract bias
8717 andi.w &0x7fff,%d1
8718 or.w %d2,%d1
8719 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
8720 mov.l (%sp)+,%d2 # restore d2
8721 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
8722 bra.b fin_sd_ovfl_dis
8723
8724#
8725# the move in MAY overflow. so...
8726#
8727fin_sd_may_ovfl:
8728 fmov.l &0x0,%fpsr # clear FPSR
8729 fmov.l L_SCR3(%a6),%fpcr # set FPCR
8730
8731 fmov.x FP_SCR0(%a6),%fp0 # perform the move
8732
8733 fmov.l %fpsr,%d1 # save status
8734 fmov.l &0x0,%fpcr # clear FPCR
8735
8736 or.l %d1,USER_FPSR(%a6) # save INEX2,N
8737
8738 fabs.x %fp0,%fp1 # make a copy of result
8739 fcmp.b %fp1,&0x2 # is |result| >= 2.b?
8740 fbge.w fin_sd_ovfl_tst # yes; overflow has occurred
8741
8742# no, it didn't overflow; we have correct result
8743 bra.w fin_sd_normal_exit
8744
8745##########################################################################
8746
8747#
8748# operand is not a NORM: check its optype and branch accordingly
8749#
8750fin_not_norm:
8751 cmpi.b %d1,&DENORM # weed out DENORM
8752 beq.w fin_denorm
8753 cmpi.b %d1,&SNAN # weed out SNANs
8754 beq.l res_snan_1op
8755 cmpi.b %d1,&QNAN # weed out QNANs
8756 beq.l res_qnan_1op
8757
8758#
8759# do the fmove in; at this point, only possible ops are ZERO and INF.
8760# use fmov to determine ccodes.
8761# prec:mode should be zero at this point but it won't affect answer anyways.
8762#
8763 fmov.x SRC(%a0),%fp0 # do fmove in
8764 fmov.l %fpsr,%d0 # no exceptions possible
8765 rol.l &0x8,%d0 # put ccodes in lo byte
8766 mov.b %d0,FPSR_CC(%a6) # insert correct ccodes
8767 rts
8768
8769#########################################################################
8770# XDEF **************************************************************** #
8771# fdiv(): emulates the fdiv instruction #
8772# fsdiv(): emulates the fsdiv instruction #
8773# fddiv(): emulates the fddiv instruction #
8774# #
8775# XREF **************************************************************** #
8776# scale_to_zero_src() - scale src exponent to zero #
8777# scale_to_zero_dst() - scale dst exponent to zero #
8778# unf_res() - return default underflow result #
8779# ovf_res() - return default overflow result #
8780# res_qnan() - return QNAN result #
8781# res_snan() - return SNAN result #
8782# #
8783# INPUT *************************************************************** #
8784# a0 = pointer to extended precision source operand #
8785# a1 = pointer to extended precision destination operand #
8786# d0 rnd prec,mode #
8787# #
8788# OUTPUT ************************************************************** #
8789# fp0 = result #
8790# fp1 = EXOP (if exception occurred) #
8791# #
8792# ALGORITHM *********************************************************** #
8793# Handle NANs, infinities, and zeroes as special cases. Divide #
8794# norms/denorms into ext/sgl/dbl precision. #
8795# For norms/denorms, scale the exponents such that a divide #
8796# instruction won't cause an exception. Use the regular fdiv to #
8797# compute a result. Check if the regular operands would have taken #
8798# an exception. If so, return the default overflow/underflow result #
8799# and return the EXOP if exceptions are enabled. Else, scale the #
8800# result operand to the proper exponent. #
8801# #
8802#########################################################################
8803
8804 align 0x10
8805tbl_fdiv_unfl:
8806 long 0x3fff - 0x0000 # ext_unfl
8807 long 0x3fff - 0x3f81 # sgl_unfl
8808 long 0x3fff - 0x3c01 # dbl_unfl
8809
8810tbl_fdiv_ovfl:
8811 long 0x3fff - 0x7ffe # ext overflow exponent
8812 long 0x3fff - 0x407e # sgl overflow exponent
8813 long 0x3fff - 0x43fe # dbl overflow exponent
8814
8815 global fsdiv
8816fsdiv:
8817 andi.b &0x30,%d0 # clear rnd prec
8818 ori.b &s_mode*0x10,%d0 # insert sgl prec
8819 bra.b fdiv
8820
8821 global fddiv
8822fddiv:
8823 andi.b &0x30,%d0 # clear rnd prec
8824 ori.b &d_mode*0x10,%d0 # insert dbl prec
8825
8826 global fdiv
8827fdiv:
8828 mov.l %d0,L_SCR3(%a6) # store rnd info
8829
8830 clr.w %d1
8831 mov.b DTAG(%a6),%d1
8832 lsl.b &0x3,%d1
8833 or.b STAG(%a6),%d1 # combine src tags
8834
8835 bne.w fdiv_not_norm # optimize on non-norm input
8836
8837#
8838# DIVIDE: NORMs and DENORMs ONLY!
8839#
8840fdiv_norm:
8841 mov.w DST_EX(%a1),FP_SCR1_EX(%a6)
8842 mov.l DST_HI(%a1),FP_SCR1_HI(%a6)
8843 mov.l DST_LO(%a1),FP_SCR1_LO(%a6)
8844
8845 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
8846 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
8847 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
8848
8849 bsr.l scale_to_zero_src # scale src exponent
8850 mov.l %d0,-(%sp) # save scale factor 1
8851
8852 bsr.l scale_to_zero_dst # scale dst exponent
8853
8854 neg.l (%sp) # SCALE FACTOR = scale1 - scale2
8855 add.l %d0,(%sp)
8856
8857 mov.w 2+L_SCR3(%a6),%d1 # fetch precision
8858 lsr.b &0x6,%d1 # shift to lo bits
8859 mov.l (%sp)+,%d0 # load S.F.
8860 cmp.l %d0,(tbl_fdiv_ovfl.b,%pc,%d1.w*4) # will result overflow?
8861 ble.w fdiv_may_ovfl # result will overflow
8862
8863 cmp.l %d0,(tbl_fdiv_unfl.w,%pc,%d1.w*4) # will result underflow?
8864 beq.w fdiv_may_unfl # maybe
8865 bgt.w fdiv_unfl # yes; go handle underflow
8866
8867fdiv_normal:
8868 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
8869
8870 fmov.l L_SCR3(%a6),%fpcr # save FPCR
8871 fmov.l &0x0,%fpsr # clear FPSR
8872
8873 fdiv.x FP_SCR0(%a6),%fp0 # perform divide
8874
8875 fmov.l %fpsr,%d1 # save FPSR
8876 fmov.l &0x0,%fpcr # clear FPCR
8877
8878 or.l %d1,USER_FPSR(%a6) # save INEX2,N
8879
8880fdiv_normal_exit:
8881 fmovm.x &0x80,FP_SCR0(%a6) # store result on stack
8882 mov.l %d2,-(%sp) # store d2
8883 mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp}
8884 mov.l %d1,%d2 # make a copy
8885 andi.l &0x7fff,%d1 # strip sign
8886 andi.w &0x8000,%d2 # keep old sign
8887 sub.l %d0,%d1 # add scale factor
8888 or.w %d2,%d1 # concat old sign,new exp
8889 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
8890 mov.l (%sp)+,%d2 # restore d2
8891 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
8892 rts
8893
8894tbl_fdiv_ovfl2:
8895 long 0x7fff
8896 long 0x407f
8897 long 0x43ff
8898
8899fdiv_no_ovfl:
8900 mov.l (%sp)+,%d0 # restore scale factor
8901 bra.b fdiv_normal_exit
8902
8903fdiv_may_ovfl:
8904 mov.l %d0,-(%sp) # save scale factor
8905
8906 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
8907
8908 fmov.l L_SCR3(%a6),%fpcr # set FPCR
8909 fmov.l &0x0,%fpsr # set FPSR
8910
8911 fdiv.x FP_SCR0(%a6),%fp0 # execute divide
8912
8913 fmov.l %fpsr,%d0
8914 fmov.l &0x0,%fpcr
8915
8916 or.l %d0,USER_FPSR(%a6) # save INEX,N
8917
8918 fmovm.x &0x01,-(%sp) # save result to stack
8919 mov.w (%sp),%d0 # fetch new exponent
8920 add.l &0xc,%sp # clear result from stack
8921 andi.l &0x7fff,%d0 # strip sign
8922 sub.l (%sp),%d0 # add scale factor
8923 cmp.l %d0,(tbl_fdiv_ovfl2.b,%pc,%d1.w*4)
8924 blt.b fdiv_no_ovfl
8925 mov.l (%sp)+,%d0
8926
8927fdiv_ovfl_tst:
8928 or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
8929
8930 mov.b FPCR_ENABLE(%a6),%d1
8931 andi.b &0x13,%d1 # is OVFL or INEX enabled?
8932 bne.b fdiv_ovfl_ena # yes
8933
8934fdiv_ovfl_dis:
8935 btst &neg_bit,FPSR_CC(%a6) # is result negative?
8936 sne %d1 # set sign param accordingly
8937 mov.l L_SCR3(%a6),%d0 # pass prec:rnd
8938 bsr.l ovf_res # calculate default result
8939 or.b %d0,FPSR_CC(%a6) # set INF if applicable
8940 fmovm.x (%a0),&0x80 # return default result in fp0
8941 rts
8942
8943fdiv_ovfl_ena:
8944 mov.l L_SCR3(%a6),%d1
8945 andi.b &0xc0,%d1 # is precision extended?
8946 bne.b fdiv_ovfl_ena_sd # no, do sgl or dbl
8947
8948fdiv_ovfl_ena_cont:
8949 fmovm.x &0x80,FP_SCR0(%a6) # move result to stack
8950
8951 mov.l %d2,-(%sp) # save d2
8952 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
8953 mov.w %d1,%d2 # make a copy
8954 andi.l &0x7fff,%d1 # strip sign
8955 sub.l %d0,%d1 # add scale factor
8956 subi.l &0x6000,%d1 # subtract bias
8957 andi.w &0x7fff,%d1 # clear sign bit
8958 andi.w &0x8000,%d2 # keep old sign
8959 or.w %d2,%d1 # concat old sign,new exp
8960 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
8961 mov.l (%sp)+,%d2 # restore d2
8962 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
8963 bra.b fdiv_ovfl_dis
8964
8965fdiv_ovfl_ena_sd:
8966 fmovm.x FP_SCR1(%a6),&0x80 # load dst operand
8967
8968 mov.l L_SCR3(%a6),%d1
8969 andi.b &0x30,%d1 # keep rnd mode
8970 fmov.l %d1,%fpcr # set FPCR
8971
8972 fdiv.x FP_SCR0(%a6),%fp0 # execute divide
8973
8974 fmov.l &0x0,%fpcr # clear FPCR
8975 bra.b fdiv_ovfl_ena_cont
8976
8977fdiv_unfl:
8978 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
8979
8980 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
8981
8982 fmov.l &rz_mode*0x10,%fpcr # set FPCR
8983 fmov.l &0x0,%fpsr # clear FPSR
8984
8985 fdiv.x FP_SCR0(%a6),%fp0 # execute divide
8986
8987 fmov.l %fpsr,%d1 # save status
8988 fmov.l &0x0,%fpcr # clear FPCR
8989
8990 or.l %d1,USER_FPSR(%a6) # save INEX2,N
8991
8992 mov.b FPCR_ENABLE(%a6),%d1
8993 andi.b &0x0b,%d1 # is UNFL or INEX enabled?
8994 bne.b fdiv_unfl_ena # yes
8995
8996fdiv_unfl_dis:
8997 fmovm.x &0x80,FP_SCR0(%a6) # store out result
8998
8999 lea FP_SCR0(%a6),%a0 # pass: result addr
9000 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
9001 bsr.l unf_res # calculate default result
9002 or.b %d0,FPSR_CC(%a6) # 'Z' may have been set
9003 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
9004 rts
9005
9006#
9007# UNFL is enabled.
9008#
9009fdiv_unfl_ena:
9010 fmovm.x FP_SCR1(%a6),&0x40 # load dst op
9011
9012 mov.l L_SCR3(%a6),%d1
9013 andi.b &0xc0,%d1 # is precision extended?
9014 bne.b fdiv_unfl_ena_sd # no, sgl or dbl
9015
9016 fmov.l L_SCR3(%a6),%fpcr # set FPCR
9017
9018fdiv_unfl_ena_cont:
9019 fmov.l &0x0,%fpsr # clear FPSR
9020
9021 fdiv.x FP_SCR0(%a6),%fp1 # execute divide
9022
9023 fmov.l &0x0,%fpcr # clear FPCR
9024
9025 fmovm.x &0x40,FP_SCR0(%a6) # save result to stack
9026 mov.l %d2,-(%sp) # save d2
9027 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
9028 mov.l %d1,%d2 # make a copy
9029 andi.l &0x7fff,%d1 # strip sign
9030 andi.w &0x8000,%d2 # keep old sign
9031 sub.l %d0,%d1 # add scale factoer
9032 addi.l &0x6000,%d1 # add bias
9033 andi.w &0x7fff,%d1
9034 or.w %d2,%d1 # concat old sign,new exp
9035 mov.w %d1,FP_SCR0_EX(%a6) # insert new exp
9036 mov.l (%sp)+,%d2 # restore d2
9037 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
9038 bra.w fdiv_unfl_dis
9039
9040fdiv_unfl_ena_sd:
9041 mov.l L_SCR3(%a6),%d1
9042 andi.b &0x30,%d1 # use only rnd mode
9043 fmov.l %d1,%fpcr # set FPCR
9044
9045 bra.b fdiv_unfl_ena_cont
9046
9047#
9048# the divide operation MAY underflow:
9049#
9050fdiv_may_unfl:
9051 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
9052
9053 fmov.l L_SCR3(%a6),%fpcr # set FPCR
9054 fmov.l &0x0,%fpsr # clear FPSR
9055
9056 fdiv.x FP_SCR0(%a6),%fp0 # execute divide
9057
9058 fmov.l %fpsr,%d1 # save status
9059 fmov.l &0x0,%fpcr # clear FPCR
9060
9061 or.l %d1,USER_FPSR(%a6) # save INEX2,N
9062
9063 fabs.x %fp0,%fp1 # make a copy of result
9064 fcmp.b %fp1,&0x1 # is |result| > 1.b?
9065 fbgt.w fdiv_normal_exit # no; no underflow occurred
9066 fblt.w fdiv_unfl # yes; underflow occurred
9067
9068#
9069# we still don't know if underflow occurred. result is ~ equal to 1. but,
9070# we don't know if the result was an underflow that rounded up to a 1
9071# or a normalized number that rounded down to a 1. so, redo the entire
9072# operation using RZ as the rounding mode to see what the pre-rounded
9073# result is. this case should be relatively rare.
9074#
9075 fmovm.x FP_SCR1(%a6),&0x40 # load dst op into fp1
9076
9077 mov.l L_SCR3(%a6),%d1
9078 andi.b &0xc0,%d1 # keep rnd prec
9079 ori.b &rz_mode*0x10,%d1 # insert RZ
9080
9081 fmov.l %d1,%fpcr # set FPCR
9082 fmov.l &0x0,%fpsr # clear FPSR
9083
9084 fdiv.x FP_SCR0(%a6),%fp1 # execute divide
9085
9086 fmov.l &0x0,%fpcr # clear FPCR
9087 fabs.x %fp1 # make absolute value
9088 fcmp.b %fp1,&0x1 # is |result| < 1.b?
9089 fbge.w fdiv_normal_exit # no; no underflow occurred
9090 bra.w fdiv_unfl # yes; underflow occurred
9091
9092############################################################################
9093
9094#
9095# Divide: inputs are not both normalized; what are they?
9096#
9097fdiv_not_norm:
9098 mov.w (tbl_fdiv_op.b,%pc,%d1.w*2),%d1
9099 jmp (tbl_fdiv_op.b,%pc,%d1.w*1)
9100
9101 swbeg &48
9102tbl_fdiv_op:
9103 short fdiv_norm - tbl_fdiv_op # NORM / NORM
9104 short fdiv_inf_load - tbl_fdiv_op # NORM / ZERO
9105 short fdiv_zero_load - tbl_fdiv_op # NORM / INF
9106 short fdiv_res_qnan - tbl_fdiv_op # NORM / QNAN
9107 short fdiv_norm - tbl_fdiv_op # NORM / DENORM
9108 short fdiv_res_snan - tbl_fdiv_op # NORM / SNAN
9109 short tbl_fdiv_op - tbl_fdiv_op #
9110 short tbl_fdiv_op - tbl_fdiv_op #
9111
9112 short fdiv_zero_load - tbl_fdiv_op # ZERO / NORM
9113 short fdiv_res_operr - tbl_fdiv_op # ZERO / ZERO
9114 short fdiv_zero_load - tbl_fdiv_op # ZERO / INF
9115 short fdiv_res_qnan - tbl_fdiv_op # ZERO / QNAN
9116 short fdiv_zero_load - tbl_fdiv_op # ZERO / DENORM
9117 short fdiv_res_snan - tbl_fdiv_op # ZERO / SNAN
9118 short tbl_fdiv_op - tbl_fdiv_op #
9119 short tbl_fdiv_op - tbl_fdiv_op #
9120
9121 short fdiv_inf_dst - tbl_fdiv_op # INF / NORM
9122 short fdiv_inf_dst - tbl_fdiv_op # INF / ZERO
9123 short fdiv_res_operr - tbl_fdiv_op # INF / INF
9124 short fdiv_res_qnan - tbl_fdiv_op # INF / QNAN
9125 short fdiv_inf_dst - tbl_fdiv_op # INF / DENORM
9126 short fdiv_res_snan - tbl_fdiv_op # INF / SNAN
9127 short tbl_fdiv_op - tbl_fdiv_op #
9128 short tbl_fdiv_op - tbl_fdiv_op #
9129
9130 short fdiv_res_qnan - tbl_fdiv_op # QNAN / NORM
9131 short fdiv_res_qnan - tbl_fdiv_op # QNAN / ZERO
9132 short fdiv_res_qnan - tbl_fdiv_op # QNAN / INF
9133 short fdiv_res_qnan - tbl_fdiv_op # QNAN / QNAN
9134 short fdiv_res_qnan - tbl_fdiv_op # QNAN / DENORM
9135 short fdiv_res_snan - tbl_fdiv_op # QNAN / SNAN
9136 short tbl_fdiv_op - tbl_fdiv_op #
9137 short tbl_fdiv_op - tbl_fdiv_op #
9138
9139 short fdiv_norm - tbl_fdiv_op # DENORM / NORM
9140 short fdiv_inf_load - tbl_fdiv_op # DENORM / ZERO
9141 short fdiv_zero_load - tbl_fdiv_op # DENORM / INF
9142 short fdiv_res_qnan - tbl_fdiv_op # DENORM / QNAN
9143 short fdiv_norm - tbl_fdiv_op # DENORM / DENORM
9144 short fdiv_res_snan - tbl_fdiv_op # DENORM / SNAN
9145 short tbl_fdiv_op - tbl_fdiv_op #
9146 short tbl_fdiv_op - tbl_fdiv_op #
9147
9148 short fdiv_res_snan - tbl_fdiv_op # SNAN / NORM
9149 short fdiv_res_snan - tbl_fdiv_op # SNAN / ZERO
9150 short fdiv_res_snan - tbl_fdiv_op # SNAN / INF
9151 short fdiv_res_snan - tbl_fdiv_op # SNAN / QNAN
9152 short fdiv_res_snan - tbl_fdiv_op # SNAN / DENORM
9153 short fdiv_res_snan - tbl_fdiv_op # SNAN / SNAN
9154 short tbl_fdiv_op - tbl_fdiv_op #
9155 short tbl_fdiv_op - tbl_fdiv_op #
9156
9157fdiv_res_qnan:
9158 bra.l res_qnan
9159fdiv_res_snan:
9160 bra.l res_snan
9161fdiv_res_operr:
9162 bra.l res_operr
9163
9164 global fdiv_zero_load # global for fsgldiv
9165fdiv_zero_load:
9166 mov.b SRC_EX(%a0),%d0 # result sign is exclusive
9167 mov.b DST_EX(%a1),%d1 # or of input signs.
9168 eor.b %d0,%d1
9169 bpl.b fdiv_zero_load_p # result is positive
9170 fmov.s &0x80000000,%fp0 # load a -ZERO
9171 mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/N
9172 rts
9173fdiv_zero_load_p:
9174 fmov.s &0x00000000,%fp0 # load a +ZERO
9175 mov.b &z_bmask,FPSR_CC(%a6) # set Z
9176 rts
9177
9178#
9179# The destination was In Range and the source was a ZERO. The result,
9180# therefore, is an INF w/ the proper sign.
9181# So, determine the sign and return a new INF (w/ the j-bit cleared).
9182#
9183 global fdiv_inf_load # global for fsgldiv
9184fdiv_inf_load:
9185 ori.w &dz_mask+adz_mask,2+USER_FPSR(%a6) # no; set DZ/ADZ
9186 mov.b SRC_EX(%a0),%d0 # load both signs
9187 mov.b DST_EX(%a1),%d1
9188 eor.b %d0,%d1
9189 bpl.b fdiv_inf_load_p # result is positive
9190 fmov.s &0xff800000,%fp0 # make result -INF
9191 mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/N
9192 rts
9193fdiv_inf_load_p:
9194 fmov.s &0x7f800000,%fp0 # make result +INF
9195 mov.b &inf_bmask,FPSR_CC(%a6) # set INF
9196 rts
9197
9198#
9199# The destination was an INF w/ an In Range or ZERO source, the result is
9200# an INF w/ the proper sign.
9201# The 68881/882 returns the destination INF w/ the new sign(if the j-bit of the
9202# dst INF is set, then then j-bit of the result INF is also set).
9203#
9204 global fdiv_inf_dst # global for fsgldiv
9205fdiv_inf_dst:
9206 mov.b DST_EX(%a1),%d0 # load both signs
9207 mov.b SRC_EX(%a0),%d1
9208 eor.b %d0,%d1
9209 bpl.b fdiv_inf_dst_p # result is positive
9210
9211 fmovm.x DST(%a1),&0x80 # return result in fp0
9212 fabs.x %fp0 # clear sign bit
9213 fneg.x %fp0 # set sign bit
9214 mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/NEG
9215 rts
9216
9217fdiv_inf_dst_p:
9218 fmovm.x DST(%a1),&0x80 # return result in fp0
9219 fabs.x %fp0 # return positive INF
9220 mov.b &inf_bmask,FPSR_CC(%a6) # set INF
9221 rts
9222
9223#########################################################################
9224# XDEF **************************************************************** #
9225# fneg(): emulates the fneg instruction #
9226# fsneg(): emulates the fsneg instruction #
9227# fdneg(): emulates the fdneg instruction #
9228# #
9229# XREF **************************************************************** #
9230# norm() - normalize a denorm to provide EXOP #
9231# scale_to_zero_src() - scale sgl/dbl source exponent #
9232# ovf_res() - return default overflow result #
9233# unf_res() - return default underflow result #
9234# res_qnan_1op() - return QNAN result #
9235# res_snan_1op() - return SNAN result #
9236# #
9237# INPUT *************************************************************** #
9238# a0 = pointer to extended precision source operand #
9239# d0 = rnd prec,mode #
9240# #
9241# OUTPUT ************************************************************** #
9242# fp0 = result #
9243# fp1 = EXOP (if exception occurred) #
9244# #
9245# ALGORITHM *********************************************************** #
9246# Handle NANs, zeroes, and infinities as special cases. Separate #
9247# norms/denorms into ext/sgl/dbl precisions. Extended precision can be #
9248# emulated by simply setting sign bit. Sgl/dbl operands must be scaled #
9249# and an actual fneg performed to see if overflow/underflow would have #
9250# occurred. If so, return default underflow/overflow result. Else, #
9251# scale the result exponent and return result. FPSR gets set based on #
9252# the result value. #
9253# #
9254#########################################################################
9255
9256 global fsneg
9257fsneg:
9258 andi.b &0x30,%d0 # clear rnd prec
9259 ori.b &s_mode*0x10,%d0 # insert sgl precision
9260 bra.b fneg
9261
9262 global fdneg
9263fdneg:
9264 andi.b &0x30,%d0 # clear rnd prec
9265 ori.b &d_mode*0x10,%d0 # insert dbl prec
9266
9267 global fneg
9268fneg:
9269 mov.l %d0,L_SCR3(%a6) # store rnd info
9270 mov.b STAG(%a6),%d1
9271 bne.w fneg_not_norm # optimize on non-norm input
9272
9273#
9274# NEGATE SIGN : norms and denorms ONLY!
9275#
9276fneg_norm:
9277 andi.b &0xc0,%d0 # is precision extended?
9278 bne.w fneg_not_ext # no; go handle sgl or dbl
9279
9280#
9281# precision selected is extended. so...we can not get an underflow
9282# or overflow because of rounding to the correct precision. so...
9283# skip the scaling and unscaling...
9284#
9285 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
9286 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
9287 mov.w SRC_EX(%a0),%d0
9288 eori.w &0x8000,%d0 # negate sign
9289 bpl.b fneg_norm_load # sign is positive
9290 mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
9291fneg_norm_load:
9292 mov.w %d0,FP_SCR0_EX(%a6)
9293 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
9294 rts
9295
9296#
9297# for an extended precision DENORM, the UNFL exception bit is set
9298# the accrued bit is NOT set in this instance(no inexactness!)
9299#
9300fneg_denorm:
9301 andi.b &0xc0,%d0 # is precision extended?
9302 bne.b fneg_not_ext # no; go handle sgl or dbl
9303
9304 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
9305
9306 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
9307 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
9308 mov.w SRC_EX(%a0),%d0
9309 eori.w &0x8000,%d0 # negate sign
9310 bpl.b fneg_denorm_done # no
9311 mov.b &neg_bmask,FPSR_CC(%a6) # yes, set 'N' ccode bit
9312fneg_denorm_done:
9313 mov.w %d0,FP_SCR0_EX(%a6)
9314 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
9315
9316 btst &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled?
9317 bne.b fneg_ext_unfl_ena # yes
9318 rts
9319
9320#
9321# the input is an extended DENORM and underflow is enabled in the FPCR.
9322# normalize the mantissa and add the bias of 0x6000 to the resulting negative
9323# exponent and insert back into the operand.
9324#
9325fneg_ext_unfl_ena:
9326 lea FP_SCR0(%a6),%a0 # pass: ptr to operand
9327 bsr.l norm # normalize result
9328 neg.w %d0 # new exponent = -(shft val)
9329 addi.w &0x6000,%d0 # add new bias to exponent
9330 mov.w FP_SCR0_EX(%a6),%d1 # fetch old sign,exp
9331 andi.w &0x8000,%d1 # keep old sign
9332 andi.w &0x7fff,%d0 # clear sign position
9333 or.w %d1,%d0 # concat old sign, new exponent
9334 mov.w %d0,FP_SCR0_EX(%a6) # insert new exponent
9335 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
9336 rts
9337
9338#
9339# operand is either single or double
9340#
9341fneg_not_ext:
9342 cmpi.b %d0,&s_mode*0x10 # separate sgl/dbl prec
9343 bne.b fneg_dbl
9344
9345#
9346# operand is to be rounded to single precision
9347#
9348fneg_sgl:
9349 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
9350 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
9351 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
9352 bsr.l scale_to_zero_src # calculate scale factor
9353
9354 cmpi.l %d0,&0x3fff-0x3f80 # will move in underflow?
9355 bge.w fneg_sd_unfl # yes; go handle underflow
9356 cmpi.l %d0,&0x3fff-0x407e # will move in overflow?
9357 beq.w fneg_sd_may_ovfl # maybe; go check
9358 blt.w fneg_sd_ovfl # yes; go handle overflow
9359
9360#
9361# operand will NOT overflow or underflow when moved in to the fp reg file
9362#
9363fneg_sd_normal:
9364 fmov.l &0x0,%fpsr # clear FPSR
9365 fmov.l L_SCR3(%a6),%fpcr # set FPCR
9366
9367 fneg.x FP_SCR0(%a6),%fp0 # perform negation
9368
9369 fmov.l %fpsr,%d1 # save FPSR
9370 fmov.l &0x0,%fpcr # clear FPCR
9371
9372 or.l %d1,USER_FPSR(%a6) # save INEX2,N
9373
9374fneg_sd_normal_exit:
9375 mov.l %d2,-(%sp) # save d2
9376 fmovm.x &0x80,FP_SCR0(%a6) # store out result
9377 mov.w FP_SCR0_EX(%a6),%d1 # load sgn,exp
9378 mov.w %d1,%d2 # make a copy
9379 andi.l &0x7fff,%d1 # strip sign
9380 sub.l %d0,%d1 # add scale factor
9381 andi.w &0x8000,%d2 # keep old sign
9382 or.w %d1,%d2 # concat old sign,new exp
9383 mov.w %d2,FP_SCR0_EX(%a6) # insert new exponent
9384 mov.l (%sp)+,%d2 # restore d2
9385 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
9386 rts
9387
9388#
9389# operand is to be rounded to double precision
9390#
9391fneg_dbl:
9392 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
9393 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
9394 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
9395 bsr.l scale_to_zero_src # calculate scale factor
9396
9397 cmpi.l %d0,&0x3fff-0x3c00 # will move in underflow?
9398 bge.b fneg_sd_unfl # yes; go handle underflow
9399 cmpi.l %d0,&0x3fff-0x43fe # will move in overflow?
9400 beq.w fneg_sd_may_ovfl # maybe; go check
9401 blt.w fneg_sd_ovfl # yes; go handle overflow
9402 bra.w fneg_sd_normal # no; ho handle normalized op
9403
9404#
9405# operand WILL underflow when moved in to the fp register file
9406#
9407fneg_sd_unfl:
9408 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
9409
9410 eori.b &0x80,FP_SCR0_EX(%a6) # negate sign
9411 bpl.b fneg_sd_unfl_tst
9412 bset &neg_bit,FPSR_CC(%a6) # set 'N' ccode bit
9413
9414# if underflow or inexact is enabled, go calculate EXOP first.
9415fneg_sd_unfl_tst:
9416 mov.b FPCR_ENABLE(%a6),%d1
9417 andi.b &0x0b,%d1 # is UNFL or INEX enabled?
9418 bne.b fneg_sd_unfl_ena # yes
9419
9420fneg_sd_unfl_dis:
9421 lea FP_SCR0(%a6),%a0 # pass: result addr
9422 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
9423 bsr.l unf_res # calculate default result
9424 or.b %d0,FPSR_CC(%a6) # unf_res may have set 'Z'
9425 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
9426 rts
9427
9428#
9429# operand will underflow AND underflow is enabled.
9430# therefore, we must return the result rounded to extended precision.
9431#
9432fneg_sd_unfl_ena:
9433 mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
9434 mov.l FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
9435 mov.w FP_SCR0_EX(%a6),%d1 # load current exponent
9436
9437 mov.l %d2,-(%sp) # save d2
9438 mov.l %d1,%d2 # make a copy
9439 andi.l &0x7fff,%d1 # strip sign
9440 andi.w &0x8000,%d2 # keep old sign
9441 sub.l %d0,%d1 # subtract scale factor
9442 addi.l &0x6000,%d1 # add new bias
9443 andi.w &0x7fff,%d1
9444 or.w %d2,%d1 # concat new sign,new exp
9445 mov.w %d1,FP_SCR1_EX(%a6) # insert new exp
9446 fmovm.x FP_SCR1(%a6),&0x40 # return EXOP in fp1
9447 mov.l (%sp)+,%d2 # restore d2
9448 bra.b fneg_sd_unfl_dis
9449
9450#
9451# operand WILL overflow.
9452#
9453fneg_sd_ovfl:
9454 fmov.l &0x0,%fpsr # clear FPSR
9455 fmov.l L_SCR3(%a6),%fpcr # set FPCR
9456
9457 fneg.x FP_SCR0(%a6),%fp0 # perform negation
9458
9459 fmov.l &0x0,%fpcr # clear FPCR
9460 fmov.l %fpsr,%d1 # save FPSR
9461
9462 or.l %d1,USER_FPSR(%a6) # save INEX2,N
9463
9464fneg_sd_ovfl_tst:
9465 or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
9466
9467 mov.b FPCR_ENABLE(%a6),%d1
9468 andi.b &0x13,%d1 # is OVFL or INEX enabled?
9469 bne.b fneg_sd_ovfl_ena # yes
9470
9471#
9472# OVFL is not enabled; therefore, we must create the default result by
9473# calling ovf_res().
9474#
9475fneg_sd_ovfl_dis:
9476 btst &neg_bit,FPSR_CC(%a6) # is result negative?
9477 sne %d1 # set sign param accordingly
9478 mov.l L_SCR3(%a6),%d0 # pass: prec,mode
9479 bsr.l ovf_res # calculate default result
9480 or.b %d0,FPSR_CC(%a6) # set INF,N if applicable
9481 fmovm.x (%a0),&0x80 # return default result in fp0
9482 rts
9483
9484#
9485# OVFL is enabled.
9486# the INEX2 bit has already been updated by the round to the correct precision.
9487# now, round to extended(and don't alter the FPSR).
9488#
9489fneg_sd_ovfl_ena:
9490 mov.l %d2,-(%sp) # save d2
9491 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
9492 mov.l %d1,%d2 # make a copy
9493 andi.l &0x7fff,%d1 # strip sign
9494 andi.w &0x8000,%d2 # keep old sign
9495 sub.l %d0,%d1 # add scale factor
9496 subi.l &0x6000,%d1 # subtract bias
9497 andi.w &0x7fff,%d1
9498 or.w %d2,%d1 # concat sign,exp
9499 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
9500 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
9501 mov.l (%sp)+,%d2 # restore d2
9502 bra.b fneg_sd_ovfl_dis
9503
9504#
9505# the move in MAY underflow. so...
9506#
9507fneg_sd_may_ovfl:
9508 fmov.l &0x0,%fpsr # clear FPSR
9509 fmov.l L_SCR3(%a6),%fpcr # set FPCR
9510
9511 fneg.x FP_SCR0(%a6),%fp0 # perform negation
9512
9513 fmov.l %fpsr,%d1 # save status
9514 fmov.l &0x0,%fpcr # clear FPCR
9515
9516 or.l %d1,USER_FPSR(%a6) # save INEX2,N
9517
9518 fabs.x %fp0,%fp1 # make a copy of result
9519 fcmp.b %fp1,&0x2 # is |result| >= 2.b?
9520 fbge.w fneg_sd_ovfl_tst # yes; overflow has occurred
9521
9522# no, it didn't overflow; we have correct result
9523 bra.w fneg_sd_normal_exit
9524
9525##########################################################################
9526
9527#
9528# input is not normalized; what is it?
9529#
9530fneg_not_norm:
9531 cmpi.b %d1,&DENORM # weed out DENORM
9532 beq.w fneg_denorm
9533 cmpi.b %d1,&SNAN # weed out SNAN
9534 beq.l res_snan_1op
9535 cmpi.b %d1,&QNAN # weed out QNAN
9536 beq.l res_qnan_1op
9537
9538#
9539# do the fneg; at this point, only possible ops are ZERO and INF.
9540# use fneg to determine ccodes.
9541# prec:mode should be zero at this point but it won't affect answer anyways.
9542#
9543 fneg.x SRC_EX(%a0),%fp0 # do fneg
9544 fmov.l %fpsr,%d0
9545 rol.l &0x8,%d0 # put ccodes in lo byte
9546 mov.b %d0,FPSR_CC(%a6) # insert correct ccodes
9547 rts
9548
9549#########################################################################
9550# XDEF **************************************************************** #
9551# ftst(): emulates the ftest instruction #
9552# #
9553# XREF **************************************************************** #
9554# res{s,q}nan_1op() - set NAN result for monadic instruction #
9555# #
9556# INPUT *************************************************************** #
9557# a0 = pointer to extended precision source operand #
9558# #
9559# OUTPUT ************************************************************** #
9560# none #
9561# #
9562# ALGORITHM *********************************************************** #
9563# Check the source operand tag (STAG) and set the FPCR according #
9564# to the operand type and sign. #
9565# #
9566#########################################################################
9567
9568 global ftst
9569ftst:
9570 mov.b STAG(%a6),%d1
9571 bne.b ftst_not_norm # optimize on non-norm input
9572
9573#
9574# Norm:
9575#
9576ftst_norm:
9577 tst.b SRC_EX(%a0) # is operand negative?
9578 bmi.b ftst_norm_m # yes
9579 rts
9580ftst_norm_m:
9581 mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
9582 rts
9583
9584#
9585# input is not normalized; what is it?
9586#
9587ftst_not_norm:
9588 cmpi.b %d1,&ZERO # weed out ZERO
9589 beq.b ftst_zero
9590 cmpi.b %d1,&INF # weed out INF
9591 beq.b ftst_inf
9592 cmpi.b %d1,&SNAN # weed out SNAN
9593 beq.l res_snan_1op
9594 cmpi.b %d1,&QNAN # weed out QNAN
9595 beq.l res_qnan_1op
9596
9597#
9598# Denorm:
9599#
9600ftst_denorm:
9601 tst.b SRC_EX(%a0) # is operand negative?
9602 bmi.b ftst_denorm_m # yes
9603 rts
9604ftst_denorm_m:
9605 mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit
9606 rts
9607
9608#
9609# Infinity:
9610#
9611ftst_inf:
9612 tst.b SRC_EX(%a0) # is operand negative?
9613 bmi.b ftst_inf_m # yes
9614ftst_inf_p:
9615 mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
9616 rts
9617ftst_inf_m:
9618 mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'I','N' ccode bits
9619 rts
9620
9621#
9622# Zero:
9623#
9624ftst_zero:
9625 tst.b SRC_EX(%a0) # is operand negative?
9626 bmi.b ftst_zero_m # yes
9627ftst_zero_p:
9628 mov.b &z_bmask,FPSR_CC(%a6) # set 'N' ccode bit
9629 rts
9630ftst_zero_m:
9631 mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
9632 rts
9633
9634#########################################################################
9635# XDEF **************************************************************** #
9636# fint(): emulates the fint instruction #
9637# #
9638# XREF **************************************************************** #
9639# res_{s,q}nan_1op() - set NAN result for monadic operation #
9640# #
9641# INPUT *************************************************************** #
9642# a0 = pointer to extended precision source operand #
9643# d0 = round precision/mode #
9644# #
9645# OUTPUT ************************************************************** #
9646# fp0 = result #
9647# #
9648# ALGORITHM *********************************************************** #
9649# Separate according to operand type. Unnorms don't pass through #
9650# here. For norms, load the rounding mode/prec, execute a "fint", then #
9651# store the resulting FPSR bits. #
9652# For denorms, force the j-bit to a one and do the same as for #
9653# norms. Denorms are so low that the answer will either be a zero or a #
9654# one. #
9655# For zeroes/infs/NANs, return the same while setting the FPSR #
9656# as appropriate. #
9657# #
9658#########################################################################
9659
9660 global fint
9661fint:
9662 mov.b STAG(%a6),%d1
9663 bne.b fint_not_norm # optimize on non-norm input
9664
9665#
9666# Norm:
9667#
9668fint_norm:
9669 andi.b &0x30,%d0 # set prec = ext
9670
9671 fmov.l %d0,%fpcr # set FPCR
9672 fmov.l &0x0,%fpsr # clear FPSR
9673
9674 fint.x SRC(%a0),%fp0 # execute fint
9675
9676 fmov.l &0x0,%fpcr # clear FPCR
9677 fmov.l %fpsr,%d0 # save FPSR
9678 or.l %d0,USER_FPSR(%a6) # set exception bits
9679
9680 rts
9681
9682#
9683# input is not normalized; what is it?
9684#
9685fint_not_norm:
9686 cmpi.b %d1,&ZERO # weed out ZERO
9687 beq.b fint_zero
9688 cmpi.b %d1,&INF # weed out INF
9689 beq.b fint_inf
9690 cmpi.b %d1,&DENORM # weed out DENORM
9691 beq.b fint_denorm
9692 cmpi.b %d1,&SNAN # weed out SNAN
9693 beq.l res_snan_1op
9694 bra.l res_qnan_1op # weed out QNAN
9695
9696#
9697# Denorm:
9698#
9699# for DENORMs, the result will be either (+/-)ZERO or (+/-)1.
9700# also, the INEX2 and AINEX exception bits will be set.
9701# so, we could either set these manually or force the DENORM
9702# to a very small NORM and ship it to the NORM routine.
9703# I do the latter.
9704#
9705fint_denorm:
9706 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) # copy sign, zero exp
9707 mov.b &0x80,FP_SCR0_HI(%a6) # force DENORM ==> small NORM
9708 lea FP_SCR0(%a6),%a0
9709 bra.b fint_norm
9710
9711#
9712# Zero:
9713#
9714fint_zero:
9715 tst.b SRC_EX(%a0) # is ZERO negative?
9716 bmi.b fint_zero_m # yes
9717fint_zero_p:
9718 fmov.s &0x00000000,%fp0 # return +ZERO in fp0
9719 mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit
9720 rts
9721fint_zero_m:
9722 fmov.s &0x80000000,%fp0 # return -ZERO in fp0
9723 mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
9724 rts
9725
9726#
9727# Infinity:
9728#
9729fint_inf:
9730 fmovm.x SRC(%a0),&0x80 # return result in fp0
9731 tst.b SRC_EX(%a0) # is INF negative?
9732 bmi.b fint_inf_m # yes
9733fint_inf_p:
9734 mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
9735 rts
9736fint_inf_m:
9737 mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits
9738 rts
9739
9740#########################################################################
9741# XDEF **************************************************************** #
9742# fintrz(): emulates the fintrz instruction #
9743# #
9744# XREF **************************************************************** #
9745# res_{s,q}nan_1op() - set NAN result for monadic operation #
9746# #
9747# INPUT *************************************************************** #
9748# a0 = pointer to extended precision source operand #
9749# d0 = round precision/mode #
9750# #
9751# OUTPUT ************************************************************** #
9752# fp0 = result #
9753# #
9754# ALGORITHM *********************************************************** #
9755# Separate according to operand type. Unnorms don't pass through #
9756# here. For norms, load the rounding mode/prec, execute a "fintrz", #
9757# then store the resulting FPSR bits. #
9758# For denorms, force the j-bit to a one and do the same as for #
9759# norms. Denorms are so low that the answer will either be a zero or a #
9760# one. #
9761# For zeroes/infs/NANs, return the same while setting the FPSR #
9762# as appropriate. #
9763# #
9764#########################################################################
9765
9766 global fintrz
9767fintrz:
9768 mov.b STAG(%a6),%d1
9769 bne.b fintrz_not_norm # optimize on non-norm input
9770
9771#
9772# Norm:
9773#
9774fintrz_norm:
9775 fmov.l &0x0,%fpsr # clear FPSR
9776
9777 fintrz.x SRC(%a0),%fp0 # execute fintrz
9778
9779 fmov.l %fpsr,%d0 # save FPSR
9780 or.l %d0,USER_FPSR(%a6) # set exception bits
9781
9782 rts
9783
9784#
9785# input is not normalized; what is it?
9786#
9787fintrz_not_norm:
9788 cmpi.b %d1,&ZERO # weed out ZERO
9789 beq.b fintrz_zero
9790 cmpi.b %d1,&INF # weed out INF
9791 beq.b fintrz_inf
9792 cmpi.b %d1,&DENORM # weed out DENORM
9793 beq.b fintrz_denorm
9794 cmpi.b %d1,&SNAN # weed out SNAN
9795 beq.l res_snan_1op
9796 bra.l res_qnan_1op # weed out QNAN
9797
9798#
9799# Denorm:
9800#
9801# for DENORMs, the result will be (+/-)ZERO.
9802# also, the INEX2 and AINEX exception bits will be set.
9803# so, we could either set these manually or force the DENORM
9804# to a very small NORM and ship it to the NORM routine.
9805# I do the latter.
9806#
9807fintrz_denorm:
9808 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) # copy sign, zero exp
9809 mov.b &0x80,FP_SCR0_HI(%a6) # force DENORM ==> small NORM
9810 lea FP_SCR0(%a6),%a0
9811 bra.b fintrz_norm
9812
9813#
9814# Zero:
9815#
9816fintrz_zero:
9817 tst.b SRC_EX(%a0) # is ZERO negative?
9818 bmi.b fintrz_zero_m # yes
9819fintrz_zero_p:
9820 fmov.s &0x00000000,%fp0 # return +ZERO in fp0
9821 mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit
9822 rts
9823fintrz_zero_m:
9824 fmov.s &0x80000000,%fp0 # return -ZERO in fp0
9825 mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
9826 rts
9827
9828#
9829# Infinity:
9830#
9831fintrz_inf:
9832 fmovm.x SRC(%a0),&0x80 # return result in fp0
9833 tst.b SRC_EX(%a0) # is INF negative?
9834 bmi.b fintrz_inf_m # yes
9835fintrz_inf_p:
9836 mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
9837 rts
9838fintrz_inf_m:
9839 mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits
9840 rts
9841
9842#########################################################################
9843# XDEF **************************************************************** #
9844# fabs(): emulates the fabs instruction #
9845# fsabs(): emulates the fsabs instruction #
9846# fdabs(): emulates the fdabs instruction #
9847# #
9848# XREF **************************************************************** #
9849# norm() - normalize denorm mantissa to provide EXOP #
9850# scale_to_zero_src() - make exponent. = 0; get scale factor #
9851# unf_res() - calculate underflow result #
9852# ovf_res() - calculate overflow result #
9853# res_{s,q}nan_1op() - set NAN result for monadic operation #
9854# #
9855# INPUT *************************************************************** #
9856# a0 = pointer to extended precision source operand #
9857# d0 = rnd precision/mode #
9858# #
9859# OUTPUT ************************************************************** #
9860# fp0 = result #
9861# fp1 = EXOP (if exception occurred) #
9862# #
9863# ALGORITHM *********************************************************** #
9864# Handle NANs, infinities, and zeroes as special cases. Divide #
9865# norms into extended, single, and double precision. #
9866# Simply clear sign for extended precision norm. Ext prec denorm #
9867# gets an EXOP created for it since it's an underflow. #
9868# Double and single precision can overflow and underflow. First, #
9869# scale the operand such that the exponent is zero. Perform an "fabs" #
9870# using the correct rnd mode/prec. Check to see if the original #
9871# exponent would take an exception. If so, use unf_res() or ovf_res() #
9872# to calculate the default result. Also, create the EXOP for the #
9873# exceptional case. If no exception should occur, insert the correct #
9874# result exponent and return. #
9875# Unnorms don't pass through here. #
9876# #
9877#########################################################################
9878
9879 global fsabs
9880fsabs:
9881 andi.b &0x30,%d0 # clear rnd prec
9882 ori.b &s_mode*0x10,%d0 # insert sgl precision
9883 bra.b fabs
9884
9885 global fdabs
9886fdabs:
9887 andi.b &0x30,%d0 # clear rnd prec
9888 ori.b &d_mode*0x10,%d0 # insert dbl precision
9889
9890 global fabs
9891fabs:
9892 mov.l %d0,L_SCR3(%a6) # store rnd info
9893 mov.b STAG(%a6),%d1
9894 bne.w fabs_not_norm # optimize on non-norm input
9895
9896#
9897# ABSOLUTE VALUE: norms and denorms ONLY!
9898#
9899fabs_norm:
9900 andi.b &0xc0,%d0 # is precision extended?
9901 bne.b fabs_not_ext # no; go handle sgl or dbl
9902
9903#
9904# precision selected is extended. so...we can not get an underflow
9905# or overflow because of rounding to the correct precision. so...
9906# skip the scaling and unscaling...
9907#
9908 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
9909 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
9910 mov.w SRC_EX(%a0),%d1
9911 bclr &15,%d1 # force absolute value
9912 mov.w %d1,FP_SCR0_EX(%a6) # insert exponent
9913 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
9914 rts
9915
9916#
9917# for an extended precision DENORM, the UNFL exception bit is set
9918# the accrued bit is NOT set in this instance(no inexactness!)
9919#
9920fabs_denorm:
9921 andi.b &0xc0,%d0 # is precision extended?
9922 bne.b fabs_not_ext # no
9923
9924 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
9925
9926 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
9927 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
9928 mov.w SRC_EX(%a0),%d0
9929 bclr &15,%d0 # clear sign
9930 mov.w %d0,FP_SCR0_EX(%a6) # insert exponent
9931
9932 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
9933
9934 btst &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled?
9935 bne.b fabs_ext_unfl_ena
9936 rts
9937
9938#
9939# the input is an extended DENORM and underflow is enabled in the FPCR.
9940# normalize the mantissa and add the bias of 0x6000 to the resulting negative
9941# exponent and insert back into the operand.
9942#
9943fabs_ext_unfl_ena:
9944 lea FP_SCR0(%a6),%a0 # pass: ptr to operand
9945 bsr.l norm # normalize result
9946 neg.w %d0 # new exponent = -(shft val)
9947 addi.w &0x6000,%d0 # add new bias to exponent
9948 mov.w FP_SCR0_EX(%a6),%d1 # fetch old sign,exp
9949 andi.w &0x8000,%d1 # keep old sign
9950 andi.w &0x7fff,%d0 # clear sign position
9951 or.w %d1,%d0 # concat old sign, new exponent
9952 mov.w %d0,FP_SCR0_EX(%a6) # insert new exponent
9953 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
9954 rts
9955
9956#
9957# operand is either single or double
9958#
9959fabs_not_ext:
9960 cmpi.b %d0,&s_mode*0x10 # separate sgl/dbl prec
9961 bne.b fabs_dbl
9962
9963#
9964# operand is to be rounded to single precision
9965#
9966fabs_sgl:
9967 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
9968 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
9969 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
9970 bsr.l scale_to_zero_src # calculate scale factor
9971
9972 cmpi.l %d0,&0x3fff-0x3f80 # will move in underflow?
9973 bge.w fabs_sd_unfl # yes; go handle underflow
9974 cmpi.l %d0,&0x3fff-0x407e # will move in overflow?
9975 beq.w fabs_sd_may_ovfl # maybe; go check
9976 blt.w fabs_sd_ovfl # yes; go handle overflow
9977
9978#
9979# operand will NOT overflow or underflow when moved in to the fp reg file
9980#
9981fabs_sd_normal:
9982 fmov.l &0x0,%fpsr # clear FPSR
9983 fmov.l L_SCR3(%a6),%fpcr # set FPCR
9984
9985 fabs.x FP_SCR0(%a6),%fp0 # perform absolute
9986
9987 fmov.l %fpsr,%d1 # save FPSR
9988 fmov.l &0x0,%fpcr # clear FPCR
9989
9990 or.l %d1,USER_FPSR(%a6) # save INEX2,N
9991
9992fabs_sd_normal_exit:
9993 mov.l %d2,-(%sp) # save d2
9994 fmovm.x &0x80,FP_SCR0(%a6) # store out result
9995 mov.w FP_SCR0_EX(%a6),%d1 # load sgn,exp
9996 mov.l %d1,%d2 # make a copy
9997 andi.l &0x7fff,%d1 # strip sign
9998 sub.l %d0,%d1 # add scale factor
9999 andi.w &0x8000,%d2 # keep old sign
10000 or.w %d1,%d2 # concat old sign,new exp
10001 mov.w %d2,FP_SCR0_EX(%a6) # insert new exponent
10002 mov.l (%sp)+,%d2 # restore d2
10003 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
10004 rts
10005
10006#
10007# operand is to be rounded to double precision
10008#
10009fabs_dbl:
10010 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
10011 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
10012 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
10013 bsr.l scale_to_zero_src # calculate scale factor
10014
10015 cmpi.l %d0,&0x3fff-0x3c00 # will move in underflow?
10016 bge.b fabs_sd_unfl # yes; go handle underflow
10017 cmpi.l %d0,&0x3fff-0x43fe # will move in overflow?
10018 beq.w fabs_sd_may_ovfl # maybe; go check
10019 blt.w fabs_sd_ovfl # yes; go handle overflow
10020 bra.w fabs_sd_normal # no; ho handle normalized op
10021
10022#
10023# operand WILL underflow when moved in to the fp register file
10024#
10025fabs_sd_unfl:
10026 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
10027
10028 bclr &0x7,FP_SCR0_EX(%a6) # force absolute value
10029
10030# if underflow or inexact is enabled, go calculate EXOP first.
10031 mov.b FPCR_ENABLE(%a6),%d1
10032 andi.b &0x0b,%d1 # is UNFL or INEX enabled?
10033 bne.b fabs_sd_unfl_ena # yes
10034
10035fabs_sd_unfl_dis:
10036 lea FP_SCR0(%a6),%a0 # pass: result addr
10037 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
10038 bsr.l unf_res # calculate default result
10039 or.b %d0,FPSR_CC(%a6) # set possible 'Z' ccode
10040 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
10041 rts
10042
10043#
10044# operand will underflow AND underflow is enabled.
10045# therefore, we must return the result rounded to extended precision.
10046#
10047fabs_sd_unfl_ena:
10048 mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
10049 mov.l FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
10050 mov.w FP_SCR0_EX(%a6),%d1 # load current exponent
10051
10052 mov.l %d2,-(%sp) # save d2
10053 mov.l %d1,%d2 # make a copy
10054 andi.l &0x7fff,%d1 # strip sign
10055 andi.w &0x8000,%d2 # keep old sign
10056 sub.l %d0,%d1 # subtract scale factor
10057 addi.l &0x6000,%d1 # add new bias
10058 andi.w &0x7fff,%d1
10059 or.w %d2,%d1 # concat new sign,new exp
10060 mov.w %d1,FP_SCR1_EX(%a6) # insert new exp
10061 fmovm.x FP_SCR1(%a6),&0x40 # return EXOP in fp1
10062 mov.l (%sp)+,%d2 # restore d2
10063 bra.b fabs_sd_unfl_dis
10064
10065#
10066# operand WILL overflow.
10067#
10068fabs_sd_ovfl:
10069 fmov.l &0x0,%fpsr # clear FPSR
10070 fmov.l L_SCR3(%a6),%fpcr # set FPCR
10071
10072 fabs.x FP_SCR0(%a6),%fp0 # perform absolute
10073
10074 fmov.l &0x0,%fpcr # clear FPCR
10075 fmov.l %fpsr,%d1 # save FPSR
10076
10077 or.l %d1,USER_FPSR(%a6) # save INEX2,N
10078
10079fabs_sd_ovfl_tst:
10080 or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
10081
10082 mov.b FPCR_ENABLE(%a6),%d1
10083 andi.b &0x13,%d1 # is OVFL or INEX enabled?
10084 bne.b fabs_sd_ovfl_ena # yes
10085
10086#
10087# OVFL is not enabled; therefore, we must create the default result by
10088# calling ovf_res().
10089#
10090fabs_sd_ovfl_dis:
10091 btst &neg_bit,FPSR_CC(%a6) # is result negative?
10092 sne %d1 # set sign param accordingly
10093 mov.l L_SCR3(%a6),%d0 # pass: prec,mode
10094 bsr.l ovf_res # calculate default result
10095 or.b %d0,FPSR_CC(%a6) # set INF,N if applicable
10096 fmovm.x (%a0),&0x80 # return default result in fp0
10097 rts
10098
10099#
10100# OVFL is enabled.
10101# the INEX2 bit has already been updated by the round to the correct precision.
10102# now, round to extended(and don't alter the FPSR).
10103#
10104fabs_sd_ovfl_ena:
10105 mov.l %d2,-(%sp) # save d2
10106 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
10107 mov.l %d1,%d2 # make a copy
10108 andi.l &0x7fff,%d1 # strip sign
10109 andi.w &0x8000,%d2 # keep old sign
10110 sub.l %d0,%d1 # add scale factor
10111 subi.l &0x6000,%d1 # subtract bias
10112 andi.w &0x7fff,%d1
10113 or.w %d2,%d1 # concat sign,exp
10114 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
10115 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
10116 mov.l (%sp)+,%d2 # restore d2
10117 bra.b fabs_sd_ovfl_dis
10118
10119#
10120# the move in MAY underflow. so...
10121#
10122fabs_sd_may_ovfl:
10123 fmov.l &0x0,%fpsr # clear FPSR
10124 fmov.l L_SCR3(%a6),%fpcr # set FPCR
10125
10126 fabs.x FP_SCR0(%a6),%fp0 # perform absolute
10127
10128 fmov.l %fpsr,%d1 # save status
10129 fmov.l &0x0,%fpcr # clear FPCR
10130
10131 or.l %d1,USER_FPSR(%a6) # save INEX2,N
10132
10133 fabs.x %fp0,%fp1 # make a copy of result
10134 fcmp.b %fp1,&0x2 # is |result| >= 2.b?
10135 fbge.w fabs_sd_ovfl_tst # yes; overflow has occurred
10136
10137# no, it didn't overflow; we have correct result
10138 bra.w fabs_sd_normal_exit
10139
10140##########################################################################
10141
10142#
10143# input is not normalized; what is it?
10144#
10145fabs_not_norm:
10146 cmpi.b %d1,&DENORM # weed out DENORM
10147 beq.w fabs_denorm
10148 cmpi.b %d1,&SNAN # weed out SNAN
10149 beq.l res_snan_1op
10150 cmpi.b %d1,&QNAN # weed out QNAN
10151 beq.l res_qnan_1op
10152
10153 fabs.x SRC(%a0),%fp0 # force absolute value
10154
10155 cmpi.b %d1,&INF # weed out INF
10156 beq.b fabs_inf
10157fabs_zero:
10158 mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit
10159 rts
10160fabs_inf:
10161 mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
10162 rts
10163
10164#########################################################################
10165# XDEF **************************************************************** #
10166# fcmp(): fp compare op routine #
10167# #
10168# XREF **************************************************************** #
10169# res_qnan() - return QNAN result #
10170# res_snan() - return SNAN result #
10171# #
10172# INPUT *************************************************************** #
10173# a0 = pointer to extended precision source operand #
10174# a1 = pointer to extended precision destination operand #
10175# d0 = round prec/mode #
10176# #
10177# OUTPUT ************************************************************** #
10178# None #
10179# #
10180# ALGORITHM *********************************************************** #
10181# Handle NANs and denorms as special cases. For everything else, #
10182# just use the actual fcmp instruction to produce the correct condition #
10183# codes. #
10184# #
10185#########################################################################
10186
10187 global fcmp
10188fcmp:
10189 clr.w %d1
10190 mov.b DTAG(%a6),%d1
10191 lsl.b &0x3,%d1
10192 or.b STAG(%a6),%d1
10193 bne.b fcmp_not_norm # optimize on non-norm input
10194
10195#
10196# COMPARE FP OPs : NORMs, ZEROs, INFs, and "corrected" DENORMs
10197#
10198fcmp_norm:
10199 fmovm.x DST(%a1),&0x80 # load dst op
10200
10201 fcmp.x %fp0,SRC(%a0) # do compare
10202
10203 fmov.l %fpsr,%d0 # save FPSR
10204 rol.l &0x8,%d0 # extract ccode bits
10205 mov.b %d0,FPSR_CC(%a6) # set ccode bits(no exc bits are set)
10206
10207 rts
10208
10209#
10210# fcmp: inputs are not both normalized; what are they?
10211#
10212fcmp_not_norm:
10213 mov.w (tbl_fcmp_op.b,%pc,%d1.w*2),%d1
10214 jmp (tbl_fcmp_op.b,%pc,%d1.w*1)
10215
10216 swbeg &48
10217tbl_fcmp_op:
10218 short fcmp_norm - tbl_fcmp_op # NORM - NORM
10219 short fcmp_norm - tbl_fcmp_op # NORM - ZERO
10220 short fcmp_norm - tbl_fcmp_op # NORM - INF
10221 short fcmp_res_qnan - tbl_fcmp_op # NORM - QNAN
10222 short fcmp_nrm_dnrm - tbl_fcmp_op # NORM - DENORM
10223 short fcmp_res_snan - tbl_fcmp_op # NORM - SNAN
10224 short tbl_fcmp_op - tbl_fcmp_op #
10225 short tbl_fcmp_op - tbl_fcmp_op #
10226
10227 short fcmp_norm - tbl_fcmp_op # ZERO - NORM
10228 short fcmp_norm - tbl_fcmp_op # ZERO - ZERO
10229 short fcmp_norm - tbl_fcmp_op # ZERO - INF
10230 short fcmp_res_qnan - tbl_fcmp_op # ZERO - QNAN
10231 short fcmp_dnrm_s - tbl_fcmp_op # ZERO - DENORM
10232 short fcmp_res_snan - tbl_fcmp_op # ZERO - SNAN
10233 short tbl_fcmp_op - tbl_fcmp_op #
10234 short tbl_fcmp_op - tbl_fcmp_op #
10235
10236 short fcmp_norm - tbl_fcmp_op # INF - NORM
10237 short fcmp_norm - tbl_fcmp_op # INF - ZERO
10238 short fcmp_norm - tbl_fcmp_op # INF - INF
10239 short fcmp_res_qnan - tbl_fcmp_op # INF - QNAN
10240 short fcmp_dnrm_s - tbl_fcmp_op # INF - DENORM
10241 short fcmp_res_snan - tbl_fcmp_op # INF - SNAN
10242 short tbl_fcmp_op - tbl_fcmp_op #
10243 short tbl_fcmp_op - tbl_fcmp_op #
10244
10245 short fcmp_res_qnan - tbl_fcmp_op # QNAN - NORM
10246 short fcmp_res_qnan - tbl_fcmp_op # QNAN - ZERO
10247 short fcmp_res_qnan - tbl_fcmp_op # QNAN - INF
10248 short fcmp_res_qnan - tbl_fcmp_op # QNAN - QNAN
10249 short fcmp_res_qnan - tbl_fcmp_op # QNAN - DENORM
10250 short fcmp_res_snan - tbl_fcmp_op # QNAN - SNAN
10251 short tbl_fcmp_op - tbl_fcmp_op #
10252 short tbl_fcmp_op - tbl_fcmp_op #
10253
10254 short fcmp_dnrm_nrm - tbl_fcmp_op # DENORM - NORM
10255 short fcmp_dnrm_d - tbl_fcmp_op # DENORM - ZERO
10256 short fcmp_dnrm_d - tbl_fcmp_op # DENORM - INF
10257 short fcmp_res_qnan - tbl_fcmp_op # DENORM - QNAN
10258 short fcmp_dnrm_sd - tbl_fcmp_op # DENORM - DENORM
10259 short fcmp_res_snan - tbl_fcmp_op # DENORM - SNAN
10260 short tbl_fcmp_op - tbl_fcmp_op #
10261 short tbl_fcmp_op - tbl_fcmp_op #
10262
10263 short fcmp_res_snan - tbl_fcmp_op # SNAN - NORM
10264 short fcmp_res_snan - tbl_fcmp_op # SNAN - ZERO
10265 short fcmp_res_snan - tbl_fcmp_op # SNAN - INF
10266 short fcmp_res_snan - tbl_fcmp_op # SNAN - QNAN
10267 short fcmp_res_snan - tbl_fcmp_op # SNAN - DENORM
10268 short fcmp_res_snan - tbl_fcmp_op # SNAN - SNAN
10269 short tbl_fcmp_op - tbl_fcmp_op #
10270 short tbl_fcmp_op - tbl_fcmp_op #
10271
10272# unlike all other functions for QNAN and SNAN, fcmp does NOT set the
10273# 'N' bit for a negative QNAN or SNAN input so we must squelch it here.
10274fcmp_res_qnan:
10275 bsr.l res_qnan
10276 andi.b &0xf7,FPSR_CC(%a6)
10277 rts
10278fcmp_res_snan:
10279 bsr.l res_snan
10280 andi.b &0xf7,FPSR_CC(%a6)
10281 rts
10282
10283#
10284# DENORMs are a little more difficult.
10285# If you have a 2 DENORMs, then you can just force the j-bit to a one
10286# and use the fcmp_norm routine.
10287# If you have a DENORM and an INF or ZERO, just force the DENORM's j-bit to a one
10288# and use the fcmp_norm routine.
10289# If you have a DENORM and a NORM with opposite signs, then use fcmp_norm, also.
10290# But with a DENORM and a NORM of the same sign, the neg bit is set if the
10291# (1) signs are (+) and the DENORM is the dst or
10292# (2) signs are (-) and the DENORM is the src
10293#
10294
10295fcmp_dnrm_s:
10296 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
10297 mov.l SRC_HI(%a0),%d0
10298 bset &31,%d0 # DENORM src; make into small norm
10299 mov.l %d0,FP_SCR0_HI(%a6)
10300 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
10301 lea FP_SCR0(%a6),%a0
10302 bra.w fcmp_norm
10303
10304fcmp_dnrm_d:
10305 mov.l DST_EX(%a1),FP_SCR0_EX(%a6)
10306 mov.l DST_HI(%a1),%d0
10307 bset &31,%d0 # DENORM src; make into small norm
10308 mov.l %d0,FP_SCR0_HI(%a6)
10309 mov.l DST_LO(%a1),FP_SCR0_LO(%a6)
10310 lea FP_SCR0(%a6),%a1
10311 bra.w fcmp_norm
10312
10313fcmp_dnrm_sd:
10314 mov.w DST_EX(%a1),FP_SCR1_EX(%a6)
10315 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
10316 mov.l DST_HI(%a1),%d0
10317 bset &31,%d0 # DENORM dst; make into small norm
10318 mov.l %d0,FP_SCR1_HI(%a6)
10319 mov.l SRC_HI(%a0),%d0
10320 bset &31,%d0 # DENORM dst; make into small norm
10321 mov.l %d0,FP_SCR0_HI(%a6)
10322 mov.l DST_LO(%a1),FP_SCR1_LO(%a6)
10323 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
10324 lea FP_SCR1(%a6),%a1
10325 lea FP_SCR0(%a6),%a0
10326 bra.w fcmp_norm
10327
10328fcmp_nrm_dnrm:
10329 mov.b SRC_EX(%a0),%d0 # determine if like signs
10330 mov.b DST_EX(%a1),%d1
10331 eor.b %d0,%d1
10332 bmi.w fcmp_dnrm_s
10333
10334# signs are the same, so must determine the answer ourselves.
10335 tst.b %d0 # is src op negative?
10336 bmi.b fcmp_nrm_dnrm_m # yes
10337 rts
10338fcmp_nrm_dnrm_m:
10339 mov.b &neg_bmask,FPSR_CC(%a6) # set 'Z' ccode bit
10340 rts
10341
10342fcmp_dnrm_nrm:
10343 mov.b SRC_EX(%a0),%d0 # determine if like signs
10344 mov.b DST_EX(%a1),%d1
10345 eor.b %d0,%d1
10346 bmi.w fcmp_dnrm_d
10347
10348# signs are the same, so must determine the answer ourselves.
10349 tst.b %d0 # is src op negative?
10350 bpl.b fcmp_dnrm_nrm_m # no
10351 rts
10352fcmp_dnrm_nrm_m:
10353 mov.b &neg_bmask,FPSR_CC(%a6) # set 'Z' ccode bit
10354 rts
10355
10356#########################################################################
10357# XDEF **************************************************************** #
10358# fsglmul(): emulates the fsglmul instruction #
10359# #
10360# XREF **************************************************************** #
10361# scale_to_zero_src() - scale src exponent to zero #
10362# scale_to_zero_dst() - scale dst exponent to zero #
10363# unf_res4() - return default underflow result for sglop #
10364# ovf_res() - return default overflow result #
10365# res_qnan() - return QNAN result #
10366# res_snan() - return SNAN result #
10367# #
10368# INPUT *************************************************************** #
10369# a0 = pointer to extended precision source operand #
10370# a1 = pointer to extended precision destination operand #
10371# d0 rnd prec,mode #
10372# #
10373# OUTPUT ************************************************************** #
10374# fp0 = result #
10375# fp1 = EXOP (if exception occurred) #
10376# #
10377# ALGORITHM *********************************************************** #
10378# Handle NANs, infinities, and zeroes as special cases. Divide #
10379# norms/denorms into ext/sgl/dbl precision. #
10380# For norms/denorms, scale the exponents such that a multiply #
10381# instruction won't cause an exception. Use the regular fsglmul to #
10382# compute a result. Check if the regular operands would have taken #
10383# an exception. If so, return the default overflow/underflow result #
10384# and return the EXOP if exceptions are enabled. Else, scale the #
10385# result operand to the proper exponent. #
10386# #
10387#########################################################################
10388
10389 global fsglmul
10390fsglmul:
10391 mov.l %d0,L_SCR3(%a6) # store rnd info
10392
10393 clr.w %d1
10394 mov.b DTAG(%a6),%d1
10395 lsl.b &0x3,%d1
10396 or.b STAG(%a6),%d1
10397
10398 bne.w fsglmul_not_norm # optimize on non-norm input
10399
10400fsglmul_norm:
10401 mov.w DST_EX(%a1),FP_SCR1_EX(%a6)
10402 mov.l DST_HI(%a1),FP_SCR1_HI(%a6)
10403 mov.l DST_LO(%a1),FP_SCR1_LO(%a6)
10404
10405 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
10406 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
10407 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
10408
10409 bsr.l scale_to_zero_src # scale exponent
10410 mov.l %d0,-(%sp) # save scale factor 1
10411
10412 bsr.l scale_to_zero_dst # scale dst exponent
10413
10414 add.l (%sp)+,%d0 # SCALE_FACTOR = scale1 + scale2
10415
10416 cmpi.l %d0,&0x3fff-0x7ffe # would result ovfl?
10417 beq.w fsglmul_may_ovfl # result may rnd to overflow
10418 blt.w fsglmul_ovfl # result will overflow
10419
10420 cmpi.l %d0,&0x3fff+0x0001 # would result unfl?
10421 beq.w fsglmul_may_unfl # result may rnd to no unfl
10422 bgt.w fsglmul_unfl # result will underflow
10423
10424fsglmul_normal:
10425 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10426
10427 fmov.l L_SCR3(%a6),%fpcr # set FPCR
10428 fmov.l &0x0,%fpsr # clear FPSR
10429
10430 fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply
10431
10432 fmov.l %fpsr,%d1 # save status
10433 fmov.l &0x0,%fpcr # clear FPCR
10434
10435 or.l %d1,USER_FPSR(%a6) # save INEX2,N
10436
10437fsglmul_normal_exit:
10438 fmovm.x &0x80,FP_SCR0(%a6) # store out result
10439 mov.l %d2,-(%sp) # save d2
10440 mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp}
10441 mov.l %d1,%d2 # make a copy
10442 andi.l &0x7fff,%d1 # strip sign
10443 andi.w &0x8000,%d2 # keep old sign
10444 sub.l %d0,%d1 # add scale factor
10445 or.w %d2,%d1 # concat old sign,new exp
10446 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
10447 mov.l (%sp)+,%d2 # restore d2
10448 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
10449 rts
10450
10451fsglmul_ovfl:
10452 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10453
10454 fmov.l L_SCR3(%a6),%fpcr # set FPCR
10455 fmov.l &0x0,%fpsr # clear FPSR
10456
10457 fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply
10458
10459 fmov.l %fpsr,%d1 # save status
10460 fmov.l &0x0,%fpcr # clear FPCR
10461
10462 or.l %d1,USER_FPSR(%a6) # save INEX2,N
10463
10464fsglmul_ovfl_tst:
10465
10466# save setting this until now because this is where fsglmul_may_ovfl may jump in
10467 or.l &ovfl_inx_mask, USER_FPSR(%a6) # set ovfl/aovfl/ainex
10468
10469 mov.b FPCR_ENABLE(%a6),%d1
10470 andi.b &0x13,%d1 # is OVFL or INEX enabled?
10471 bne.b fsglmul_ovfl_ena # yes
10472
10473fsglmul_ovfl_dis:
10474 btst &neg_bit,FPSR_CC(%a6) # is result negative?
10475 sne %d1 # set sign param accordingly
10476 mov.l L_SCR3(%a6),%d0 # pass prec:rnd
10477 andi.b &0x30,%d0 # force prec = ext
10478 bsr.l ovf_res # calculate default result
10479 or.b %d0,FPSR_CC(%a6) # set INF,N if applicable
10480 fmovm.x (%a0),&0x80 # return default result in fp0
10481 rts
10482
10483fsglmul_ovfl_ena:
10484 fmovm.x &0x80,FP_SCR0(%a6) # move result to stack
10485
10486 mov.l %d2,-(%sp) # save d2
10487 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
10488 mov.l %d1,%d2 # make a copy
10489 andi.l &0x7fff,%d1 # strip sign
10490 sub.l %d0,%d1 # add scale factor
10491 subi.l &0x6000,%d1 # subtract bias
10492 andi.w &0x7fff,%d1
10493 andi.w &0x8000,%d2 # keep old sign
10494 or.w %d2,%d1 # concat old sign,new exp
10495 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
10496 mov.l (%sp)+,%d2 # restore d2
10497 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
10498 bra.b fsglmul_ovfl_dis
10499
10500fsglmul_may_ovfl:
10501 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10502
10503 fmov.l L_SCR3(%a6),%fpcr # set FPCR
10504 fmov.l &0x0,%fpsr # clear FPSR
10505
10506 fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply
10507
10508 fmov.l %fpsr,%d1 # save status
10509 fmov.l &0x0,%fpcr # clear FPCR
10510
10511 or.l %d1,USER_FPSR(%a6) # save INEX2,N
10512
10513 fabs.x %fp0,%fp1 # make a copy of result
10514 fcmp.b %fp1,&0x2 # is |result| >= 2.b?
10515 fbge.w fsglmul_ovfl_tst # yes; overflow has occurred
10516
10517# no, it didn't overflow; we have correct result
10518 bra.w fsglmul_normal_exit
10519
10520fsglmul_unfl:
10521 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
10522
10523 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10524
10525 fmov.l &rz_mode*0x10,%fpcr # set FPCR
10526 fmov.l &0x0,%fpsr # clear FPSR
10527
10528 fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply
10529
10530 fmov.l %fpsr,%d1 # save status
10531 fmov.l &0x0,%fpcr # clear FPCR
10532
10533 or.l %d1,USER_FPSR(%a6) # save INEX2,N
10534
10535 mov.b FPCR_ENABLE(%a6),%d1
10536 andi.b &0x0b,%d1 # is UNFL or INEX enabled?
10537 bne.b fsglmul_unfl_ena # yes
10538
10539fsglmul_unfl_dis:
10540 fmovm.x &0x80,FP_SCR0(%a6) # store out result
10541
10542 lea FP_SCR0(%a6),%a0 # pass: result addr
10543 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
10544 bsr.l unf_res4 # calculate default result
10545 or.b %d0,FPSR_CC(%a6) # 'Z' bit may have been set
10546 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
10547 rts
10548
10549#
10550# UNFL is enabled.
10551#
10552fsglmul_unfl_ena:
10553 fmovm.x FP_SCR1(%a6),&0x40 # load dst op
10554
10555 fmov.l L_SCR3(%a6),%fpcr # set FPCR
10556 fmov.l &0x0,%fpsr # clear FPSR
10557
10558 fsglmul.x FP_SCR0(%a6),%fp1 # execute sgl multiply
10559
10560 fmov.l &0x0,%fpcr # clear FPCR
10561
10562 fmovm.x &0x40,FP_SCR0(%a6) # save result to stack
10563 mov.l %d2,-(%sp) # save d2
10564 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
10565 mov.l %d1,%d2 # make a copy
10566 andi.l &0x7fff,%d1 # strip sign
10567 andi.w &0x8000,%d2 # keep old sign
10568 sub.l %d0,%d1 # add scale factor
10569 addi.l &0x6000,%d1 # add bias
10570 andi.w &0x7fff,%d1
10571 or.w %d2,%d1 # concat old sign,new exp
10572 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
10573 mov.l (%sp)+,%d2 # restore d2
10574 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
10575 bra.w fsglmul_unfl_dis
10576
10577fsglmul_may_unfl:
10578 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10579
10580 fmov.l L_SCR3(%a6),%fpcr # set FPCR
10581 fmov.l &0x0,%fpsr # clear FPSR
10582
10583 fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply
10584
10585 fmov.l %fpsr,%d1 # save status
10586 fmov.l &0x0,%fpcr # clear FPCR
10587
10588 or.l %d1,USER_FPSR(%a6) # save INEX2,N
10589
10590 fabs.x %fp0,%fp1 # make a copy of result
10591 fcmp.b %fp1,&0x2 # is |result| > 2.b?
10592 fbgt.w fsglmul_normal_exit # no; no underflow occurred
10593 fblt.w fsglmul_unfl # yes; underflow occurred
10594
10595#
10596# we still don't know if underflow occurred. result is ~ equal to 2. but,
10597# we don't know if the result was an underflow that rounded up to a 2 or
10598# a normalized number that rounded down to a 2. so, redo the entire operation
10599# using RZ as the rounding mode to see what the pre-rounded result is.
10600# this case should be relatively rare.
10601#
10602 fmovm.x FP_SCR1(%a6),&0x40 # load dst op into fp1
10603
10604 mov.l L_SCR3(%a6),%d1
10605 andi.b &0xc0,%d1 # keep rnd prec
10606 ori.b &rz_mode*0x10,%d1 # insert RZ
10607
10608 fmov.l %d1,%fpcr # set FPCR
10609 fmov.l &0x0,%fpsr # clear FPSR
10610
10611 fsglmul.x FP_SCR0(%a6),%fp1 # execute sgl multiply
10612
10613 fmov.l &0x0,%fpcr # clear FPCR
10614 fabs.x %fp1 # make absolute value
10615 fcmp.b %fp1,&0x2 # is |result| < 2.b?
10616 fbge.w fsglmul_normal_exit # no; no underflow occurred
10617 bra.w fsglmul_unfl # yes, underflow occurred
10618
10619##############################################################################
10620
10621#
10622# Single Precision Multiply: inputs are not both normalized; what are they?
10623#
10624fsglmul_not_norm:
10625 mov.w (tbl_fsglmul_op.b,%pc,%d1.w*2),%d1
10626 jmp (tbl_fsglmul_op.b,%pc,%d1.w*1)
10627
10628 swbeg &48
10629tbl_fsglmul_op:
10630 short fsglmul_norm - tbl_fsglmul_op # NORM x NORM
10631 short fsglmul_zero - tbl_fsglmul_op # NORM x ZERO
10632 short fsglmul_inf_src - tbl_fsglmul_op # NORM x INF
10633 short fsglmul_res_qnan - tbl_fsglmul_op # NORM x QNAN
10634 short fsglmul_norm - tbl_fsglmul_op # NORM x DENORM
10635 short fsglmul_res_snan - tbl_fsglmul_op # NORM x SNAN
10636 short tbl_fsglmul_op - tbl_fsglmul_op #
10637 short tbl_fsglmul_op - tbl_fsglmul_op #
10638
10639 short fsglmul_zero - tbl_fsglmul_op # ZERO x NORM
10640 short fsglmul_zero - tbl_fsglmul_op # ZERO x ZERO
10641 short fsglmul_res_operr - tbl_fsglmul_op # ZERO x INF
10642 short fsglmul_res_qnan - tbl_fsglmul_op # ZERO x QNAN
10643 short fsglmul_zero - tbl_fsglmul_op # ZERO x DENORM
10644 short fsglmul_res_snan - tbl_fsglmul_op # ZERO x SNAN
10645 short tbl_fsglmul_op - tbl_fsglmul_op #
10646 short tbl_fsglmul_op - tbl_fsglmul_op #
10647
10648 short fsglmul_inf_dst - tbl_fsglmul_op # INF x NORM
10649 short fsglmul_res_operr - tbl_fsglmul_op # INF x ZERO
10650 short fsglmul_inf_dst - tbl_fsglmul_op # INF x INF
10651 short fsglmul_res_qnan - tbl_fsglmul_op # INF x QNAN
10652 short fsglmul_inf_dst - tbl_fsglmul_op # INF x DENORM
10653 short fsglmul_res_snan - tbl_fsglmul_op # INF x SNAN
10654 short tbl_fsglmul_op - tbl_fsglmul_op #
10655 short tbl_fsglmul_op - tbl_fsglmul_op #
10656
10657 short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x NORM
10658 short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x ZERO
10659 short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x INF
10660 short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x QNAN
10661 short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x DENORM
10662 short fsglmul_res_snan - tbl_fsglmul_op # QNAN x SNAN
10663 short tbl_fsglmul_op - tbl_fsglmul_op #
10664 short tbl_fsglmul_op - tbl_fsglmul_op #
10665
10666 short fsglmul_norm - tbl_fsglmul_op # NORM x NORM
10667 short fsglmul_zero - tbl_fsglmul_op # NORM x ZERO
10668 short fsglmul_inf_src - tbl_fsglmul_op # NORM x INF
10669 short fsglmul_res_qnan - tbl_fsglmul_op # NORM x QNAN
10670 short fsglmul_norm - tbl_fsglmul_op # NORM x DENORM
10671 short fsglmul_res_snan - tbl_fsglmul_op # NORM x SNAN
10672 short tbl_fsglmul_op - tbl_fsglmul_op #
10673 short tbl_fsglmul_op - tbl_fsglmul_op #
10674
10675 short fsglmul_res_snan - tbl_fsglmul_op # SNAN x NORM
10676 short fsglmul_res_snan - tbl_fsglmul_op # SNAN x ZERO
10677 short fsglmul_res_snan - tbl_fsglmul_op # SNAN x INF
10678 short fsglmul_res_snan - tbl_fsglmul_op # SNAN x QNAN
10679 short fsglmul_res_snan - tbl_fsglmul_op # SNAN x DENORM
10680 short fsglmul_res_snan - tbl_fsglmul_op # SNAN x SNAN
10681 short tbl_fsglmul_op - tbl_fsglmul_op #
10682 short tbl_fsglmul_op - tbl_fsglmul_op #
10683
10684fsglmul_res_operr:
10685 bra.l res_operr
10686fsglmul_res_snan:
10687 bra.l res_snan
10688fsglmul_res_qnan:
10689 bra.l res_qnan
10690fsglmul_zero:
10691 bra.l fmul_zero
10692fsglmul_inf_src:
10693 bra.l fmul_inf_src
10694fsglmul_inf_dst:
10695 bra.l fmul_inf_dst
10696
10697#########################################################################
10698# XDEF **************************************************************** #
10699# fsgldiv(): emulates the fsgldiv instruction #
10700# #
10701# XREF **************************************************************** #
10702# scale_to_zero_src() - scale src exponent to zero #
10703# scale_to_zero_dst() - scale dst exponent to zero #
10704# unf_res4() - return default underflow result for sglop #
10705# ovf_res() - return default overflow result #
10706# res_qnan() - return QNAN result #
10707# res_snan() - return SNAN result #
10708# #
10709# INPUT *************************************************************** #
10710# a0 = pointer to extended precision source operand #
10711# a1 = pointer to extended precision destination operand #
10712# d0 rnd prec,mode #
10713# #
10714# OUTPUT ************************************************************** #
10715# fp0 = result #
10716# fp1 = EXOP (if exception occurred) #
10717# #
10718# ALGORITHM *********************************************************** #
10719# Handle NANs, infinities, and zeroes as special cases. Divide #
10720# norms/denorms into ext/sgl/dbl precision. #
10721# For norms/denorms, scale the exponents such that a divide #
10722# instruction won't cause an exception. Use the regular fsgldiv to #
10723# compute a result. Check if the regular operands would have taken #
10724# an exception. If so, return the default overflow/underflow result #
10725# and return the EXOP if exceptions are enabled. Else, scale the #
10726# result operand to the proper exponent. #
10727# #
10728#########################################################################
10729
10730 global fsgldiv
10731fsgldiv:
10732 mov.l %d0,L_SCR3(%a6) # store rnd info
10733
10734 clr.w %d1
10735 mov.b DTAG(%a6),%d1
10736 lsl.b &0x3,%d1
10737 or.b STAG(%a6),%d1 # combine src tags
10738
10739 bne.w fsgldiv_not_norm # optimize on non-norm input
10740
10741#
10742# DIVIDE: NORMs and DENORMs ONLY!
10743#
10744fsgldiv_norm:
10745 mov.w DST_EX(%a1),FP_SCR1_EX(%a6)
10746 mov.l DST_HI(%a1),FP_SCR1_HI(%a6)
10747 mov.l DST_LO(%a1),FP_SCR1_LO(%a6)
10748
10749 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
10750 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
10751 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
10752
10753 bsr.l scale_to_zero_src # calculate scale factor 1
10754 mov.l %d0,-(%sp) # save scale factor 1
10755
10756 bsr.l scale_to_zero_dst # calculate scale factor 2
10757
10758 neg.l (%sp) # S.F. = scale1 - scale2
10759 add.l %d0,(%sp)
10760
10761 mov.w 2+L_SCR3(%a6),%d1 # fetch precision,mode
10762 lsr.b &0x6,%d1
10763 mov.l (%sp)+,%d0
10764 cmpi.l %d0,&0x3fff-0x7ffe
10765 ble.w fsgldiv_may_ovfl
10766
10767 cmpi.l %d0,&0x3fff-0x0000 # will result underflow?
10768 beq.w fsgldiv_may_unfl # maybe
10769 bgt.w fsgldiv_unfl # yes; go handle underflow
10770
10771fsgldiv_normal:
10772 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10773
10774 fmov.l L_SCR3(%a6),%fpcr # save FPCR
10775 fmov.l &0x0,%fpsr # clear FPSR
10776
10777 fsgldiv.x FP_SCR0(%a6),%fp0 # perform sgl divide
10778
10779 fmov.l %fpsr,%d1 # save FPSR
10780 fmov.l &0x0,%fpcr # clear FPCR
10781
10782 or.l %d1,USER_FPSR(%a6) # save INEX2,N
10783
10784fsgldiv_normal_exit:
10785 fmovm.x &0x80,FP_SCR0(%a6) # store result on stack
10786 mov.l %d2,-(%sp) # save d2
10787 mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp}
10788 mov.l %d1,%d2 # make a copy
10789 andi.l &0x7fff,%d1 # strip sign
10790 andi.w &0x8000,%d2 # keep old sign
10791 sub.l %d0,%d1 # add scale factor
10792 or.w %d2,%d1 # concat old sign,new exp
10793 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
10794 mov.l (%sp)+,%d2 # restore d2
10795 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
10796 rts
10797
10798fsgldiv_may_ovfl:
10799 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10800
10801 fmov.l L_SCR3(%a6),%fpcr # set FPCR
10802 fmov.l &0x0,%fpsr # set FPSR
10803
10804 fsgldiv.x FP_SCR0(%a6),%fp0 # execute divide
10805
10806 fmov.l %fpsr,%d1
10807 fmov.l &0x0,%fpcr
10808
10809 or.l %d1,USER_FPSR(%a6) # save INEX,N
10810
10811 fmovm.x &0x01,-(%sp) # save result to stack
10812 mov.w (%sp),%d1 # fetch new exponent
10813 add.l &0xc,%sp # clear result
10814 andi.l &0x7fff,%d1 # strip sign
10815 sub.l %d0,%d1 # add scale factor
10816 cmp.l %d1,&0x7fff # did divide overflow?
10817 blt.b fsgldiv_normal_exit
10818
10819fsgldiv_ovfl_tst:
10820 or.w &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex
10821
10822 mov.b FPCR_ENABLE(%a6),%d1
10823 andi.b &0x13,%d1 # is OVFL or INEX enabled?
10824 bne.b fsgldiv_ovfl_ena # yes
10825
10826fsgldiv_ovfl_dis:
10827 btst &neg_bit,FPSR_CC(%a6) # is result negative
10828 sne %d1 # set sign param accordingly
10829 mov.l L_SCR3(%a6),%d0 # pass prec:rnd
10830 andi.b &0x30,%d0 # kill precision
10831 bsr.l ovf_res # calculate default result
10832 or.b %d0,FPSR_CC(%a6) # set INF if applicable
10833 fmovm.x (%a0),&0x80 # return default result in fp0
10834 rts
10835
10836fsgldiv_ovfl_ena:
10837 fmovm.x &0x80,FP_SCR0(%a6) # move result to stack
10838
10839 mov.l %d2,-(%sp) # save d2
10840 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
10841 mov.l %d1,%d2 # make a copy
10842 andi.l &0x7fff,%d1 # strip sign
10843 andi.w &0x8000,%d2 # keep old sign
10844 sub.l %d0,%d1 # add scale factor
10845 subi.l &0x6000,%d1 # subtract new bias
10846 andi.w &0x7fff,%d1 # clear ms bit
10847 or.w %d2,%d1 # concat old sign,new exp
10848 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
10849 mov.l (%sp)+,%d2 # restore d2
10850 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
10851 bra.b fsgldiv_ovfl_dis
10852
10853fsgldiv_unfl:
10854 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
10855
10856 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10857
10858 fmov.l &rz_mode*0x10,%fpcr # set FPCR
10859 fmov.l &0x0,%fpsr # clear FPSR
10860
10861 fsgldiv.x FP_SCR0(%a6),%fp0 # execute sgl divide
10862
10863 fmov.l %fpsr,%d1 # save status
10864 fmov.l &0x0,%fpcr # clear FPCR
10865
10866 or.l %d1,USER_FPSR(%a6) # save INEX2,N
10867
10868 mov.b FPCR_ENABLE(%a6),%d1
10869 andi.b &0x0b,%d1 # is UNFL or INEX enabled?
10870 bne.b fsgldiv_unfl_ena # yes
10871
10872fsgldiv_unfl_dis:
10873 fmovm.x &0x80,FP_SCR0(%a6) # store out result
10874
10875 lea FP_SCR0(%a6),%a0 # pass: result addr
10876 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
10877 bsr.l unf_res4 # calculate default result
10878 or.b %d0,FPSR_CC(%a6) # 'Z' bit may have been set
10879 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
10880 rts
10881
10882#
10883# UNFL is enabled.
10884#
10885fsgldiv_unfl_ena:
10886 fmovm.x FP_SCR1(%a6),&0x40 # load dst op
10887
10888 fmov.l L_SCR3(%a6),%fpcr # set FPCR
10889 fmov.l &0x0,%fpsr # clear FPSR
10890
10891 fsgldiv.x FP_SCR0(%a6),%fp1 # execute sgl divide
10892
10893 fmov.l &0x0,%fpcr # clear FPCR
10894
10895 fmovm.x &0x40,FP_SCR0(%a6) # save result to stack
10896 mov.l %d2,-(%sp) # save d2
10897 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
10898 mov.l %d1,%d2 # make a copy
10899 andi.l &0x7fff,%d1 # strip sign
10900 andi.w &0x8000,%d2 # keep old sign
10901 sub.l %d0,%d1 # add scale factor
10902 addi.l &0x6000,%d1 # add bias
10903 andi.w &0x7fff,%d1 # clear top bit
10904 or.w %d2,%d1 # concat old sign, new exp
10905 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
10906 mov.l (%sp)+,%d2 # restore d2
10907 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
10908 bra.b fsgldiv_unfl_dis
10909
10910#
10911# the divide operation MAY underflow:
10912#
10913fsgldiv_may_unfl:
10914 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
10915
10916 fmov.l L_SCR3(%a6),%fpcr # set FPCR
10917 fmov.l &0x0,%fpsr # clear FPSR
10918
10919 fsgldiv.x FP_SCR0(%a6),%fp0 # execute sgl divide
10920
10921 fmov.l %fpsr,%d1 # save status
10922 fmov.l &0x0,%fpcr # clear FPCR
10923
10924 or.l %d1,USER_FPSR(%a6) # save INEX2,N
10925
10926 fabs.x %fp0,%fp1 # make a copy of result
10927 fcmp.b %fp1,&0x1 # is |result| > 1.b?
10928 fbgt.w fsgldiv_normal_exit # no; no underflow occurred
10929 fblt.w fsgldiv_unfl # yes; underflow occurred
10930
10931#
10932# we still don't know if underflow occurred. result is ~ equal to 1. but,
10933# we don't know if the result was an underflow that rounded up to a 1
10934# or a normalized number that rounded down to a 1. so, redo the entire
10935# operation using RZ as the rounding mode to see what the pre-rounded
10936# result is. this case should be relatively rare.
10937#
10938 fmovm.x FP_SCR1(%a6),&0x40 # load dst op into %fp1
10939
10940 clr.l %d1 # clear scratch register
10941 ori.b &rz_mode*0x10,%d1 # force RZ rnd mode
10942
10943 fmov.l %d1,%fpcr # set FPCR
10944 fmov.l &0x0,%fpsr # clear FPSR
10945
10946 fsgldiv.x FP_SCR0(%a6),%fp1 # execute sgl divide
10947
10948 fmov.l &0x0,%fpcr # clear FPCR
10949 fabs.x %fp1 # make absolute value
10950 fcmp.b %fp1,&0x1 # is |result| < 1.b?
10951 fbge.w fsgldiv_normal_exit # no; no underflow occurred
10952 bra.w fsgldiv_unfl # yes; underflow occurred
10953
10954############################################################################
10955
10956#
10957# Divide: inputs are not both normalized; what are they?
10958#
10959fsgldiv_not_norm:
10960 mov.w (tbl_fsgldiv_op.b,%pc,%d1.w*2),%d1
10961 jmp (tbl_fsgldiv_op.b,%pc,%d1.w*1)
10962
10963 swbeg &48
10964tbl_fsgldiv_op:
10965 short fsgldiv_norm - tbl_fsgldiv_op # NORM / NORM
10966 short fsgldiv_inf_load - tbl_fsgldiv_op # NORM / ZERO
10967 short fsgldiv_zero_load - tbl_fsgldiv_op # NORM / INF
10968 short fsgldiv_res_qnan - tbl_fsgldiv_op # NORM / QNAN
10969 short fsgldiv_norm - tbl_fsgldiv_op # NORM / DENORM
10970 short fsgldiv_res_snan - tbl_fsgldiv_op # NORM / SNAN
10971 short tbl_fsgldiv_op - tbl_fsgldiv_op #
10972 short tbl_fsgldiv_op - tbl_fsgldiv_op #
10973
10974 short fsgldiv_zero_load - tbl_fsgldiv_op # ZERO / NORM
10975 short fsgldiv_res_operr - tbl_fsgldiv_op # ZERO / ZERO
10976 short fsgldiv_zero_load - tbl_fsgldiv_op # ZERO / INF
10977 short fsgldiv_res_qnan - tbl_fsgldiv_op # ZERO / QNAN
10978 short fsgldiv_zero_load - tbl_fsgldiv_op # ZERO / DENORM
10979 short fsgldiv_res_snan - tbl_fsgldiv_op # ZERO / SNAN
10980 short tbl_fsgldiv_op - tbl_fsgldiv_op #
10981 short tbl_fsgldiv_op - tbl_fsgldiv_op #
10982
10983 short fsgldiv_inf_dst - tbl_fsgldiv_op # INF / NORM
10984 short fsgldiv_inf_dst - tbl_fsgldiv_op # INF / ZERO
10985 short fsgldiv_res_operr - tbl_fsgldiv_op # INF / INF
10986 short fsgldiv_res_qnan - tbl_fsgldiv_op # INF / QNAN
10987 short fsgldiv_inf_dst - tbl_fsgldiv_op # INF / DENORM
10988 short fsgldiv_res_snan - tbl_fsgldiv_op # INF / SNAN
10989 short tbl_fsgldiv_op - tbl_fsgldiv_op #
10990 short tbl_fsgldiv_op - tbl_fsgldiv_op #
10991
10992 short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / NORM
10993 short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / ZERO
10994 short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / INF
10995 short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / QNAN
10996 short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / DENORM
10997 short fsgldiv_res_snan - tbl_fsgldiv_op # QNAN / SNAN
10998 short tbl_fsgldiv_op - tbl_fsgldiv_op #
10999 short tbl_fsgldiv_op - tbl_fsgldiv_op #
11000
11001 short fsgldiv_norm - tbl_fsgldiv_op # DENORM / NORM
11002 short fsgldiv_inf_load - tbl_fsgldiv_op # DENORM / ZERO
11003 short fsgldiv_zero_load - tbl_fsgldiv_op # DENORM / INF
11004 short fsgldiv_res_qnan - tbl_fsgldiv_op # DENORM / QNAN
11005 short fsgldiv_norm - tbl_fsgldiv_op # DENORM / DENORM
11006 short fsgldiv_res_snan - tbl_fsgldiv_op # DENORM / SNAN
11007 short tbl_fsgldiv_op - tbl_fsgldiv_op #
11008 short tbl_fsgldiv_op - tbl_fsgldiv_op #
11009
11010 short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / NORM
11011 short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / ZERO
11012 short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / INF
11013 short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / QNAN
11014 short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / DENORM
11015 short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / SNAN
11016 short tbl_fsgldiv_op - tbl_fsgldiv_op #
11017 short tbl_fsgldiv_op - tbl_fsgldiv_op #
11018
11019fsgldiv_res_qnan:
11020 bra.l res_qnan
11021fsgldiv_res_snan:
11022 bra.l res_snan
11023fsgldiv_res_operr:
11024 bra.l res_operr
11025fsgldiv_inf_load:
11026 bra.l fdiv_inf_load
11027fsgldiv_zero_load:
11028 bra.l fdiv_zero_load
11029fsgldiv_inf_dst:
11030 bra.l fdiv_inf_dst
11031
11032#########################################################################
11033# XDEF **************************************************************** #
11034# fadd(): emulates the fadd instruction #
11035# fsadd(): emulates the fadd instruction #
11036# fdadd(): emulates the fdadd instruction #
11037# #
11038# XREF **************************************************************** #
11039# addsub_scaler2() - scale the operands so they won't take exc #
11040# ovf_res() - return default overflow result #
11041# unf_res() - return default underflow result #
11042# res_qnan() - set QNAN result #
11043# res_snan() - set SNAN result #
11044# res_operr() - set OPERR result #
11045# scale_to_zero_src() - set src operand exponent equal to zero #
11046# scale_to_zero_dst() - set dst operand exponent equal to zero #
11047# #
11048# INPUT *************************************************************** #
11049# a0 = pointer to extended precision source operand #
11050# a1 = pointer to extended precision destination operand #
11051# #
11052# OUTPUT ************************************************************** #
11053# fp0 = result #
11054# fp1 = EXOP (if exception occurred) #
11055# #
11056# ALGORITHM *********************************************************** #
11057# Handle NANs, infinities, and zeroes as special cases. Divide #
11058# norms into extended, single, and double precision. #
11059# Do addition after scaling exponents such that exception won't #
11060# occur. Then, check result exponent to see if exception would have #
11061# occurred. If so, return default result and maybe EXOP. Else, insert #
11062# the correct result exponent and return. Set FPSR bits as appropriate. #
11063# #
11064#########################################################################
11065
11066 global fsadd
11067fsadd:
11068 andi.b &0x30,%d0 # clear rnd prec
11069 ori.b &s_mode*0x10,%d0 # insert sgl prec
11070 bra.b fadd
11071
11072 global fdadd
11073fdadd:
11074 andi.b &0x30,%d0 # clear rnd prec
11075 ori.b &d_mode*0x10,%d0 # insert dbl prec
11076
11077 global fadd
11078fadd:
11079 mov.l %d0,L_SCR3(%a6) # store rnd info
11080
11081 clr.w %d1
11082 mov.b DTAG(%a6),%d1
11083 lsl.b &0x3,%d1
11084 or.b STAG(%a6),%d1 # combine src tags
11085
11086 bne.w fadd_not_norm # optimize on non-norm input
11087
11088#
11089# ADD: norms and denorms
11090#
11091fadd_norm:
11092 bsr.l addsub_scaler2 # scale exponents
11093
11094fadd_zero_entry:
11095 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
11096
11097 fmov.l &0x0,%fpsr # clear FPSR
11098 fmov.l L_SCR3(%a6),%fpcr # set FPCR
11099
11100 fadd.x FP_SCR0(%a6),%fp0 # execute add
11101
11102 fmov.l &0x0,%fpcr # clear FPCR
11103 fmov.l %fpsr,%d1 # fetch INEX2,N,Z
11104
11105 or.l %d1,USER_FPSR(%a6) # save exc and ccode bits
11106
11107 fbeq.w fadd_zero_exit # if result is zero, end now
11108
11109 mov.l %d2,-(%sp) # save d2
11110
11111 fmovm.x &0x01,-(%sp) # save result to stack
11112
11113 mov.w 2+L_SCR3(%a6),%d1
11114 lsr.b &0x6,%d1
11115
11116 mov.w (%sp),%d2 # fetch new sign, exp
11117 andi.l &0x7fff,%d2 # strip sign
11118 sub.l %d0,%d2 # add scale factor
11119
11120 cmp.l %d2,(tbl_fadd_ovfl.b,%pc,%d1.w*4) # is it an overflow?
11121 bge.b fadd_ovfl # yes
11122
11123 cmp.l %d2,(tbl_fadd_unfl.b,%pc,%d1.w*4) # is it an underflow?
11124 blt.w fadd_unfl # yes
11125 beq.w fadd_may_unfl # maybe; go find out
11126
11127fadd_normal:
11128 mov.w (%sp),%d1
11129 andi.w &0x8000,%d1 # keep sign
11130 or.w %d2,%d1 # concat sign,new exp
11131 mov.w %d1,(%sp) # insert new exponent
11132
11133 fmovm.x (%sp)+,&0x80 # return result in fp0
11134
11135 mov.l (%sp)+,%d2 # restore d2
11136 rts
11137
11138fadd_zero_exit:
11139# fmov.s &0x00000000,%fp0 # return zero in fp0
11140 rts
11141
11142tbl_fadd_ovfl:
11143 long 0x7fff # ext ovfl
11144 long 0x407f # sgl ovfl
11145 long 0x43ff # dbl ovfl
11146
11147tbl_fadd_unfl:
11148 long 0x0000 # ext unfl
11149 long 0x3f81 # sgl unfl
11150 long 0x3c01 # dbl unfl
11151
11152fadd_ovfl:
11153 or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
11154
11155 mov.b FPCR_ENABLE(%a6),%d1
11156 andi.b &0x13,%d1 # is OVFL or INEX enabled?
11157 bne.b fadd_ovfl_ena # yes
11158
11159 add.l &0xc,%sp
11160fadd_ovfl_dis:
11161 btst &neg_bit,FPSR_CC(%a6) # is result negative?
11162 sne %d1 # set sign param accordingly
11163 mov.l L_SCR3(%a6),%d0 # pass prec:rnd
11164 bsr.l ovf_res # calculate default result
11165 or.b %d0,FPSR_CC(%a6) # set INF,N if applicable
11166 fmovm.x (%a0),&0x80 # return default result in fp0
11167 mov.l (%sp)+,%d2 # restore d2
11168 rts
11169
11170fadd_ovfl_ena:
11171 mov.b L_SCR3(%a6),%d1
11172 andi.b &0xc0,%d1 # is precision extended?
11173 bne.b fadd_ovfl_ena_sd # no; prec = sgl or dbl
11174
11175fadd_ovfl_ena_cont:
11176 mov.w (%sp),%d1
11177 andi.w &0x8000,%d1 # keep sign
11178 subi.l &0x6000,%d2 # add extra bias
11179 andi.w &0x7fff,%d2
11180 or.w %d2,%d1 # concat sign,new exp
11181 mov.w %d1,(%sp) # insert new exponent
11182
11183 fmovm.x (%sp)+,&0x40 # return EXOP in fp1
11184 bra.b fadd_ovfl_dis
11185
11186fadd_ovfl_ena_sd:
11187 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
11188
11189 mov.l L_SCR3(%a6),%d1
11190 andi.b &0x30,%d1 # keep rnd mode
11191 fmov.l %d1,%fpcr # set FPCR
11192
11193 fadd.x FP_SCR0(%a6),%fp0 # execute add
11194
11195 fmov.l &0x0,%fpcr # clear FPCR
11196
11197 add.l &0xc,%sp
11198 fmovm.x &0x01,-(%sp)
11199 bra.b fadd_ovfl_ena_cont
11200
11201fadd_unfl:
11202 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
11203
11204 add.l &0xc,%sp
11205
11206 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
11207
11208 fmov.l &rz_mode*0x10,%fpcr # set FPCR
11209 fmov.l &0x0,%fpsr # clear FPSR
11210
11211 fadd.x FP_SCR0(%a6),%fp0 # execute add
11212
11213 fmov.l &0x0,%fpcr # clear FPCR
11214 fmov.l %fpsr,%d1 # save status
11215
11216 or.l %d1,USER_FPSR(%a6) # save INEX,N
11217
11218 mov.b FPCR_ENABLE(%a6),%d1
11219 andi.b &0x0b,%d1 # is UNFL or INEX enabled?
11220 bne.b fadd_unfl_ena # yes
11221
11222fadd_unfl_dis:
11223 fmovm.x &0x80,FP_SCR0(%a6) # store out result
11224
11225 lea FP_SCR0(%a6),%a0 # pass: result addr
11226 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
11227 bsr.l unf_res # calculate default result
11228 or.b %d0,FPSR_CC(%a6) # 'Z' bit may have been set
11229 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
11230 mov.l (%sp)+,%d2 # restore d2
11231 rts
11232
11233fadd_unfl_ena:
11234 fmovm.x FP_SCR1(%a6),&0x40 # load dst op
11235
11236 mov.l L_SCR3(%a6),%d1
11237 andi.b &0xc0,%d1 # is precision extended?
11238 bne.b fadd_unfl_ena_sd # no; sgl or dbl
11239
11240 fmov.l L_SCR3(%a6),%fpcr # set FPCR
11241
11242fadd_unfl_ena_cont:
11243 fmov.l &0x0,%fpsr # clear FPSR
11244
11245 fadd.x FP_SCR0(%a6),%fp1 # execute multiply
11246
11247 fmov.l &0x0,%fpcr # clear FPCR
11248
11249 fmovm.x &0x40,FP_SCR0(%a6) # save result to stack
11250 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
11251 mov.l %d1,%d2 # make a copy
11252 andi.l &0x7fff,%d1 # strip sign
11253 andi.w &0x8000,%d2 # keep old sign
11254 sub.l %d0,%d1 # add scale factor
11255 addi.l &0x6000,%d1 # add new bias
11256 andi.w &0x7fff,%d1 # clear top bit
11257 or.w %d2,%d1 # concat sign,new exp
11258 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
11259 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
11260 bra.w fadd_unfl_dis
11261
11262fadd_unfl_ena_sd:
11263 mov.l L_SCR3(%a6),%d1
11264 andi.b &0x30,%d1 # use only rnd mode
11265 fmov.l %d1,%fpcr # set FPCR
11266
11267 bra.b fadd_unfl_ena_cont
11268
11269#
11270# result is equal to the smallest normalized number in the selected precision
11271# if the precision is extended, this result could not have come from an
11272# underflow that rounded up.
11273#
11274fadd_may_unfl:
11275 mov.l L_SCR3(%a6),%d1
11276 andi.b &0xc0,%d1
11277 beq.w fadd_normal # yes; no underflow occurred
11278
11279 mov.l 0x4(%sp),%d1 # extract hi(man)
11280 cmpi.l %d1,&0x80000000 # is hi(man) = 0x80000000?
11281 bne.w fadd_normal # no; no underflow occurred
11282
11283 tst.l 0x8(%sp) # is lo(man) = 0x0?
11284 bne.w fadd_normal # no; no underflow occurred
11285
11286 btst &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
11287 beq.w fadd_normal # no; no underflow occurred
11288
11289#
11290# ok, so now the result has a exponent equal to the smallest normalized
11291# exponent for the selected precision. also, the mantissa is equal to
11292# 0x8000000000000000 and this mantissa is the result of rounding non-zero
11293# g,r,s.
11294# now, we must determine whether the pre-rounded result was an underflow
11295# rounded "up" or a normalized number rounded "down".
11296# so, we do this be re-executing the add using RZ as the rounding mode and
11297# seeing if the new result is smaller or equal to the current result.
11298#
11299 fmovm.x FP_SCR1(%a6),&0x40 # load dst op into fp1
11300
11301 mov.l L_SCR3(%a6),%d1
11302 andi.b &0xc0,%d1 # keep rnd prec
11303 ori.b &rz_mode*0x10,%d1 # insert rnd mode
11304 fmov.l %d1,%fpcr # set FPCR
11305 fmov.l &0x0,%fpsr # clear FPSR
11306
11307 fadd.x FP_SCR0(%a6),%fp1 # execute add
11308
11309 fmov.l &0x0,%fpcr # clear FPCR
11310
11311 fabs.x %fp0 # compare absolute values
11312 fabs.x %fp1
11313 fcmp.x %fp0,%fp1 # is first result > second?
11314
11315 fbgt.w fadd_unfl # yes; it's an underflow
11316 bra.w fadd_normal # no; it's not an underflow
11317
11318##########################################################################
11319
11320#
11321# Add: inputs are not both normalized; what are they?
11322#
11323fadd_not_norm:
11324 mov.w (tbl_fadd_op.b,%pc,%d1.w*2),%d1
11325 jmp (tbl_fadd_op.b,%pc,%d1.w*1)
11326
11327 swbeg &48
11328tbl_fadd_op:
11329 short fadd_norm - tbl_fadd_op # NORM + NORM
11330 short fadd_zero_src - tbl_fadd_op # NORM + ZERO
11331 short fadd_inf_src - tbl_fadd_op # NORM + INF
11332 short fadd_res_qnan - tbl_fadd_op # NORM + QNAN
11333 short fadd_norm - tbl_fadd_op # NORM + DENORM
11334 short fadd_res_snan - tbl_fadd_op # NORM + SNAN
11335 short tbl_fadd_op - tbl_fadd_op #
11336 short tbl_fadd_op - tbl_fadd_op #
11337
11338 short fadd_zero_dst - tbl_fadd_op # ZERO + NORM
11339 short fadd_zero_2 - tbl_fadd_op # ZERO + ZERO
11340 short fadd_inf_src - tbl_fadd_op # ZERO + INF
11341 short fadd_res_qnan - tbl_fadd_op # NORM + QNAN
11342 short fadd_zero_dst - tbl_fadd_op # ZERO + DENORM
11343 short fadd_res_snan - tbl_fadd_op # NORM + SNAN
11344 short tbl_fadd_op - tbl_fadd_op #
11345 short tbl_fadd_op - tbl_fadd_op #
11346
11347 short fadd_inf_dst - tbl_fadd_op # INF + NORM
11348 short fadd_inf_dst - tbl_fadd_op # INF + ZERO
11349 short fadd_inf_2 - tbl_fadd_op # INF + INF
11350 short fadd_res_qnan - tbl_fadd_op # NORM + QNAN
11351 short fadd_inf_dst - tbl_fadd_op # INF + DENORM
11352 short fadd_res_snan - tbl_fadd_op # NORM + SNAN
11353 short tbl_fadd_op - tbl_fadd_op #
11354 short tbl_fadd_op - tbl_fadd_op #
11355
11356 short fadd_res_qnan - tbl_fadd_op # QNAN + NORM
11357 short fadd_res_qnan - tbl_fadd_op # QNAN + ZERO
11358 short fadd_res_qnan - tbl_fadd_op # QNAN + INF
11359 short fadd_res_qnan - tbl_fadd_op # QNAN + QNAN
11360 short fadd_res_qnan - tbl_fadd_op # QNAN + DENORM
11361 short fadd_res_snan - tbl_fadd_op # QNAN + SNAN
11362 short tbl_fadd_op - tbl_fadd_op #
11363 short tbl_fadd_op - tbl_fadd_op #
11364
11365 short fadd_norm - tbl_fadd_op # DENORM + NORM
11366 short fadd_zero_src - tbl_fadd_op # DENORM + ZERO
11367 short fadd_inf_src - tbl_fadd_op # DENORM + INF
11368 short fadd_res_qnan - tbl_fadd_op # NORM + QNAN
11369 short fadd_norm - tbl_fadd_op # DENORM + DENORM
11370 short fadd_res_snan - tbl_fadd_op # NORM + SNAN
11371 short tbl_fadd_op - tbl_fadd_op #
11372 short tbl_fadd_op - tbl_fadd_op #
11373
11374 short fadd_res_snan - tbl_fadd_op # SNAN + NORM
11375 short fadd_res_snan - tbl_fadd_op # SNAN + ZERO
11376 short fadd_res_snan - tbl_fadd_op # SNAN + INF
11377 short fadd_res_snan - tbl_fadd_op # SNAN + QNAN
11378 short fadd_res_snan - tbl_fadd_op # SNAN + DENORM
11379 short fadd_res_snan - tbl_fadd_op # SNAN + SNAN
11380 short tbl_fadd_op - tbl_fadd_op #
11381 short tbl_fadd_op - tbl_fadd_op #
11382
11383fadd_res_qnan:
11384 bra.l res_qnan
11385fadd_res_snan:
11386 bra.l res_snan
11387
11388#
11389# both operands are ZEROes
11390#
11391fadd_zero_2:
11392 mov.b SRC_EX(%a0),%d0 # are the signs opposite
11393 mov.b DST_EX(%a1),%d1
11394 eor.b %d0,%d1
11395 bmi.w fadd_zero_2_chk_rm # weed out (-ZERO)+(+ZERO)
11396
11397# the signs are the same. so determine whether they are positive or negative
11398# and return the appropriately signed zero.
11399 tst.b %d0 # are ZEROes positive or negative?
11400 bmi.b fadd_zero_rm # negative
11401 fmov.s &0x00000000,%fp0 # return +ZERO
11402 mov.b &z_bmask,FPSR_CC(%a6) # set Z
11403 rts
11404
11405#
11406# the ZEROes have opposite signs:
11407# - therefore, we return +ZERO if the rounding modes are RN,RZ, or RP.
11408# - -ZERO is returned in the case of RM.
11409#
11410fadd_zero_2_chk_rm:
11411 mov.b 3+L_SCR3(%a6),%d1
11412 andi.b &0x30,%d1 # extract rnd mode
11413 cmpi.b %d1,&rm_mode*0x10 # is rnd mode == RM?
11414 beq.b fadd_zero_rm # yes
11415 fmov.s &0x00000000,%fp0 # return +ZERO
11416 mov.b &z_bmask,FPSR_CC(%a6) # set Z
11417 rts
11418
11419fadd_zero_rm:
11420 fmov.s &0x80000000,%fp0 # return -ZERO
11421 mov.b &neg_bmask+z_bmask,FPSR_CC(%a6) # set NEG/Z
11422 rts
11423
11424#
11425# one operand is a ZERO and the other is a DENORM or NORM. scale
11426# the DENORM or NORM and jump to the regular fadd routine.
11427#
11428fadd_zero_dst:
11429 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
11430 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
11431 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
11432 bsr.l scale_to_zero_src # scale the operand
11433 clr.w FP_SCR1_EX(%a6)
11434 clr.l FP_SCR1_HI(%a6)
11435 clr.l FP_SCR1_LO(%a6)
11436 bra.w fadd_zero_entry # go execute fadd
11437
11438fadd_zero_src:
11439 mov.w DST_EX(%a1),FP_SCR1_EX(%a6)
11440 mov.l DST_HI(%a1),FP_SCR1_HI(%a6)
11441 mov.l DST_LO(%a1),FP_SCR1_LO(%a6)
11442 bsr.l scale_to_zero_dst # scale the operand
11443 clr.w FP_SCR0_EX(%a6)
11444 clr.l FP_SCR0_HI(%a6)
11445 clr.l FP_SCR0_LO(%a6)
11446 bra.w fadd_zero_entry # go execute fadd
11447
11448#
11449# both operands are INFs. an OPERR will result if the INFs have
11450# different signs. else, an INF of the same sign is returned
11451#
11452fadd_inf_2:
11453 mov.b SRC_EX(%a0),%d0 # exclusive or the signs
11454 mov.b DST_EX(%a1),%d1
11455 eor.b %d1,%d0
11456 bmi.l res_operr # weed out (-INF)+(+INF)
11457
11458# ok, so it's not an OPERR. but, we do have to remember to return the
11459# src INF since that's where the 881/882 gets the j-bit from...
11460
11461#
11462# operands are INF and one of {ZERO, INF, DENORM, NORM}
11463#
11464fadd_inf_src:
11465 fmovm.x SRC(%a0),&0x80 # return src INF
11466 tst.b SRC_EX(%a0) # is INF positive?
11467 bpl.b fadd_inf_done # yes; we're done
11468 mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
11469 rts
11470
11471#
11472# operands are INF and one of {ZERO, INF, DENORM, NORM}
11473#
11474fadd_inf_dst:
11475 fmovm.x DST(%a1),&0x80 # return dst INF
11476 tst.b DST_EX(%a1) # is INF positive?
11477 bpl.b fadd_inf_done # yes; we're done
11478 mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
11479 rts
11480
11481fadd_inf_done:
11482 mov.b &inf_bmask,FPSR_CC(%a6) # set INF
11483 rts
11484
11485#########################################################################
11486# XDEF **************************************************************** #
11487# fsub(): emulates the fsub instruction #
11488# fssub(): emulates the fssub instruction #
11489# fdsub(): emulates the fdsub instruction #
11490# #
11491# XREF **************************************************************** #
11492# addsub_scaler2() - scale the operands so they won't take exc #
11493# ovf_res() - return default overflow result #
11494# unf_res() - return default underflow result #
11495# res_qnan() - set QNAN result #
11496# res_snan() - set SNAN result #
11497# res_operr() - set OPERR result #
11498# scale_to_zero_src() - set src operand exponent equal to zero #
11499# scale_to_zero_dst() - set dst operand exponent equal to zero #
11500# #
11501# INPUT *************************************************************** #
11502# a0 = pointer to extended precision source operand #
11503# a1 = pointer to extended precision destination operand #
11504# #
11505# OUTPUT ************************************************************** #
11506# fp0 = result #
11507# fp1 = EXOP (if exception occurred) #
11508# #
11509# ALGORITHM *********************************************************** #
11510# Handle NANs, infinities, and zeroes as special cases. Divide #
11511# norms into extended, single, and double precision. #
11512# Do subtraction after scaling exponents such that exception won't#
11513# occur. Then, check result exponent to see if exception would have #
11514# occurred. If so, return default result and maybe EXOP. Else, insert #
11515# the correct result exponent and return. Set FPSR bits as appropriate. #
11516# #
11517#########################################################################
11518
11519 global fssub
11520fssub:
11521 andi.b &0x30,%d0 # clear rnd prec
11522 ori.b &s_mode*0x10,%d0 # insert sgl prec
11523 bra.b fsub
11524
11525 global fdsub
11526fdsub:
11527 andi.b &0x30,%d0 # clear rnd prec
11528 ori.b &d_mode*0x10,%d0 # insert dbl prec
11529
11530 global fsub
11531fsub:
11532 mov.l %d0,L_SCR3(%a6) # store rnd info
11533
11534 clr.w %d1
11535 mov.b DTAG(%a6),%d1
11536 lsl.b &0x3,%d1
11537 or.b STAG(%a6),%d1 # combine src tags
11538
11539 bne.w fsub_not_norm # optimize on non-norm input
11540
11541#
11542# SUB: norms and denorms
11543#
11544fsub_norm:
11545 bsr.l addsub_scaler2 # scale exponents
11546
11547fsub_zero_entry:
11548 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
11549
11550 fmov.l &0x0,%fpsr # clear FPSR
11551 fmov.l L_SCR3(%a6),%fpcr # set FPCR
11552
11553 fsub.x FP_SCR0(%a6),%fp0 # execute subtract
11554
11555 fmov.l &0x0,%fpcr # clear FPCR
11556 fmov.l %fpsr,%d1 # fetch INEX2, N, Z
11557
11558 or.l %d1,USER_FPSR(%a6) # save exc and ccode bits
11559
11560 fbeq.w fsub_zero_exit # if result zero, end now
11561
11562 mov.l %d2,-(%sp) # save d2
11563
11564 fmovm.x &0x01,-(%sp) # save result to stack
11565
11566 mov.w 2+L_SCR3(%a6),%d1
11567 lsr.b &0x6,%d1
11568
11569 mov.w (%sp),%d2 # fetch new exponent
11570 andi.l &0x7fff,%d2 # strip sign
11571 sub.l %d0,%d2 # add scale factor
11572
11573 cmp.l %d2,(tbl_fsub_ovfl.b,%pc,%d1.w*4) # is it an overflow?
11574 bge.b fsub_ovfl # yes
11575
11576 cmp.l %d2,(tbl_fsub_unfl.b,%pc,%d1.w*4) # is it an underflow?
11577 blt.w fsub_unfl # yes
11578 beq.w fsub_may_unfl # maybe; go find out
11579
11580fsub_normal:
11581 mov.w (%sp),%d1
11582 andi.w &0x8000,%d1 # keep sign
11583 or.w %d2,%d1 # insert new exponent
11584 mov.w %d1,(%sp) # insert new exponent
11585
11586 fmovm.x (%sp)+,&0x80 # return result in fp0
11587
11588 mov.l (%sp)+,%d2 # restore d2
11589 rts
11590
11591fsub_zero_exit:
11592# fmov.s &0x00000000,%fp0 # return zero in fp0
11593 rts
11594
11595tbl_fsub_ovfl:
11596 long 0x7fff # ext ovfl
11597 long 0x407f # sgl ovfl
11598 long 0x43ff # dbl ovfl
11599
11600tbl_fsub_unfl:
11601 long 0x0000 # ext unfl
11602 long 0x3f81 # sgl unfl
11603 long 0x3c01 # dbl unfl
11604
11605fsub_ovfl:
11606 or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
11607
11608 mov.b FPCR_ENABLE(%a6),%d1
11609 andi.b &0x13,%d1 # is OVFL or INEX enabled?
11610 bne.b fsub_ovfl_ena # yes
11611
11612 add.l &0xc,%sp
11613fsub_ovfl_dis:
11614 btst &neg_bit,FPSR_CC(%a6) # is result negative?
11615 sne %d1 # set sign param accordingly
11616 mov.l L_SCR3(%a6),%d0 # pass prec:rnd
11617 bsr.l ovf_res # calculate default result
11618 or.b %d0,FPSR_CC(%a6) # set INF,N if applicable
11619 fmovm.x (%a0),&0x80 # return default result in fp0
11620 mov.l (%sp)+,%d2 # restore d2
11621 rts
11622
11623fsub_ovfl_ena:
11624 mov.b L_SCR3(%a6),%d1
11625 andi.b &0xc0,%d1 # is precision extended?
11626 bne.b fsub_ovfl_ena_sd # no
11627
11628fsub_ovfl_ena_cont:
11629 mov.w (%sp),%d1 # fetch {sgn,exp}
11630 andi.w &0x8000,%d1 # keep sign
11631 subi.l &0x6000,%d2 # subtract new bias
11632 andi.w &0x7fff,%d2 # clear top bit
11633 or.w %d2,%d1 # concat sign,exp
11634 mov.w %d1,(%sp) # insert new exponent
11635
11636 fmovm.x (%sp)+,&0x40 # return EXOP in fp1
11637 bra.b fsub_ovfl_dis
11638
11639fsub_ovfl_ena_sd:
11640 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
11641
11642 mov.l L_SCR3(%a6),%d1
11643 andi.b &0x30,%d1 # clear rnd prec
11644 fmov.l %d1,%fpcr # set FPCR
11645
11646 fsub.x FP_SCR0(%a6),%fp0 # execute subtract
11647
11648 fmov.l &0x0,%fpcr # clear FPCR
11649
11650 add.l &0xc,%sp
11651 fmovm.x &0x01,-(%sp)
11652 bra.b fsub_ovfl_ena_cont
11653
11654fsub_unfl:
11655 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
11656
11657 add.l &0xc,%sp
11658
11659 fmovm.x FP_SCR1(%a6),&0x80 # load dst op
11660
11661 fmov.l &rz_mode*0x10,%fpcr # set FPCR
11662 fmov.l &0x0,%fpsr # clear FPSR
11663
11664 fsub.x FP_SCR0(%a6),%fp0 # execute subtract
11665
11666 fmov.l &0x0,%fpcr # clear FPCR
11667 fmov.l %fpsr,%d1 # save status
11668
11669 or.l %d1,USER_FPSR(%a6)
11670
11671 mov.b FPCR_ENABLE(%a6),%d1
11672 andi.b &0x0b,%d1 # is UNFL or INEX enabled?
11673 bne.b fsub_unfl_ena # yes
11674
11675fsub_unfl_dis:
11676 fmovm.x &0x80,FP_SCR0(%a6) # store out result
11677
11678 lea FP_SCR0(%a6),%a0 # pass: result addr
11679 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
11680 bsr.l unf_res # calculate default result
11681 or.b %d0,FPSR_CC(%a6) # 'Z' may have been set
11682 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
11683 mov.l (%sp)+,%d2 # restore d2
11684 rts
11685
11686fsub_unfl_ena:
11687 fmovm.x FP_SCR1(%a6),&0x40
11688
11689 mov.l L_SCR3(%a6),%d1
11690 andi.b &0xc0,%d1 # is precision extended?
11691 bne.b fsub_unfl_ena_sd # no
11692
11693 fmov.l L_SCR3(%a6),%fpcr # set FPCR
11694
11695fsub_unfl_ena_cont:
11696 fmov.l &0x0,%fpsr # clear FPSR
11697
11698 fsub.x FP_SCR0(%a6),%fp1 # execute subtract
11699
11700 fmov.l &0x0,%fpcr # clear FPCR
11701
11702 fmovm.x &0x40,FP_SCR0(%a6) # store result to stack
11703 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
11704 mov.l %d1,%d2 # make a copy
11705 andi.l &0x7fff,%d1 # strip sign
11706 andi.w &0x8000,%d2 # keep old sign
11707 sub.l %d0,%d1 # add scale factor
11708 addi.l &0x6000,%d1 # subtract new bias
11709 andi.w &0x7fff,%d1 # clear top bit
11710 or.w %d2,%d1 # concat sgn,exp
11711 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
11712 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
11713 bra.w fsub_unfl_dis
11714
11715fsub_unfl_ena_sd:
11716 mov.l L_SCR3(%a6),%d1
11717 andi.b &0x30,%d1 # clear rnd prec
11718 fmov.l %d1,%fpcr # set FPCR
11719
11720 bra.b fsub_unfl_ena_cont
11721
11722#
11723# result is equal to the smallest normalized number in the selected precision
11724# if the precision is extended, this result could not have come from an
11725# underflow that rounded up.
11726#
11727fsub_may_unfl:
11728 mov.l L_SCR3(%a6),%d1
11729 andi.b &0xc0,%d1 # fetch rnd prec
11730 beq.w fsub_normal # yes; no underflow occurred
11731
11732 mov.l 0x4(%sp),%d1
11733 cmpi.l %d1,&0x80000000 # is hi(man) = 0x80000000?
11734 bne.w fsub_normal # no; no underflow occurred
11735
11736 tst.l 0x8(%sp) # is lo(man) = 0x0?
11737 bne.w fsub_normal # no; no underflow occurred
11738
11739 btst &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
11740 beq.w fsub_normal # no; no underflow occurred
11741
11742#
11743# ok, so now the result has a exponent equal to the smallest normalized
11744# exponent for the selected precision. also, the mantissa is equal to
11745# 0x8000000000000000 and this mantissa is the result of rounding non-zero
11746# g,r,s.
11747# now, we must determine whether the pre-rounded result was an underflow
11748# rounded "up" or a normalized number rounded "down".
11749# so, we do this be re-executing the add using RZ as the rounding mode and
11750# seeing if the new result is smaller or equal to the current result.
11751#
11752 fmovm.x FP_SCR1(%a6),&0x40 # load dst op into fp1
11753
11754 mov.l L_SCR3(%a6),%d1
11755 andi.b &0xc0,%d1 # keep rnd prec
11756 ori.b &rz_mode*0x10,%d1 # insert rnd mode
11757 fmov.l %d1,%fpcr # set FPCR
11758 fmov.l &0x0,%fpsr # clear FPSR
11759
11760 fsub.x FP_SCR0(%a6),%fp1 # execute subtract
11761
11762 fmov.l &0x0,%fpcr # clear FPCR
11763
11764 fabs.x %fp0 # compare absolute values
11765 fabs.x %fp1
11766 fcmp.x %fp0,%fp1 # is first result > second?
11767
11768 fbgt.w fsub_unfl # yes; it's an underflow
11769 bra.w fsub_normal # no; it's not an underflow
11770
11771##########################################################################
11772
11773#
11774# Sub: inputs are not both normalized; what are they?
11775#
11776fsub_not_norm:
11777 mov.w (tbl_fsub_op.b,%pc,%d1.w*2),%d1
11778 jmp (tbl_fsub_op.b,%pc,%d1.w*1)
11779
11780 swbeg &48
11781tbl_fsub_op:
11782 short fsub_norm - tbl_fsub_op # NORM - NORM
11783 short fsub_zero_src - tbl_fsub_op # NORM - ZERO
11784 short fsub_inf_src - tbl_fsub_op # NORM - INF
11785 short fsub_res_qnan - tbl_fsub_op # NORM - QNAN
11786 short fsub_norm - tbl_fsub_op # NORM - DENORM
11787 short fsub_res_snan - tbl_fsub_op # NORM - SNAN
11788 short tbl_fsub_op - tbl_fsub_op #
11789 short tbl_fsub_op - tbl_fsub_op #
11790
11791 short fsub_zero_dst - tbl_fsub_op # ZERO - NORM
11792 short fsub_zero_2 - tbl_fsub_op # ZERO - ZERO
11793 short fsub_inf_src - tbl_fsub_op # ZERO - INF
11794 short fsub_res_qnan - tbl_fsub_op # NORM - QNAN
11795 short fsub_zero_dst - tbl_fsub_op # ZERO - DENORM
11796 short fsub_res_snan - tbl_fsub_op # NORM - SNAN
11797 short tbl_fsub_op - tbl_fsub_op #
11798 short tbl_fsub_op - tbl_fsub_op #
11799
11800 short fsub_inf_dst - tbl_fsub_op # INF - NORM
11801 short fsub_inf_dst - tbl_fsub_op # INF - ZERO
11802 short fsub_inf_2 - tbl_fsub_op # INF - INF
11803 short fsub_res_qnan - tbl_fsub_op # NORM - QNAN
11804 short fsub_inf_dst - tbl_fsub_op # INF - DENORM
11805 short fsub_res_snan - tbl_fsub_op # NORM - SNAN
11806 short tbl_fsub_op - tbl_fsub_op #
11807 short tbl_fsub_op - tbl_fsub_op #
11808
11809 short fsub_res_qnan - tbl_fsub_op # QNAN - NORM
11810 short fsub_res_qnan - tbl_fsub_op # QNAN - ZERO
11811 short fsub_res_qnan - tbl_fsub_op # QNAN - INF
11812 short fsub_res_qnan - tbl_fsub_op # QNAN - QNAN
11813 short fsub_res_qnan - tbl_fsub_op # QNAN - DENORM
11814 short fsub_res_snan - tbl_fsub_op # QNAN - SNAN
11815 short tbl_fsub_op - tbl_fsub_op #
11816 short tbl_fsub_op - tbl_fsub_op #
11817
11818 short fsub_norm - tbl_fsub_op # DENORM - NORM
11819 short fsub_zero_src - tbl_fsub_op # DENORM - ZERO
11820 short fsub_inf_src - tbl_fsub_op # DENORM - INF
11821 short fsub_res_qnan - tbl_fsub_op # NORM - QNAN
11822 short fsub_norm - tbl_fsub_op # DENORM - DENORM
11823 short fsub_res_snan - tbl_fsub_op # NORM - SNAN
11824 short tbl_fsub_op - tbl_fsub_op #
11825 short tbl_fsub_op - tbl_fsub_op #
11826
11827 short fsub_res_snan - tbl_fsub_op # SNAN - NORM
11828 short fsub_res_snan - tbl_fsub_op # SNAN - ZERO
11829 short fsub_res_snan - tbl_fsub_op # SNAN - INF
11830 short fsub_res_snan - tbl_fsub_op # SNAN - QNAN
11831 short fsub_res_snan - tbl_fsub_op # SNAN - DENORM
11832 short fsub_res_snan - tbl_fsub_op # SNAN - SNAN
11833 short tbl_fsub_op - tbl_fsub_op #
11834 short tbl_fsub_op - tbl_fsub_op #
11835
11836fsub_res_qnan:
11837 bra.l res_qnan
11838fsub_res_snan:
11839 bra.l res_snan
11840
11841#
11842# both operands are ZEROes
11843#
11844fsub_zero_2:
11845 mov.b SRC_EX(%a0),%d0
11846 mov.b DST_EX(%a1),%d1
11847 eor.b %d1,%d0
11848 bpl.b fsub_zero_2_chk_rm
11849
11850# the signs are opposite, so, return a ZERO w/ the sign of the dst ZERO
11851 tst.b %d0 # is dst negative?
11852 bmi.b fsub_zero_2_rm # yes
11853 fmov.s &0x00000000,%fp0 # no; return +ZERO
11854 mov.b &z_bmask,FPSR_CC(%a6) # set Z
11855 rts
11856
11857#
11858# the ZEROes have the same signs:
11859# - therefore, we return +ZERO if the rounding mode is RN,RZ, or RP
11860# - -ZERO is returned in the case of RM.
11861#
11862fsub_zero_2_chk_rm:
11863 mov.b 3+L_SCR3(%a6),%d1
11864 andi.b &0x30,%d1 # extract rnd mode
11865 cmpi.b %d1,&rm_mode*0x10 # is rnd mode = RM?
11866 beq.b fsub_zero_2_rm # yes
11867 fmov.s &0x00000000,%fp0 # no; return +ZERO
11868 mov.b &z_bmask,FPSR_CC(%a6) # set Z
11869 rts
11870
11871fsub_zero_2_rm:
11872 fmov.s &0x80000000,%fp0 # return -ZERO
11873 mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/NEG
11874 rts
11875
11876#
11877# one operand is a ZERO and the other is a DENORM or a NORM.
11878# scale the DENORM or NORM and jump to the regular fsub routine.
11879#
11880fsub_zero_dst:
11881 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
11882 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
11883 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
11884 bsr.l scale_to_zero_src # scale the operand
11885 clr.w FP_SCR1_EX(%a6)
11886 clr.l FP_SCR1_HI(%a6)
11887 clr.l FP_SCR1_LO(%a6)
11888 bra.w fsub_zero_entry # go execute fsub
11889
11890fsub_zero_src:
11891 mov.w DST_EX(%a1),FP_SCR1_EX(%a6)
11892 mov.l DST_HI(%a1),FP_SCR1_HI(%a6)
11893 mov.l DST_LO(%a1),FP_SCR1_LO(%a6)
11894 bsr.l scale_to_zero_dst # scale the operand
11895 clr.w FP_SCR0_EX(%a6)
11896 clr.l FP_SCR0_HI(%a6)
11897 clr.l FP_SCR0_LO(%a6)
11898 bra.w fsub_zero_entry # go execute fsub
11899
11900#
11901# both operands are INFs. an OPERR will result if the INFs have the
11902# same signs. else,
11903#
11904fsub_inf_2:
11905 mov.b SRC_EX(%a0),%d0 # exclusive or the signs
11906 mov.b DST_EX(%a1),%d1
11907 eor.b %d1,%d0
11908 bpl.l res_operr # weed out (-INF)+(+INF)
11909
11910# ok, so it's not an OPERR. but we do have to remember to return
11911# the src INF since that's where the 881/882 gets the j-bit.
11912
11913fsub_inf_src:
11914 fmovm.x SRC(%a0),&0x80 # return src INF
11915 fneg.x %fp0 # invert sign
11916 fbge.w fsub_inf_done # sign is now positive
11917 mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
11918 rts
11919
11920fsub_inf_dst:
11921 fmovm.x DST(%a1),&0x80 # return dst INF
11922 tst.b DST_EX(%a1) # is INF negative?
11923 bpl.b fsub_inf_done # no
11924 mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG
11925 rts
11926
11927fsub_inf_done:
11928 mov.b &inf_bmask,FPSR_CC(%a6) # set INF
11929 rts
11930
11931#########################################################################
11932# XDEF **************************************************************** #
11933# fsqrt(): emulates the fsqrt instruction #
11934# fssqrt(): emulates the fssqrt instruction #
11935# fdsqrt(): emulates the fdsqrt instruction #
11936# #
11937# XREF **************************************************************** #
11938# scale_sqrt() - scale the source operand #
11939# unf_res() - return default underflow result #
11940# ovf_res() - return default overflow result #
11941# res_qnan_1op() - return QNAN result #
11942# res_snan_1op() - return SNAN result #
11943# #
11944# INPUT *************************************************************** #
11945# a0 = pointer to extended precision source operand #
11946# d0 rnd prec,mode #
11947# #
11948# OUTPUT ************************************************************** #
11949# fp0 = result #
11950# fp1 = EXOP (if exception occurred) #
11951# #
11952# ALGORITHM *********************************************************** #
11953# Handle NANs, infinities, and zeroes as special cases. Divide #
11954# norms/denorms into ext/sgl/dbl precision. #
11955# For norms/denorms, scale the exponents such that a sqrt #
11956# instruction won't cause an exception. Use the regular fsqrt to #
11957# compute a result. Check if the regular operands would have taken #
11958# an exception. If so, return the default overflow/underflow result #
11959# and return the EXOP if exceptions are enabled. Else, scale the #
11960# result operand to the proper exponent. #
11961# #
11962#########################################################################
11963
11964 global fssqrt
11965fssqrt:
11966 andi.b &0x30,%d0 # clear rnd prec
11967 ori.b &s_mode*0x10,%d0 # insert sgl precision
11968 bra.b fsqrt
11969
11970 global fdsqrt
11971fdsqrt:
11972 andi.b &0x30,%d0 # clear rnd prec
11973 ori.b &d_mode*0x10,%d0 # insert dbl precision
11974
11975 global fsqrt
11976fsqrt:
11977 mov.l %d0,L_SCR3(%a6) # store rnd info
11978 clr.w %d1
11979 mov.b STAG(%a6),%d1
11980 bne.w fsqrt_not_norm # optimize on non-norm input
11981
11982#
11983# SQUARE ROOT: norms and denorms ONLY!
11984#
11985fsqrt_norm:
11986 tst.b SRC_EX(%a0) # is operand negative?
11987 bmi.l res_operr # yes
11988
11989 andi.b &0xc0,%d0 # is precision extended?
11990 bne.b fsqrt_not_ext # no; go handle sgl or dbl
11991
11992 fmov.l L_SCR3(%a6),%fpcr # set FPCR
11993 fmov.l &0x0,%fpsr # clear FPSR
11994
11995 fsqrt.x (%a0),%fp0 # execute square root
11996
11997 fmov.l %fpsr,%d1
11998 or.l %d1,USER_FPSR(%a6) # set N,INEX
11999
12000 rts
12001
12002fsqrt_denorm:
12003 tst.b SRC_EX(%a0) # is operand negative?
12004 bmi.l res_operr # yes
12005
12006 andi.b &0xc0,%d0 # is precision extended?
12007 bne.b fsqrt_not_ext # no; go handle sgl or dbl
12008
12009 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
12010 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
12011 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
12012
12013 bsr.l scale_sqrt # calculate scale factor
12014
12015 bra.w fsqrt_sd_normal
12016
12017#
12018# operand is either single or double
12019#
12020fsqrt_not_ext:
12021 cmpi.b %d0,&s_mode*0x10 # separate sgl/dbl prec
12022 bne.w fsqrt_dbl
12023
12024#
12025# operand is to be rounded to single precision
12026#
12027fsqrt_sgl:
12028 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
12029 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
12030 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
12031
12032 bsr.l scale_sqrt # calculate scale factor
12033
12034 cmpi.l %d0,&0x3fff-0x3f81 # will move in underflow?
12035 beq.w fsqrt_sd_may_unfl
12036 bgt.w fsqrt_sd_unfl # yes; go handle underflow
12037 cmpi.l %d0,&0x3fff-0x407f # will move in overflow?
12038 beq.w fsqrt_sd_may_ovfl # maybe; go check
12039 blt.w fsqrt_sd_ovfl # yes; go handle overflow
12040
12041#
12042# operand will NOT overflow or underflow when moved in to the fp reg file
12043#
12044fsqrt_sd_normal:
12045 fmov.l &0x0,%fpsr # clear FPSR
12046 fmov.l L_SCR3(%a6),%fpcr # set FPCR
12047
12048 fsqrt.x FP_SCR0(%a6),%fp0 # perform absolute
12049
12050 fmov.l %fpsr,%d1 # save FPSR
12051 fmov.l &0x0,%fpcr # clear FPCR
12052
12053 or.l %d1,USER_FPSR(%a6) # save INEX2,N
12054
12055fsqrt_sd_normal_exit:
12056 mov.l %d2,-(%sp) # save d2
12057 fmovm.x &0x80,FP_SCR0(%a6) # store out result
12058 mov.w FP_SCR0_EX(%a6),%d1 # load sgn,exp
12059 mov.l %d1,%d2 # make a copy
12060 andi.l &0x7fff,%d1 # strip sign
12061 sub.l %d0,%d1 # add scale factor
12062 andi.w &0x8000,%d2 # keep old sign
12063 or.w %d1,%d2 # concat old sign,new exp
12064 mov.w %d2,FP_SCR0_EX(%a6) # insert new exponent
12065 mov.l (%sp)+,%d2 # restore d2
12066 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0
12067 rts
12068
12069#
12070# operand is to be rounded to double precision
12071#
12072fsqrt_dbl:
12073 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6)
12074 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6)
12075 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6)
12076
12077 bsr.l scale_sqrt # calculate scale factor
12078
12079 cmpi.l %d0,&0x3fff-0x3c01 # will move in underflow?
12080 beq.w fsqrt_sd_may_unfl
12081 bgt.b fsqrt_sd_unfl # yes; go handle underflow
12082 cmpi.l %d0,&0x3fff-0x43ff # will move in overflow?
12083 beq.w fsqrt_sd_may_ovfl # maybe; go check
12084 blt.w fsqrt_sd_ovfl # yes; go handle overflow
12085 bra.w fsqrt_sd_normal # no; ho handle normalized op
12086
12087# we're on the line here and the distinguising characteristic is whether
12088# the exponent is 3fff or 3ffe. if it's 3ffe, then it's a safe number
12089# elsewise fall through to underflow.
12090fsqrt_sd_may_unfl:
12091 btst &0x0,1+FP_SCR0_EX(%a6) # is exponent 0x3fff?
12092 bne.w fsqrt_sd_normal # yes, so no underflow
12093
12094#
12095# operand WILL underflow when moved in to the fp register file
12096#
12097fsqrt_sd_unfl:
12098 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit
12099
12100 fmov.l &rz_mode*0x10,%fpcr # set FPCR
12101 fmov.l &0x0,%fpsr # clear FPSR
12102
12103 fsqrt.x FP_SCR0(%a6),%fp0 # execute square root
12104
12105 fmov.l %fpsr,%d1 # save status
12106 fmov.l &0x0,%fpcr # clear FPCR
12107
12108 or.l %d1,USER_FPSR(%a6) # save INEX2,N
12109
12110# if underflow or inexact is enabled, go calculate EXOP first.
12111 mov.b FPCR_ENABLE(%a6),%d1
12112 andi.b &0x0b,%d1 # is UNFL or INEX enabled?
12113 bne.b fsqrt_sd_unfl_ena # yes
12114
12115fsqrt_sd_unfl_dis:
12116 fmovm.x &0x80,FP_SCR0(%a6) # store out result
12117
12118 lea FP_SCR0(%a6),%a0 # pass: result addr
12119 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode
12120 bsr.l unf_res # calculate default result
12121 or.b %d0,FPSR_CC(%a6) # set possible 'Z' ccode
12122 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0
12123 rts
12124
12125#
12126# operand will underflow AND underflow is enabled.
12127# therefore, we must return the result rounded to extended precision.
12128#
12129fsqrt_sd_unfl_ena:
12130 mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6)
12131 mov.l FP_SCR0_LO(%a6),FP_SCR1_LO(%a6)
12132 mov.w FP_SCR0_EX(%a6),%d1 # load current exponent
12133
12134 mov.l %d2,-(%sp) # save d2
12135 mov.l %d1,%d2 # make a copy
12136 andi.l &0x7fff,%d1 # strip sign
12137 andi.w &0x8000,%d2 # keep old sign
12138 sub.l %d0,%d1 # subtract scale factor
12139 addi.l &0x6000,%d1 # add new bias
12140 andi.w &0x7fff,%d1
12141 or.w %d2,%d1 # concat new sign,new exp
12142 mov.w %d1,FP_SCR1_EX(%a6) # insert new exp
12143 fmovm.x FP_SCR1(%a6),&0x40 # return EXOP in fp1
12144 mov.l (%sp)+,%d2 # restore d2
12145 bra.b fsqrt_sd_unfl_dis
12146
12147#
12148# operand WILL overflow.
12149#
12150fsqrt_sd_ovfl:
12151 fmov.l &0x0,%fpsr # clear FPSR
12152 fmov.l L_SCR3(%a6),%fpcr # set FPCR
12153
12154 fsqrt.x FP_SCR0(%a6),%fp0 # perform square root
12155
12156 fmov.l &0x0,%fpcr # clear FPCR
12157 fmov.l %fpsr,%d1 # save FPSR
12158
12159 or.l %d1,USER_FPSR(%a6) # save INEX2,N
12160
12161fsqrt_sd_ovfl_tst:
12162 or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex
12163
12164 mov.b FPCR_ENABLE(%a6),%d1
12165 andi.b &0x13,%d1 # is OVFL or INEX enabled?
12166 bne.b fsqrt_sd_ovfl_ena # yes
12167
12168#
12169# OVFL is not enabled; therefore, we must create the default result by
12170# calling ovf_res().
12171#
12172fsqrt_sd_ovfl_dis:
12173 btst &neg_bit,FPSR_CC(%a6) # is result negative?
12174 sne %d1 # set sign param accordingly
12175 mov.l L_SCR3(%a6),%d0 # pass: prec,mode
12176 bsr.l ovf_res # calculate default result
12177 or.b %d0,FPSR_CC(%a6) # set INF,N if applicable
12178 fmovm.x (%a0),&0x80 # return default result in fp0
12179 rts
12180
12181#
12182# OVFL is enabled.
12183# the INEX2 bit has already been updated by the round to the correct precision.
12184# now, round to extended(and don't alter the FPSR).
12185#
12186fsqrt_sd_ovfl_ena:
12187 mov.l %d2,-(%sp) # save d2
12188 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp}
12189 mov.l %d1,%d2 # make a copy
12190 andi.l &0x7fff,%d1 # strip sign
12191 andi.w &0x8000,%d2 # keep old sign
12192 sub.l %d0,%d1 # add scale factor
12193 subi.l &0x6000,%d1 # subtract bias
12194 andi.w &0x7fff,%d1
12195 or.w %d2,%d1 # concat sign,exp
12196 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent
12197 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1
12198 mov.l (%sp)+,%d2 # restore d2
12199 bra.b fsqrt_sd_ovfl_dis
12200
12201#
12202# the move in MAY underflow. so...
12203#
12204fsqrt_sd_may_ovfl:
12205 btst &0x0,1+FP_SCR0_EX(%a6) # is exponent 0x3fff?
12206 bne.w fsqrt_sd_ovfl # yes, so overflow
12207
12208 fmov.l &0x0,%fpsr # clear FPSR
12209 fmov.l L_SCR3(%a6),%fpcr # set FPCR
12210
12211 fsqrt.x FP_SCR0(%a6),%fp0 # perform absolute
12212
12213 fmov.l %fpsr,%d1 # save status
12214 fmov.l &0x0,%fpcr # clear FPCR
12215
12216 or.l %d1,USER_FPSR(%a6) # save INEX2,N
12217
12218 fmov.x %fp0,%fp1 # make a copy of result
12219 fcmp.b %fp1,&0x1 # is |result| >= 1.b?
12220 fbge.w fsqrt_sd_ovfl_tst # yes; overflow has occurred
12221
12222# no, it didn't overflow; we have correct result
12223 bra.w fsqrt_sd_normal_exit
12224
12225##########################################################################
12226
12227#
12228# input is not normalized; what is it?
12229#
12230fsqrt_not_norm:
12231 cmpi.b %d1,&DENORM # weed out DENORM
12232 beq.w fsqrt_denorm
12233 cmpi.b %d1,&ZERO # weed out ZERO
12234 beq.b fsqrt_zero
12235 cmpi.b %d1,&INF # weed out INF
12236 beq.b fsqrt_inf
12237 cmpi.b %d1,&SNAN # weed out SNAN
12238 beq.l res_snan_1op
12239 bra.l res_qnan_1op
12240
12241#
12242# fsqrt(+0) = +0
12243# fsqrt(-0) = -0
12244# fsqrt(+INF) = +INF
12245# fsqrt(-INF) = OPERR
12246#
12247fsqrt_zero:
12248 tst.b SRC_EX(%a0) # is ZERO positive or negative?
12249 bmi.b fsqrt_zero_m # negative
12250fsqrt_zero_p:
12251 fmov.s &0x00000000,%fp0 # return +ZERO
12252 mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit
12253 rts
12254fsqrt_zero_m:
12255 fmov.s &0x80000000,%fp0 # return -ZERO
12256 mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits
12257 rts
12258
12259fsqrt_inf:
12260 tst.b SRC_EX(%a0) # is INF positive or negative?
12261 bmi.l res_operr # negative
12262fsqrt_inf_p:
12263 fmovm.x SRC(%a0),&0x80 # return +INF in fp0
12264 mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit
12265 rts
12266
12267#########################################################################
12268# XDEF **************************************************************** #
12269# fetch_dreg(): fetch register according to index in d1 #
12270# #
12271# XREF **************************************************************** #
12272# None #
12273# #
12274# INPUT *************************************************************** #
12275# d1 = index of register to fetch from #
12276# #
12277# OUTPUT ************************************************************** #
12278# d0 = value of register fetched #
12279# #
12280# ALGORITHM *********************************************************** #
12281# According to the index value in d1 which can range from zero #
12282# to fifteen, load the corresponding register file value (where #
12283# address register indexes start at 8). D0/D1/A0/A1/A6/A7 are on the #
12284# stack. The rest should still be in their original places. #
12285# #
12286#########################################################################
12287
12288# this routine leaves d1 intact for subsequent store_dreg calls.
12289 global fetch_dreg
12290fetch_dreg:
12291 mov.w (tbl_fdreg.b,%pc,%d1.w*2),%d0
12292 jmp (tbl_fdreg.b,%pc,%d0.w*1)
12293
12294tbl_fdreg:
12295 short fdreg0 - tbl_fdreg
12296 short fdreg1 - tbl_fdreg
12297 short fdreg2 - tbl_fdreg
12298 short fdreg3 - tbl_fdreg
12299 short fdreg4 - tbl_fdreg
12300 short fdreg5 - tbl_fdreg
12301 short fdreg6 - tbl_fdreg
12302 short fdreg7 - tbl_fdreg
12303 short fdreg8 - tbl_fdreg
12304 short fdreg9 - tbl_fdreg
12305 short fdrega - tbl_fdreg
12306 short fdregb - tbl_fdreg
12307 short fdregc - tbl_fdreg
12308 short fdregd - tbl_fdreg
12309 short fdrege - tbl_fdreg
12310 short fdregf - tbl_fdreg
12311
12312fdreg0:
12313 mov.l EXC_DREGS+0x0(%a6),%d0
12314 rts
12315fdreg1:
12316 mov.l EXC_DREGS+0x4(%a6),%d0
12317 rts
12318fdreg2:
12319 mov.l %d2,%d0
12320 rts
12321fdreg3:
12322 mov.l %d3,%d0
12323 rts
12324fdreg4:
12325 mov.l %d4,%d0
12326 rts
12327fdreg5:
12328 mov.l %d5,%d0
12329 rts
12330fdreg6:
12331 mov.l %d6,%d0
12332 rts
12333fdreg7:
12334 mov.l %d7,%d0
12335 rts
12336fdreg8:
12337 mov.l EXC_DREGS+0x8(%a6),%d0
12338 rts
12339fdreg9:
12340 mov.l EXC_DREGS+0xc(%a6),%d0
12341 rts
12342fdrega:
12343 mov.l %a2,%d0
12344 rts
12345fdregb:
12346 mov.l %a3,%d0
12347 rts
12348fdregc:
12349 mov.l %a4,%d0
12350 rts
12351fdregd:
12352 mov.l %a5,%d0
12353 rts
12354fdrege:
12355 mov.l (%a6),%d0
12356 rts
12357fdregf:
12358 mov.l EXC_A7(%a6),%d0
12359 rts
12360
12361#########################################################################
12362# XDEF **************************************************************** #
12363# store_dreg_l(): store longword to data register specified by d1 #
12364# #
12365# XREF **************************************************************** #
12366# None #
12367# #
12368# INPUT *************************************************************** #
12369# d0 = longowrd value to store #
12370# d1 = index of register to fetch from #
12371# #
12372# OUTPUT ************************************************************** #
12373# (data register is updated) #
12374# #
12375# ALGORITHM *********************************************************** #
12376# According to the index value in d1, store the longword value #
12377# in d0 to the corresponding data register. D0/D1 are on the stack #
12378# while the rest are in their initial places. #
12379# #
12380#########################################################################
12381
12382 global store_dreg_l
12383store_dreg_l:
12384 mov.w (tbl_sdregl.b,%pc,%d1.w*2),%d1
12385 jmp (tbl_sdregl.b,%pc,%d1.w*1)
12386
12387tbl_sdregl:
12388 short sdregl0 - tbl_sdregl
12389 short sdregl1 - tbl_sdregl
12390 short sdregl2 - tbl_sdregl
12391 short sdregl3 - tbl_sdregl
12392 short sdregl4 - tbl_sdregl
12393 short sdregl5 - tbl_sdregl
12394 short sdregl6 - tbl_sdregl
12395 short sdregl7 - tbl_sdregl
12396
12397sdregl0:
12398 mov.l %d0,EXC_DREGS+0x0(%a6)
12399 rts
12400sdregl1:
12401 mov.l %d0,EXC_DREGS+0x4(%a6)
12402 rts
12403sdregl2:
12404 mov.l %d0,%d2
12405 rts
12406sdregl3:
12407 mov.l %d0,%d3
12408 rts
12409sdregl4:
12410 mov.l %d0,%d4
12411 rts
12412sdregl5:
12413 mov.l %d0,%d5
12414 rts
12415sdregl6:
12416 mov.l %d0,%d6
12417 rts
12418sdregl7:
12419 mov.l %d0,%d7
12420 rts
12421
12422#########################################################################
12423# XDEF **************************************************************** #
12424# store_dreg_w(): store word to data register specified by d1 #
12425# #
12426# XREF **************************************************************** #
12427# None #
12428# #
12429# INPUT *************************************************************** #
12430# d0 = word value to store #
12431# d1 = index of register to fetch from #
12432# #
12433# OUTPUT ************************************************************** #
12434# (data register is updated) #
12435# #
12436# ALGORITHM *********************************************************** #
12437# According to the index value in d1, store the word value #
12438# in d0 to the corresponding data register. D0/D1 are on the stack #
12439# while the rest are in their initial places. #
12440# #
12441#########################################################################
12442
12443 global store_dreg_w
12444store_dreg_w:
12445 mov.w (tbl_sdregw.b,%pc,%d1.w*2),%d1
12446 jmp (tbl_sdregw.b,%pc,%d1.w*1)
12447
12448tbl_sdregw:
12449 short sdregw0 - tbl_sdregw
12450 short sdregw1 - tbl_sdregw
12451 short sdregw2 - tbl_sdregw
12452 short sdregw3 - tbl_sdregw
12453 short sdregw4 - tbl_sdregw
12454 short sdregw5 - tbl_sdregw
12455 short sdregw6 - tbl_sdregw
12456 short sdregw7 - tbl_sdregw
12457
12458sdregw0:
12459 mov.w %d0,2+EXC_DREGS+0x0(%a6)
12460 rts
12461sdregw1:
12462 mov.w %d0,2+EXC_DREGS+0x4(%a6)
12463 rts
12464sdregw2:
12465 mov.w %d0,%d2
12466 rts
12467sdregw3:
12468 mov.w %d0,%d3
12469 rts
12470sdregw4:
12471 mov.w %d0,%d4
12472 rts
12473sdregw5:
12474 mov.w %d0,%d5
12475 rts
12476sdregw6:
12477 mov.w %d0,%d6
12478 rts
12479sdregw7:
12480 mov.w %d0,%d7
12481 rts
12482
12483#########################################################################
12484# XDEF **************************************************************** #
12485# store_dreg_b(): store byte to data register specified by d1 #
12486# #
12487# XREF **************************************************************** #
12488# None #
12489# #
12490# INPUT *************************************************************** #
12491# d0 = byte value to store #
12492# d1 = index of register to fetch from #
12493# #
12494# OUTPUT ************************************************************** #
12495# (data register is updated) #
12496# #
12497# ALGORITHM *********************************************************** #
12498# According to the index value in d1, store the byte value #
12499# in d0 to the corresponding data register. D0/D1 are on the stack #
12500# while the rest are in their initial places. #
12501# #
12502#########################################################################
12503
12504 global store_dreg_b
12505store_dreg_b:
12506 mov.w (tbl_sdregb.b,%pc,%d1.w*2),%d1
12507 jmp (tbl_sdregb.b,%pc,%d1.w*1)
12508
12509tbl_sdregb:
12510 short sdregb0 - tbl_sdregb
12511 short sdregb1 - tbl_sdregb
12512 short sdregb2 - tbl_sdregb
12513 short sdregb3 - tbl_sdregb
12514 short sdregb4 - tbl_sdregb
12515 short sdregb5 - tbl_sdregb
12516 short sdregb6 - tbl_sdregb
12517 short sdregb7 - tbl_sdregb
12518
12519sdregb0:
12520 mov.b %d0,3+EXC_DREGS+0x0(%a6)
12521 rts
12522sdregb1:
12523 mov.b %d0,3+EXC_DREGS+0x4(%a6)
12524 rts
12525sdregb2:
12526 mov.b %d0,%d2
12527 rts
12528sdregb3:
12529 mov.b %d0,%d3
12530 rts
12531sdregb4:
12532 mov.b %d0,%d4
12533 rts
12534sdregb5:
12535 mov.b %d0,%d5
12536 rts
12537sdregb6:
12538 mov.b %d0,%d6
12539 rts
12540sdregb7:
12541 mov.b %d0,%d7
12542 rts
12543
12544#########################################################################
12545# XDEF **************************************************************** #
12546# inc_areg(): increment an address register by the value in d0 #
12547# #
12548# XREF **************************************************************** #
12549# None #
12550# #
12551# INPUT *************************************************************** #
12552# d0 = amount to increment by #
12553# d1 = index of address register to increment #
12554# #
12555# OUTPUT ************************************************************** #
12556# (address register is updated) #
12557# #
12558# ALGORITHM *********************************************************** #
12559# Typically used for an instruction w/ a post-increment <ea>, #
12560# this routine adds the increment value in d0 to the address register #
12561# specified by d1. A0/A1/A6/A7 reside on the stack. The rest reside #
12562# in their original places. #
12563# For a7, if the increment amount is one, then we have to #
12564# increment by two. For any a7 update, set the mia7_flag so that if #
12565# an access error exception occurs later in emulation, this address #
12566# register update can be undone. #
12567# #
12568#########################################################################
12569
12570 global inc_areg
12571inc_areg:
12572 mov.w (tbl_iareg.b,%pc,%d1.w*2),%d1
12573 jmp (tbl_iareg.b,%pc,%d1.w*1)
12574
12575tbl_iareg:
12576 short iareg0 - tbl_iareg
12577 short iareg1 - tbl_iareg
12578 short iareg2 - tbl_iareg
12579 short iareg3 - tbl_iareg
12580 short iareg4 - tbl_iareg
12581 short iareg5 - tbl_iareg
12582 short iareg6 - tbl_iareg
12583 short iareg7 - tbl_iareg
12584
12585iareg0: add.l %d0,EXC_DREGS+0x8(%a6)
12586 rts
12587iareg1: add.l %d0,EXC_DREGS+0xc(%a6)
12588 rts
12589iareg2: add.l %d0,%a2
12590 rts
12591iareg3: add.l %d0,%a3
12592 rts
12593iareg4: add.l %d0,%a4
12594 rts
12595iareg5: add.l %d0,%a5
12596 rts
12597iareg6: add.l %d0,(%a6)
12598 rts
12599iareg7: mov.b &mia7_flg,SPCOND_FLG(%a6)
12600 cmpi.b %d0,&0x1
12601 beq.b iareg7b
12602 add.l %d0,EXC_A7(%a6)
12603 rts
12604iareg7b:
12605 addq.l &0x2,EXC_A7(%a6)
12606 rts
12607
12608#########################################################################
12609# XDEF **************************************************************** #
12610# dec_areg(): decrement an address register by the value in d0 #
12611# #
12612# XREF **************************************************************** #
12613# None #
12614# #
12615# INPUT *************************************************************** #
12616# d0 = amount to decrement by #
12617# d1 = index of address register to decrement #
12618# #
12619# OUTPUT ************************************************************** #
12620# (address register is updated) #
12621# #
12622# ALGORITHM *********************************************************** #
12623# Typically used for an instruction w/ a pre-decrement <ea>, #
12624# this routine adds the decrement value in d0 to the address register #
12625# specified by d1. A0/A1/A6/A7 reside on the stack. The rest reside #
12626# in their original places. #
12627# For a7, if the decrement amount is one, then we have to #
12628# decrement by two. For any a7 update, set the mda7_flag so that if #
12629# an access error exception occurs later in emulation, this address #
12630# register update can be undone. #
12631# #
12632#########################################################################
12633
12634 global dec_areg
12635dec_areg:
12636 mov.w (tbl_dareg.b,%pc,%d1.w*2),%d1
12637 jmp (tbl_dareg.b,%pc,%d1.w*1)
12638
12639tbl_dareg:
12640 short dareg0 - tbl_dareg
12641 short dareg1 - tbl_dareg
12642 short dareg2 - tbl_dareg
12643 short dareg3 - tbl_dareg
12644 short dareg4 - tbl_dareg
12645 short dareg5 - tbl_dareg
12646 short dareg6 - tbl_dareg
12647 short dareg7 - tbl_dareg
12648
12649dareg0: sub.l %d0,EXC_DREGS+0x8(%a6)
12650 rts
12651dareg1: sub.l %d0,EXC_DREGS+0xc(%a6)
12652 rts
12653dareg2: sub.l %d0,%a2
12654 rts
12655dareg3: sub.l %d0,%a3
12656 rts
12657dareg4: sub.l %d0,%a4
12658 rts
12659dareg5: sub.l %d0,%a5
12660 rts
12661dareg6: sub.l %d0,(%a6)
12662 rts
12663dareg7: mov.b &mda7_flg,SPCOND_FLG(%a6)
12664 cmpi.b %d0,&0x1
12665 beq.b dareg7b
12666 sub.l %d0,EXC_A7(%a6)
12667 rts
12668dareg7b:
12669 subq.l &0x2,EXC_A7(%a6)
12670 rts
12671
12672##############################################################################
12673
12674#########################################################################
12675# XDEF **************************************************************** #
12676# load_fpn1(): load FP register value into FP_SRC(a6). #
12677# #
12678# XREF **************************************************************** #
12679# None #
12680# #
12681# INPUT *************************************************************** #
12682# d0 = index of FP register to load #
12683# #
12684# OUTPUT ************************************************************** #
12685# FP_SRC(a6) = value loaded from FP register file #
12686# #
12687# ALGORITHM *********************************************************** #
12688# Using the index in d0, load FP_SRC(a6) with a number from the #
12689# FP register file. #
12690# #
12691#########################################################################
12692
12693 global load_fpn1
12694load_fpn1:
12695 mov.w (tbl_load_fpn1.b,%pc,%d0.w*2), %d0
12696 jmp (tbl_load_fpn1.b,%pc,%d0.w*1)
12697
12698tbl_load_fpn1:
12699 short load_fpn1_0 - tbl_load_fpn1
12700 short load_fpn1_1 - tbl_load_fpn1
12701 short load_fpn1_2 - tbl_load_fpn1
12702 short load_fpn1_3 - tbl_load_fpn1
12703 short load_fpn1_4 - tbl_load_fpn1
12704 short load_fpn1_5 - tbl_load_fpn1
12705 short load_fpn1_6 - tbl_load_fpn1
12706 short load_fpn1_7 - tbl_load_fpn1
12707
12708load_fpn1_0:
12709 mov.l 0+EXC_FP0(%a6), 0+FP_SRC(%a6)
12710 mov.l 4+EXC_FP0(%a6), 4+FP_SRC(%a6)
12711 mov.l 8+EXC_FP0(%a6), 8+FP_SRC(%a6)
12712 lea FP_SRC(%a6), %a0
12713 rts
12714load_fpn1_1:
12715 mov.l 0+EXC_FP1(%a6), 0+FP_SRC(%a6)
12716 mov.l 4+EXC_FP1(%a6), 4+FP_SRC(%a6)
12717 mov.l 8+EXC_FP1(%a6), 8+FP_SRC(%a6)
12718 lea FP_SRC(%a6), %a0
12719 rts
12720load_fpn1_2:
12721 fmovm.x &0x20, FP_SRC(%a6)
12722 lea FP_SRC(%a6), %a0
12723 rts
12724load_fpn1_3:
12725 fmovm.x &0x10, FP_SRC(%a6)
12726 lea FP_SRC(%a6), %a0
12727 rts
12728load_fpn1_4:
12729 fmovm.x &0x08, FP_SRC(%a6)
12730 lea FP_SRC(%a6), %a0
12731 rts
12732load_fpn1_5:
12733 fmovm.x &0x04, FP_SRC(%a6)
12734 lea FP_SRC(%a6), %a0
12735 rts
12736load_fpn1_6:
12737 fmovm.x &0x02, FP_SRC(%a6)
12738 lea FP_SRC(%a6), %a0
12739 rts
12740load_fpn1_7:
12741 fmovm.x &0x01, FP_SRC(%a6)
12742 lea FP_SRC(%a6), %a0
12743 rts
12744
12745#############################################################################
12746
12747#########################################################################
12748# XDEF **************************************************************** #
12749# load_fpn2(): load FP register value into FP_DST(a6). #
12750# #
12751# XREF **************************************************************** #
12752# None #
12753# #
12754# INPUT *************************************************************** #
12755# d0 = index of FP register to load #
12756# #
12757# OUTPUT ************************************************************** #
12758# FP_DST(a6) = value loaded from FP register file #
12759# #
12760# ALGORITHM *********************************************************** #
12761# Using the index in d0, load FP_DST(a6) with a number from the #
12762# FP register file. #
12763# #
12764#########################################################################
12765
12766 global load_fpn2
12767load_fpn2:
12768 mov.w (tbl_load_fpn2.b,%pc,%d0.w*2), %d0
12769 jmp (tbl_load_fpn2.b,%pc,%d0.w*1)
12770
12771tbl_load_fpn2:
12772 short load_fpn2_0 - tbl_load_fpn2
12773 short load_fpn2_1 - tbl_load_fpn2
12774 short load_fpn2_2 - tbl_load_fpn2
12775 short load_fpn2_3 - tbl_load_fpn2
12776 short load_fpn2_4 - tbl_load_fpn2
12777 short load_fpn2_5 - tbl_load_fpn2
12778 short load_fpn2_6 - tbl_load_fpn2
12779 short load_fpn2_7 - tbl_load_fpn2
12780
12781load_fpn2_0:
12782 mov.l 0+EXC_FP0(%a6), 0+FP_DST(%a6)
12783 mov.l 4+EXC_FP0(%a6), 4+FP_DST(%a6)
12784 mov.l 8+EXC_FP0(%a6), 8+FP_DST(%a6)
12785 lea FP_DST(%a6), %a0
12786 rts
12787load_fpn2_1:
12788 mov.l 0+EXC_FP1(%a6), 0+FP_DST(%a6)
12789 mov.l 4+EXC_FP1(%a6), 4+FP_DST(%a6)
12790 mov.l 8+EXC_FP1(%a6), 8+FP_DST(%a6)
12791 lea FP_DST(%a6), %a0
12792 rts
12793load_fpn2_2:
12794 fmovm.x &0x20, FP_DST(%a6)
12795 lea FP_DST(%a6), %a0
12796 rts
12797load_fpn2_3:
12798 fmovm.x &0x10, FP_DST(%a6)
12799 lea FP_DST(%a6), %a0
12800 rts
12801load_fpn2_4:
12802 fmovm.x &0x08, FP_DST(%a6)
12803 lea FP_DST(%a6), %a0
12804 rts
12805load_fpn2_5:
12806 fmovm.x &0x04, FP_DST(%a6)
12807 lea FP_DST(%a6), %a0
12808 rts
12809load_fpn2_6:
12810 fmovm.x &0x02, FP_DST(%a6)
12811 lea FP_DST(%a6), %a0
12812 rts
12813load_fpn2_7:
12814 fmovm.x &0x01, FP_DST(%a6)
12815 lea FP_DST(%a6), %a0
12816 rts
12817
12818#############################################################################
12819
12820#########################################################################
12821# XDEF **************************************************************** #
12822# store_fpreg(): store an fp value to the fpreg designated d0. #
12823# #
12824# XREF **************************************************************** #
12825# None #
12826# #
12827# INPUT *************************************************************** #
12828# fp0 = extended precision value to store #
12829# d0 = index of floating-point register #
12830# #
12831# OUTPUT ************************************************************** #
12832# None #
12833# #
12834# ALGORITHM *********************************************************** #
12835# Store the value in fp0 to the FP register designated by the #
12836# value in d0. The FP number can be DENORM or SNAN so we have to be #
12837# careful that we don't take an exception here. #
12838# #
12839#########################################################################
12840
12841 global store_fpreg
12842store_fpreg:
12843 mov.w (tbl_store_fpreg.b,%pc,%d0.w*2), %d0
12844 jmp (tbl_store_fpreg.b,%pc,%d0.w*1)
12845
12846tbl_store_fpreg:
12847 short store_fpreg_0 - tbl_store_fpreg
12848 short store_fpreg_1 - tbl_store_fpreg
12849 short store_fpreg_2 - tbl_store_fpreg
12850 short store_fpreg_3 - tbl_store_fpreg
12851 short store_fpreg_4 - tbl_store_fpreg
12852 short store_fpreg_5 - tbl_store_fpreg
12853 short store_fpreg_6 - tbl_store_fpreg
12854 short store_fpreg_7 - tbl_store_fpreg
12855
12856store_fpreg_0:
12857 fmovm.x &0x80, EXC_FP0(%a6)
12858 rts
12859store_fpreg_1:
12860 fmovm.x &0x80, EXC_FP1(%a6)
12861 rts
12862store_fpreg_2:
12863 fmovm.x &0x01, -(%sp)
12864 fmovm.x (%sp)+, &0x20
12865 rts
12866store_fpreg_3:
12867 fmovm.x &0x01, -(%sp)
12868 fmovm.x (%sp)+, &0x10
12869 rts
12870store_fpreg_4:
12871 fmovm.x &0x01, -(%sp)
12872 fmovm.x (%sp)+, &0x08
12873 rts
12874store_fpreg_5:
12875 fmovm.x &0x01, -(%sp)
12876 fmovm.x (%sp)+, &0x04
12877 rts
12878store_fpreg_6:
12879 fmovm.x &0x01, -(%sp)
12880 fmovm.x (%sp)+, &0x02
12881 rts
12882store_fpreg_7:
12883 fmovm.x &0x01, -(%sp)
12884 fmovm.x (%sp)+, &0x01
12885 rts
12886
12887#########################################################################
12888# XDEF **************************************************************** #
12889# get_packed(): fetch a packed operand from memory and then #
12890# convert it to a floating-point binary number. #
12891# #
12892# XREF **************************************************************** #
12893# _dcalc_ea() - calculate the correct <ea> #
12894# _mem_read() - fetch the packed operand from memory #
12895# facc_in_x() - the fetch failed so jump to special exit code #
12896# decbin() - convert packed to binary extended precision #
12897# #
12898# INPUT *************************************************************** #
12899# None #
12900# #
12901# OUTPUT ************************************************************** #
12902# If no failure on _mem_read(): #
12903# FP_SRC(a6) = packed operand now as a binary FP number #
12904# #
12905# ALGORITHM *********************************************************** #
12906# Get the correct <ea> whihc is the value on the exception stack #
12907# frame w/ maybe a correction factor if the <ea> is -(an) or (an)+. #
12908# Then, fetch the operand from memory. If the fetch fails, exit #
12909# through facc_in_x(). #
12910# If the packed operand is a ZERO,NAN, or INF, convert it to #
12911# its binary representation here. Else, call decbin() which will #
12912# convert the packed value to an extended precision binary value. #
12913# #
12914#########################################################################
12915
12916# the stacked <ea> for packed is correct except for -(An).
12917# the base reg must be updated for both -(An) and (An)+.
12918 global get_packed
12919get_packed:
12920 mov.l &0xc,%d0 # packed is 12 bytes
12921 bsr.l _dcalc_ea # fetch <ea>; correct An
12922
12923 lea FP_SRC(%a6),%a1 # pass: ptr to super dst
12924 mov.l &0xc,%d0 # pass: 12 bytes
12925 bsr.l _dmem_read # read packed operand
12926
12927 tst.l %d1 # did dfetch fail?
12928 bne.l facc_in_x # yes
12929
12930# The packed operand is an INF or a NAN if the exponent field is all ones.
12931 bfextu FP_SRC(%a6){&1:&15},%d0 # get exp
12932 cmpi.w %d0,&0x7fff # INF or NAN?
12933 bne.b gp_try_zero # no
12934 rts # operand is an INF or NAN
12935
12936# The packed operand is a zero if the mantissa is all zero, else it's
12937# a normal packed op.
12938gp_try_zero:
12939 mov.b 3+FP_SRC(%a6),%d0 # get byte 4
12940 andi.b &0x0f,%d0 # clear all but last nybble
12941 bne.b gp_not_spec # not a zero
12942 tst.l FP_SRC_HI(%a6) # is lw 2 zero?
12943 bne.b gp_not_spec # not a zero
12944 tst.l FP_SRC_LO(%a6) # is lw 3 zero?
12945 bne.b gp_not_spec # not a zero
12946 rts # operand is a ZERO
12947gp_not_spec:
12948 lea FP_SRC(%a6),%a0 # pass: ptr to packed op
12949 bsr.l decbin # convert to extended
12950 fmovm.x &0x80,FP_SRC(%a6) # make this the srcop
12951 rts
12952
12953#########################################################################
12954# decbin(): Converts normalized packed bcd value pointed to by register #
12955# a0 to extended-precision value in fp0. #
12956# #
12957# INPUT *************************************************************** #
12958# a0 = pointer to normalized packed bcd value #
12959# #
12960# OUTPUT ************************************************************** #
12961# fp0 = exact fp representation of the packed bcd value. #
12962# #
12963# ALGORITHM *********************************************************** #
12964# Expected is a normal bcd (i.e. non-exceptional; all inf, zero, #
12965# and NaN operands are dispatched without entering this routine) #
12966# value in 68881/882 format at location (a0). #
12967# #
12968# A1. Convert the bcd exponent to binary by successive adds and #
12969# muls. Set the sign according to SE. Subtract 16 to compensate #
12970# for the mantissa which is to be interpreted as 17 integer #
12971# digits, rather than 1 integer and 16 fraction digits. #
12972# Note: this operation can never overflow. #
12973# #
12974# A2. Convert the bcd mantissa to binary by successive #
12975# adds and muls in FP0. Set the sign according to SM. #
12976# The mantissa digits will be converted with the decimal point #
12977# assumed following the least-significant digit. #
12978# Note: this operation can never overflow. #
12979# #
12980# A3. Count the number of leading/trailing zeros in the #
12981# bcd string. If SE is positive, count the leading zeros; #
12982# if negative, count the trailing zeros. Set the adjusted #
12983# exponent equal to the exponent from A1 and the zero count #
12984# added if SM = 1 and subtracted if SM = 0. Scale the #
12985# mantissa the equivalent of forcing in the bcd value: #
12986# #
12987# SM = 0 a non-zero digit in the integer position #
12988# SM = 1 a non-zero digit in Mant0, lsd of the fraction #
12989# #
12990# this will insure that any value, regardless of its #
12991# representation (ex. 0.1E2, 1E1, 10E0, 100E-1), is converted #
12992# consistently. #
12993# #
12994# A4. Calculate the factor 10^exp in FP1 using a table of #
12995# 10^(2^n) values. To reduce the error in forming factors #
12996# greater than 10^27, a directed rounding scheme is used with #
12997# tables rounded to RN, RM, and RP, according to the table #
12998# in the comments of the pwrten section. #
12999# #
13000# A5. Form the final binary number by scaling the mantissa by #
13001# the exponent factor. This is done by multiplying the #
13002# mantissa in FP0 by the factor in FP1 if the adjusted #
13003# exponent sign is positive, and dividing FP0 by FP1 if #
13004# it is negative. #
13005# #
13006# Clean up and return. Check if the final mul or div was inexact. #
13007# If so, set INEX1 in USER_FPSR. #
13008# #
13009#########################################################################
13010
13011#
13012# PTENRN, PTENRM, and PTENRP are arrays of powers of 10 rounded
13013# to nearest, minus, and plus, respectively. The tables include
13014# 10**{1,2,4,8,16,32,64,128,256,512,1024,2048,4096}. No rounding
13015# is required until the power is greater than 27, however, all
13016# tables include the first 5 for ease of indexing.
13017#
13018RTABLE:
13019 byte 0,0,0,0
13020 byte 2,3,2,3
13021 byte 2,3,3,2
13022 byte 3,2,2,3
13023
13024 set FNIBS,7
13025 set FSTRT,0
13026
13027 set ESTRT,4
13028 set EDIGITS,2
13029
13030 global decbin
13031decbin:
13032 mov.l 0x0(%a0),FP_SCR0_EX(%a6) # make a copy of input
13033 mov.l 0x4(%a0),FP_SCR0_HI(%a6) # so we don't alter it
13034 mov.l 0x8(%a0),FP_SCR0_LO(%a6)
13035
13036 lea FP_SCR0(%a6),%a0
13037
13038 movm.l &0x3c00,-(%sp) # save d2-d5
13039 fmovm.x &0x1,-(%sp) # save fp1
13040#
13041# Calculate exponent:
13042# 1. Copy bcd value in memory for use as a working copy.
13043# 2. Calculate absolute value of exponent in d1 by mul and add.
13044# 3. Correct for exponent sign.
13045# 4. Subtract 16 to compensate for interpreting the mant as all integer digits.
13046# (i.e., all digits assumed left of the decimal point.)
13047#
13048# Register usage:
13049#
13050# calc_e:
13051# (*) d0: temp digit storage
13052# (*) d1: accumulator for binary exponent
13053# (*) d2: digit count
13054# (*) d3: offset pointer
13055# ( ) d4: first word of bcd
13056# ( ) a0: pointer to working bcd value
13057# ( ) a6: pointer to original bcd value
13058# (*) FP_SCR1: working copy of original bcd value
13059# (*) L_SCR1: copy of original exponent word
13060#
13061calc_e:
13062 mov.l &EDIGITS,%d2 # # of nibbles (digits) in fraction part
13063 mov.l &ESTRT,%d3 # counter to pick up digits
13064 mov.l (%a0),%d4 # get first word of bcd
13065 clr.l %d1 # zero d1 for accumulator
13066e_gd:
13067 mulu.l &0xa,%d1 # mul partial product by one digit place
13068 bfextu %d4{%d3:&4},%d0 # get the digit and zero extend into d0
13069 add.l %d0,%d1 # d1 = d1 + d0
13070 addq.b &4,%d3 # advance d3 to the next digit
13071 dbf.w %d2,e_gd # if we have used all 3 digits, exit loop
13072 btst &30,%d4 # get SE
13073 beq.b e_pos # don't negate if pos
13074 neg.l %d1 # negate before subtracting
13075e_pos:
13076 sub.l &16,%d1 # sub to compensate for shift of mant
13077 bge.b e_save # if still pos, do not neg
13078 neg.l %d1 # now negative, make pos and set SE
13079 or.l &0x40000000,%d4 # set SE in d4,
13080 or.l &0x40000000,(%a0) # and in working bcd
13081e_save:
13082 mov.l %d1,-(%sp) # save exp on stack
13083#
13084#
13085# Calculate mantissa:
13086# 1. Calculate absolute value of mantissa in fp0 by mul and add.
13087# 2. Correct for mantissa sign.
13088# (i.e., all digits assumed left of the decimal point.)
13089#
13090# Register usage:
13091#
13092# calc_m:
13093# (*) d0: temp digit storage
13094# (*) d1: lword counter
13095# (*) d2: digit count
13096# (*) d3: offset pointer
13097# ( ) d4: words 2 and 3 of bcd
13098# ( ) a0: pointer to working bcd value
13099# ( ) a6: pointer to original bcd value
13100# (*) fp0: mantissa accumulator
13101# ( ) FP_SCR1: working copy of original bcd value
13102# ( ) L_SCR1: copy of original exponent word
13103#
13104calc_m:
13105 mov.l &1,%d1 # word counter, init to 1
13106 fmov.s &0x00000000,%fp0 # accumulator
13107#
13108#
13109# Since the packed number has a long word between the first & second parts,
13110# get the integer digit then skip down & get the rest of the
13111# mantissa. We will unroll the loop once.
13112#
13113 bfextu (%a0){&28:&4},%d0 # integer part is ls digit in long word
13114 fadd.b %d0,%fp0 # add digit to sum in fp0
13115#
13116#
13117# Get the rest of the mantissa.
13118#
13119loadlw:
13120 mov.l (%a0,%d1.L*4),%d4 # load mantissa lonqword into d4
13121 mov.l &FSTRT,%d3 # counter to pick up digits
13122 mov.l &FNIBS,%d2 # reset number of digits per a0 ptr
13123md2b:
13124 fmul.s &0x41200000,%fp0 # fp0 = fp0 * 10
13125 bfextu %d4{%d3:&4},%d0 # get the digit and zero extend
13126 fadd.b %d0,%fp0 # fp0 = fp0 + digit
13127#
13128#
13129# If all the digits (8) in that long word have been converted (d2=0),
13130# then inc d1 (=2) to point to the next long word and reset d3 to 0
13131# to initialize the digit offset, and set d2 to 7 for the digit count;
13132# else continue with this long word.
13133#
13134 addq.b &4,%d3 # advance d3 to the next digit
13135 dbf.w %d2,md2b # check for last digit in this lw
13136nextlw:
13137 addq.l &1,%d1 # inc lw pointer in mantissa
13138 cmp.l %d1,&2 # test for last lw
13139 ble.b loadlw # if not, get last one
13140#
13141# Check the sign of the mant and make the value in fp0 the same sign.
13142#
13143m_sign:
13144 btst &31,(%a0) # test sign of the mantissa
13145 beq.b ap_st_z # if clear, go to append/strip zeros
13146 fneg.x %fp0 # if set, negate fp0
13147#
13148# Append/strip zeros:
13149#
13150# For adjusted exponents which have an absolute value greater than 27*,
13151# this routine calculates the amount needed to normalize the mantissa
13152# for the adjusted exponent. That number is subtracted from the exp
13153# if the exp was positive, and added if it was negative. The purpose
13154# of this is to reduce the value of the exponent and the possibility
13155# of error in calculation of pwrten.
13156#
13157# 1. Branch on the sign of the adjusted exponent.
13158# 2p.(positive exp)
13159# 2. Check M16 and the digits in lwords 2 and 3 in decending order.
13160# 3. Add one for each zero encountered until a non-zero digit.
13161# 4. Subtract the count from the exp.
13162# 5. Check if the exp has crossed zero in #3 above; make the exp abs
13163# and set SE.
13164# 6. Multiply the mantissa by 10**count.
13165# 2n.(negative exp)
13166# 2. Check the digits in lwords 3 and 2 in decending order.
13167# 3. Add one for each zero encountered until a non-zero digit.
13168# 4. Add the count to the exp.
13169# 5. Check if the exp has crossed zero in #3 above; clear SE.
13170# 6. Divide the mantissa by 10**count.
13171#
13172# *Why 27? If the adjusted exponent is within -28 < expA < 28, than
13173# any adjustment due to append/strip zeros will drive the resultane
13174# exponent towards zero. Since all pwrten constants with a power
13175# of 27 or less are exact, there is no need to use this routine to
13176# attempt to lessen the resultant exponent.
13177#
13178# Register usage:
13179#
13180# ap_st_z:
13181# (*) d0: temp digit storage
13182# (*) d1: zero count
13183# (*) d2: digit count
13184# (*) d3: offset pointer
13185# ( ) d4: first word of bcd
13186# (*) d5: lword counter
13187# ( ) a0: pointer to working bcd value
13188# ( ) FP_SCR1: working copy of original bcd value
13189# ( ) L_SCR1: copy of original exponent word
13190#
13191#
13192# First check the absolute value of the exponent to see if this
13193# routine is necessary. If so, then check the sign of the exponent
13194# and do append (+) or strip (-) zeros accordingly.
13195# This section handles a positive adjusted exponent.
13196#
13197ap_st_z:
13198 mov.l (%sp),%d1 # load expA for range test
13199 cmp.l %d1,&27 # test is with 27
13200 ble.w pwrten # if abs(expA) <28, skip ap/st zeros
13201 btst &30,(%a0) # check sign of exp
13202 bne.b ap_st_n # if neg, go to neg side
13203 clr.l %d1 # zero count reg
13204 mov.l (%a0),%d4 # load lword 1 to d4
13205 bfextu %d4{&28:&4},%d0 # get M16 in d0
13206 bne.b ap_p_fx # if M16 is non-zero, go fix exp
13207 addq.l &1,%d1 # inc zero count
13208 mov.l &1,%d5 # init lword counter
13209 mov.l (%a0,%d5.L*4),%d4 # get lword 2 to d4
13210 bne.b ap_p_cl # if lw 2 is zero, skip it
13211 addq.l &8,%d1 # and inc count by 8
13212 addq.l &1,%d5 # inc lword counter
13213 mov.l (%a0,%d5.L*4),%d4 # get lword 3 to d4
13214ap_p_cl:
13215 clr.l %d3 # init offset reg
13216 mov.l &7,%d2 # init digit counter
13217ap_p_gd:
13218 bfextu %d4{%d3:&4},%d0 # get digit
13219 bne.b ap_p_fx # if non-zero, go to fix exp
13220 addq.l &4,%d3 # point to next digit
13221 addq.l &1,%d1 # inc digit counter
13222 dbf.w %d2,ap_p_gd # get next digit
13223ap_p_fx:
13224 mov.l %d1,%d0 # copy counter to d2
13225 mov.l (%sp),%d1 # get adjusted exp from memory
13226 sub.l %d0,%d1 # subtract count from exp
13227 bge.b ap_p_fm # if still pos, go to pwrten
13228 neg.l %d1 # now its neg; get abs
13229 mov.l (%a0),%d4 # load lword 1 to d4
13230 or.l &0x40000000,%d4 # and set SE in d4
13231 or.l &0x40000000,(%a0) # and in memory
13232#
13233# Calculate the mantissa multiplier to compensate for the striping of
13234# zeros from the mantissa.
13235#
13236ap_p_fm:
13237 lea.l PTENRN(%pc),%a1 # get address of power-of-ten table
13238 clr.l %d3 # init table index
13239 fmov.s &0x3f800000,%fp1 # init fp1 to 1
13240 mov.l &3,%d2 # init d2 to count bits in counter
13241ap_p_el:
13242 asr.l &1,%d0 # shift lsb into carry
13243 bcc.b ap_p_en # if 1, mul fp1 by pwrten factor
13244 fmul.x (%a1,%d3),%fp1 # mul by 10**(d3_bit_no)
13245ap_p_en:
13246 add.l &12,%d3 # inc d3 to next rtable entry
13247 tst.l %d0 # check if d0 is zero
13248 bne.b ap_p_el # if not, get next bit
13249 fmul.x %fp1,%fp0 # mul mantissa by 10**(no_bits_shifted)
13250 bra.b pwrten # go calc pwrten
13251#
13252# This section handles a negative adjusted exponent.
13253#
13254ap_st_n:
13255 clr.l %d1 # clr counter
13256 mov.l &2,%d5 # set up d5 to point to lword 3
13257 mov.l (%a0,%d5.L*4),%d4 # get lword 3
13258 bne.b ap_n_cl # if not zero, check digits
13259 sub.l &1,%d5 # dec d5 to point to lword 2
13260 addq.l &8,%d1 # inc counter by 8
13261 mov.l (%a0,%d5.L*4),%d4 # get lword 2
13262ap_n_cl:
13263 mov.l &28,%d3 # point to last digit
13264 mov.l &7,%d2 # init digit counter
13265ap_n_gd:
13266 bfextu %d4{%d3:&4},%d0 # get digit
13267 bne.b ap_n_fx # if non-zero, go to exp fix
13268 subq.l &4,%d3 # point to previous digit
13269 addq.l &1,%d1 # inc digit counter
13270 dbf.w %d2,ap_n_gd # get next digit
13271ap_n_fx:
13272 mov.l %d1,%d0 # copy counter to d0
13273 mov.l (%sp),%d1 # get adjusted exp from memory
13274 sub.l %d0,%d1 # subtract count from exp
13275 bgt.b ap_n_fm # if still pos, go fix mantissa
13276 neg.l %d1 # take abs of exp and clr SE
13277 mov.l (%a0),%d4 # load lword 1 to d4
13278 and.l &0xbfffffff,%d4 # and clr SE in d4
13279 and.l &0xbfffffff,(%a0) # and in memory
13280#
13281# Calculate the mantissa multiplier to compensate for the appending of
13282# zeros to the mantissa.
13283#
13284ap_n_fm:
13285 lea.l PTENRN(%pc),%a1 # get address of power-of-ten table
13286 clr.l %d3 # init table index
13287 fmov.s &0x3f800000,%fp1 # init fp1 to 1
13288 mov.l &3,%d2 # init d2 to count bits in counter
13289ap_n_el:
13290 asr.l &1,%d0 # shift lsb into carry
13291 bcc.b ap_n_en # if 1, mul fp1 by pwrten factor
13292 fmul.x (%a1,%d3),%fp1 # mul by 10**(d3_bit_no)
13293ap_n_en:
13294 add.l &12,%d3 # inc d3 to next rtable entry
13295 tst.l %d0 # check if d0 is zero
13296 bne.b ap_n_el # if not, get next bit
13297 fdiv.x %fp1,%fp0 # div mantissa by 10**(no_bits_shifted)
13298#
13299#
13300# Calculate power-of-ten factor from adjusted and shifted exponent.
13301#
13302# Register usage:
13303#
13304# pwrten:
13305# (*) d0: temp
13306# ( ) d1: exponent
13307# (*) d2: {FPCR[6:5],SM,SE} as index in RTABLE; temp
13308# (*) d3: FPCR work copy
13309# ( ) d4: first word of bcd
13310# (*) a1: RTABLE pointer
13311# calc_p:
13312# (*) d0: temp
13313# ( ) d1: exponent
13314# (*) d3: PWRTxx table index
13315# ( ) a0: pointer to working copy of bcd
13316# (*) a1: PWRTxx pointer
13317# (*) fp1: power-of-ten accumulator
13318#
13319# Pwrten calculates the exponent factor in the selected rounding mode
13320# according to the following table:
13321#
13322# Sign of Mant Sign of Exp Rounding Mode PWRTEN Rounding Mode
13323#
13324# ANY ANY RN RN
13325#
13326# + + RP RP
13327# - + RP RM
13328# + - RP RM
13329# - - RP RP
13330#
13331# + + RM RM
13332# - + RM RP
13333# + - RM RP
13334# - - RM RM
13335#
13336# + + RZ RM
13337# - + RZ RM
13338# + - RZ RP
13339# - - RZ RP
13340#
13341#
13342pwrten:
13343 mov.l USER_FPCR(%a6),%d3 # get user's FPCR
13344 bfextu %d3{&26:&2},%d2 # isolate rounding mode bits
13345 mov.l (%a0),%d4 # reload 1st bcd word to d4
13346 asl.l &2,%d2 # format d2 to be
13347 bfextu %d4{&0:&2},%d0 # {FPCR[6],FPCR[5],SM,SE}
13348 add.l %d0,%d2 # in d2 as index into RTABLE
13349 lea.l RTABLE(%pc),%a1 # load rtable base
13350 mov.b (%a1,%d2),%d0 # load new rounding bits from table
13351 clr.l %d3 # clear d3 to force no exc and extended
13352 bfins %d0,%d3{&26:&2} # stuff new rounding bits in FPCR
13353 fmov.l %d3,%fpcr # write new FPCR
13354 asr.l &1,%d0 # write correct PTENxx table
13355 bcc.b not_rp # to a1
13356 lea.l PTENRP(%pc),%a1 # it is RP
13357 bra.b calc_p # go to init section
13358not_rp:
13359 asr.l &1,%d0 # keep checking
13360 bcc.b not_rm
13361 lea.l PTENRM(%pc),%a1 # it is RM
13362 bra.b calc_p # go to init section
13363not_rm:
13364 lea.l PTENRN(%pc),%a1 # it is RN
13365calc_p:
13366 mov.l %d1,%d0 # copy exp to d0;use d0
13367 bpl.b no_neg # if exp is negative,
13368 neg.l %d0 # invert it
13369 or.l &0x40000000,(%a0) # and set SE bit
13370no_neg:
13371 clr.l %d3 # table index
13372 fmov.s &0x3f800000,%fp1 # init fp1 to 1
13373e_loop:
13374 asr.l &1,%d0 # shift next bit into carry
13375 bcc.b e_next # if zero, skip the mul
13376 fmul.x (%a1,%d3),%fp1 # mul by 10**(d3_bit_no)
13377e_next:
13378 add.l &12,%d3 # inc d3 to next rtable entry
13379 tst.l %d0 # check if d0 is zero
13380 bne.b e_loop # not zero, continue shifting
13381#
13382#
13383# Check the sign of the adjusted exp and make the value in fp0 the
13384# same sign. If the exp was pos then multiply fp1*fp0;
13385# else divide fp0/fp1.
13386#
13387# Register Usage:
13388# norm:
13389# ( ) a0: pointer to working bcd value
13390# (*) fp0: mantissa accumulator
13391# ( ) fp1: scaling factor - 10**(abs(exp))
13392#
13393pnorm:
13394 btst &30,(%a0) # test the sign of the exponent
13395 beq.b mul # if clear, go to multiply
13396div:
13397 fdiv.x %fp1,%fp0 # exp is negative, so divide mant by exp
13398 bra.b end_dec
13399mul:
13400 fmul.x %fp1,%fp0 # exp is positive, so multiply by exp
13401#
13402#
13403# Clean up and return with result in fp0.
13404#
13405# If the final mul/div in decbin incurred an inex exception,
13406# it will be inex2, but will be reported as inex1 by get_op.
13407#
13408end_dec:
13409 fmov.l %fpsr,%d0 # get status register
13410 bclr &inex2_bit+8,%d0 # test for inex2 and clear it
13411 beq.b no_exc # skip this if no exc
13412 ori.w &inx1a_mask,2+USER_FPSR(%a6) # set INEX1/AINEX
13413no_exc:
13414 add.l &0x4,%sp # clear 1 lw param
13415 fmovm.x (%sp)+,&0x40 # restore fp1
13416 movm.l (%sp)+,&0x3c # restore d2-d5
13417 fmov.l &0x0,%fpcr
13418 fmov.l &0x0,%fpsr
13419 rts
13420
13421#########################################################################
13422# bindec(): Converts an input in extended precision format to bcd format#
13423# #
13424# INPUT *************************************************************** #
13425# a0 = pointer to the input extended precision value in memory. #
13426# the input may be either normalized, unnormalized, or #
13427# denormalized. #
13428# d0 = contains the k-factor sign-extended to 32-bits. #
13429# #
13430# OUTPUT ************************************************************** #
13431# FP_SCR0(a6) = bcd format result on the stack. #
13432# #
13433# ALGORITHM *********************************************************** #
13434# #
13435# A1. Set RM and size ext; Set SIGMA = sign of input. #
13436# The k-factor is saved for use in d7. Clear the #
13437# BINDEC_FLG for separating normalized/denormalized #
13438# input. If input is unnormalized or denormalized, #
13439# normalize it. #
13440# #
13441# A2. Set X = abs(input). #
13442# #
13443# A3. Compute ILOG. #
13444# ILOG is the log base 10 of the input value. It is #
13445# approximated by adding e + 0.f when the original #
13446# value is viewed as 2^^e * 1.f in extended precision. #
13447# This value is stored in d6. #
13448# #
13449# A4. Clr INEX bit. #
13450# The operation in A3 above may have set INEX2. #
13451# #
13452# A5. Set ICTR = 0; #
13453# ICTR is a flag used in A13. It must be set before the #
13454# loop entry A6. #
13455# #
13456# A6. Calculate LEN. #
13457# LEN is the number of digits to be displayed. The #
13458# k-factor can dictate either the total number of digits, #
13459# if it is a positive number, or the number of digits #
13460# after the decimal point which are to be included as #
13461# significant. See the 68882 manual for examples. #
13462# If LEN is computed to be greater than 17, set OPERR in #
13463# USER_FPSR. LEN is stored in d4. #
13464# #
13465# A7. Calculate SCALE. #
13466# SCALE is equal to 10^ISCALE, where ISCALE is the number #
13467# of decimal places needed to insure LEN integer digits #
13468# in the output before conversion to bcd. LAMBDA is the #
13469# sign of ISCALE, used in A9. Fp1 contains #
13470# 10^^(abs(ISCALE)) using a rounding mode which is a #
13471# function of the original rounding mode and the signs #
13472# of ISCALE and X. A table is given in the code. #
13473# #
13474# A8. Clr INEX; Force RZ. #
13475# The operation in A3 above may have set INEX2. #
13476# RZ mode is forced for the scaling operation to insure #
13477# only one rounding error. The grs bits are collected in #
13478# the INEX flag for use in A10. #
13479# #
13480# A9. Scale X -> Y. #
13481# The mantissa is scaled to the desired number of #
13482# significant digits. The excess digits are collected #
13483# in INEX2. #
13484# #
13485# A10. Or in INEX. #
13486# If INEX is set, round error occurred. This is #
13487# compensated for by 'or-ing' in the INEX2 flag to #
13488# the lsb of Y. #
13489# #
13490# A11. Restore original FPCR; set size ext. #
13491# Perform FINT operation in the user's rounding mode. #
13492# Keep the size to extended. #
13493# #
13494# A12. Calculate YINT = FINT(Y) according to user's rounding #
13495# mode. The FPSP routine sintd0 is used. The output #
13496# is in fp0. #
13497# #
13498# A13. Check for LEN digits. #
13499# If the int operation results in more than LEN digits, #
13500# or less than LEN -1 digits, adjust ILOG and repeat from #
13501# A6. This test occurs only on the first pass. If the #
13502# result is exactly 10^LEN, decrement ILOG and divide #
13503# the mantissa by 10. #
13504# #
13505# A14. Convert the mantissa to bcd. #
13506# The binstr routine is used to convert the LEN digit #
13507# mantissa to bcd in memory. The input to binstr is #
13508# to be a fraction; i.e. (mantissa)/10^LEN and adjusted #
13509# such that the decimal point is to the left of bit 63. #
13510# The bcd digits are stored in the correct position in #
13511# the final string area in memory. #
13512# #
13513# A15. Convert the exponent to bcd. #
13514# As in A14 above, the exp is converted to bcd and the #
13515# digits are stored in the final string. #
13516# Test the length of the final exponent string. If the #
13517# length is 4, set operr. #
13518# #
13519# A16. Write sign bits to final string. #
13520# #
13521#########################################################################
13522
13523set BINDEC_FLG, EXC_TEMP # DENORM flag
13524
13525# Constants in extended precision
13526PLOG2:
13527 long 0x3FFD0000,0x9A209A84,0xFBCFF798,0x00000000
13528PLOG2UP1:
13529 long 0x3FFD0000,0x9A209A84,0xFBCFF799,0x00000000
13530
13531# Constants in single precision
13532FONE:
13533 long 0x3F800000,0x00000000,0x00000000,0x00000000
13534FTWO:
13535 long 0x40000000,0x00000000,0x00000000,0x00000000
13536FTEN:
13537 long 0x41200000,0x00000000,0x00000000,0x00000000
13538F4933:
13539 long 0x459A2800,0x00000000,0x00000000,0x00000000
13540
13541RBDTBL:
13542 byte 0,0,0,0
13543 byte 3,3,2,2
13544 byte 3,2,2,3
13545 byte 2,3,3,2
13546
13547# Implementation Notes:
13548#
13549# The registers are used as follows:
13550#
13551# d0: scratch; LEN input to binstr
13552# d1: scratch
13553# d2: upper 32-bits of mantissa for binstr
13554# d3: scratch;lower 32-bits of mantissa for binstr
13555# d4: LEN
13556# d5: LAMBDA/ICTR
13557# d6: ILOG
13558# d7: k-factor
13559# a0: ptr for original operand/final result
13560# a1: scratch pointer
13561# a2: pointer to FP_X; abs(original value) in ext
13562# fp0: scratch
13563# fp1: scratch
13564# fp2: scratch
13565# F_SCR1:
13566# F_SCR2:
13567# L_SCR1:
13568# L_SCR2:
13569
13570 global bindec
13571bindec:
13572 movm.l &0x3f20,-(%sp) # {%d2-%d7/%a2}
13573 fmovm.x &0x7,-(%sp) # {%fp0-%fp2}
13574
13575# A1. Set RM and size ext. Set SIGMA = sign input;
13576# The k-factor is saved for use in d7. Clear BINDEC_FLG for
13577# separating normalized/denormalized input. If the input
13578# is a denormalized number, set the BINDEC_FLG memory word
13579# to signal denorm. If the input is unnormalized, normalize
13580# the input and test for denormalized result.
13581#
13582 fmov.l &rm_mode*0x10,%fpcr # set RM and ext
13583 mov.l (%a0),L_SCR2(%a6) # save exponent for sign check
13584 mov.l %d0,%d7 # move k-factor to d7
13585
13586 clr.b BINDEC_FLG(%a6) # clr norm/denorm flag
13587 cmpi.b STAG(%a6),&DENORM # is input a DENORM?
13588 bne.w A2_str # no; input is a NORM
13589
13590#
13591# Normalize the denorm
13592#
13593un_de_norm:
13594 mov.w (%a0),%d0
13595 and.w &0x7fff,%d0 # strip sign of normalized exp
13596 mov.l 4(%a0),%d1
13597 mov.l 8(%a0),%d2
13598norm_loop:
13599 sub.w &1,%d0
13600 lsl.l &1,%d2
13601 roxl.l &1,%d1
13602 tst.l %d1
13603 bge.b norm_loop
13604#
13605# Test if the normalized input is denormalized
13606#
13607 tst.w %d0
13608 bgt.b pos_exp # if greater than zero, it is a norm
13609 st BINDEC_FLG(%a6) # set flag for denorm
13610pos_exp:
13611 and.w &0x7fff,%d0 # strip sign of normalized exp
13612 mov.w %d0,(%a0)
13613 mov.l %d1,4(%a0)
13614 mov.l %d2,8(%a0)
13615
13616# A2. Set X = abs(input).
13617#
13618A2_str:
13619 mov.l (%a0),FP_SCR1(%a6) # move input to work space
13620 mov.l 4(%a0),FP_SCR1+4(%a6) # move input to work space
13621 mov.l 8(%a0),FP_SCR1+8(%a6) # move input to work space
13622 and.l &0x7fffffff,FP_SCR1(%a6) # create abs(X)
13623
13624# A3. Compute ILOG.
13625# ILOG is the log base 10 of the input value. It is approx-
13626# imated by adding e + 0.f when the original value is viewed
13627# as 2^^e * 1.f in extended precision. This value is stored
13628# in d6.
13629#
13630# Register usage:
13631# Input/Output
13632# d0: k-factor/exponent
13633# d2: x/x
13634# d3: x/x
13635# d4: x/x
13636# d5: x/x
13637# d6: x/ILOG
13638# d7: k-factor/Unchanged
13639# a0: ptr for original operand/final result
13640# a1: x/x
13641# a2: x/x
13642# fp0: x/float(ILOG)
13643# fp1: x/x
13644# fp2: x/x
13645# F_SCR1:x/x
13646# F_SCR2:Abs(X)/Abs(X) with $3fff exponent
13647# L_SCR1:x/x
13648# L_SCR2:first word of X packed/Unchanged
13649
13650 tst.b BINDEC_FLG(%a6) # check for denorm
13651 beq.b A3_cont # if clr, continue with norm
13652 mov.l &-4933,%d6 # force ILOG = -4933
13653 bra.b A4_str
13654A3_cont:
13655 mov.w FP_SCR1(%a6),%d0 # move exp to d0
13656 mov.w &0x3fff,FP_SCR1(%a6) # replace exponent with 0x3fff
13657 fmov.x FP_SCR1(%a6),%fp0 # now fp0 has 1.f
13658 sub.w &0x3fff,%d0 # strip off bias
13659 fadd.w %d0,%fp0 # add in exp
13660 fsub.s FONE(%pc),%fp0 # subtract off 1.0
13661 fbge.w pos_res # if pos, branch
13662 fmul.x PLOG2UP1(%pc),%fp0 # if neg, mul by LOG2UP1
13663 fmov.l %fp0,%d6 # put ILOG in d6 as a lword
13664 bra.b A4_str # go move out ILOG
13665pos_res:
13666 fmul.x PLOG2(%pc),%fp0 # if pos, mul by LOG2
13667 fmov.l %fp0,%d6 # put ILOG in d6 as a lword
13668
13669
13670# A4. Clr INEX bit.
13671# The operation in A3 above may have set INEX2.
13672
13673A4_str:
13674 fmov.l &0,%fpsr # zero all of fpsr - nothing needed
13675
13676
13677# A5. Set ICTR = 0;
13678# ICTR is a flag used in A13. It must be set before the
13679# loop entry A6. The lower word of d5 is used for ICTR.
13680
13681 clr.w %d5 # clear ICTR
13682
13683# A6. Calculate LEN.
13684# LEN is the number of digits to be displayed. The k-factor
13685# can dictate either the total number of digits, if it is
13686# a positive number, or the number of digits after the
13687# original decimal point which are to be included as
13688# significant. See the 68882 manual for examples.
13689# If LEN is computed to be greater than 17, set OPERR in
13690# USER_FPSR. LEN is stored in d4.
13691#
13692# Register usage:
13693# Input/Output
13694# d0: exponent/Unchanged
13695# d2: x/x/scratch
13696# d3: x/x
13697# d4: exc picture/LEN
13698# d5: ICTR/Unchanged
13699# d6: ILOG/Unchanged
13700# d7: k-factor/Unchanged
13701# a0: ptr for original operand/final result
13702# a1: x/x
13703# a2: x/x
13704# fp0: float(ILOG)/Unchanged
13705# fp1: x/x
13706# fp2: x/x
13707# F_SCR1:x/x
13708# F_SCR2:Abs(X) with $3fff exponent/Unchanged
13709# L_SCR1:x/x
13710# L_SCR2:first word of X packed/Unchanged
13711
13712A6_str:
13713 tst.l %d7 # branch on sign of k
13714 ble.b k_neg # if k <= 0, LEN = ILOG + 1 - k
13715 mov.l %d7,%d4 # if k > 0, LEN = k
13716 bra.b len_ck # skip to LEN check
13717k_neg:
13718 mov.l %d6,%d4 # first load ILOG to d4
13719 sub.l %d7,%d4 # subtract off k
13720 addq.l &1,%d4 # add in the 1
13721len_ck:
13722 tst.l %d4 # LEN check: branch on sign of LEN
13723 ble.b LEN_ng # if neg, set LEN = 1
13724 cmp.l %d4,&17 # test if LEN > 17
13725 ble.b A7_str # if not, forget it
13726 mov.l &17,%d4 # set max LEN = 17
13727 tst.l %d7 # if negative, never set OPERR
13728 ble.b A7_str # if positive, continue
13729 or.l &opaop_mask,USER_FPSR(%a6) # set OPERR & AIOP in USER_FPSR
13730 bra.b A7_str # finished here
13731LEN_ng:
13732 mov.l &1,%d4 # min LEN is 1
13733
13734
13735# A7. Calculate SCALE.
13736# SCALE is equal to 10^ISCALE, where ISCALE is the number
13737# of decimal places needed to insure LEN integer digits
13738# in the output before conversion to bcd. LAMBDA is the sign
13739# of ISCALE, used in A9. Fp1 contains 10^^(abs(ISCALE)) using
13740# the rounding mode as given in the following table (see
13741# Coonen, p. 7.23 as ref.; however, the SCALE variable is
13742# of opposite sign in bindec.sa from Coonen).
13743#
13744# Initial USE
13745# FPCR[6:5] LAMBDA SIGN(X) FPCR[6:5]
13746# ----------------------------------------------
13747# RN 00 0 0 00/0 RN
13748# RN 00 0 1 00/0 RN
13749# RN 00 1 0 00/0 RN
13750# RN 00 1 1 00/0 RN
13751# RZ 01 0 0 11/3 RP
13752# RZ 01 0 1 11/3 RP
13753# RZ 01 1 0 10/2 RM
13754# RZ 01 1 1 10/2 RM
13755# RM 10 0 0 11/3 RP
13756# RM 10 0 1 10/2 RM
13757# RM 10 1 0 10/2 RM
13758# RM 10 1 1 11/3 RP
13759# RP 11 0 0 10/2 RM
13760# RP 11 0 1 11/3 RP
13761# RP 11 1 0 11/3 RP
13762# RP 11 1 1 10/2 RM
13763#
13764# Register usage:
13765# Input/Output
13766# d0: exponent/scratch - final is 0
13767# d2: x/0 or 24 for A9
13768# d3: x/scratch - offset ptr into PTENRM array
13769# d4: LEN/Unchanged
13770# d5: 0/ICTR:LAMBDA
13771# d6: ILOG/ILOG or k if ((k<=0)&(ILOG<k))
13772# d7: k-factor/Unchanged
13773# a0: ptr for original operand/final result
13774# a1: x/ptr to PTENRM array
13775# a2: x/x
13776# fp0: float(ILOG)/Unchanged
13777# fp1: x/10^ISCALE
13778# fp2: x/x
13779# F_SCR1:x/x
13780# F_SCR2:Abs(X) with $3fff exponent/Unchanged
13781# L_SCR1:x/x
13782# L_SCR2:first word of X packed/Unchanged
13783
13784A7_str:
13785 tst.l %d7 # test sign of k
13786 bgt.b k_pos # if pos and > 0, skip this
13787 cmp.l %d7,%d6 # test k - ILOG
13788 blt.b k_pos # if ILOG >= k, skip this
13789 mov.l %d7,%d6 # if ((k<0) & (ILOG < k)) ILOG = k
13790k_pos:
13791 mov.l %d6,%d0 # calc ILOG + 1 - LEN in d0
13792 addq.l &1,%d0 # add the 1
13793 sub.l %d4,%d0 # sub off LEN
13794 swap %d5 # use upper word of d5 for LAMBDA
13795 clr.w %d5 # set it zero initially
13796 clr.w %d2 # set up d2 for very small case
13797 tst.l %d0 # test sign of ISCALE
13798 bge.b iscale # if pos, skip next inst
13799 addq.w &1,%d5 # if neg, set LAMBDA true
13800 cmp.l %d0,&0xffffecd4 # test iscale <= -4908
13801 bgt.b no_inf # if false, skip rest
13802 add.l &24,%d0 # add in 24 to iscale
13803 mov.l &24,%d2 # put 24 in d2 for A9
13804no_inf:
13805 neg.l %d0 # and take abs of ISCALE
13806iscale:
13807 fmov.s FONE(%pc),%fp1 # init fp1 to 1
13808 bfextu USER_FPCR(%a6){&26:&2},%d1 # get initial rmode bits
13809 lsl.w &1,%d1 # put them in bits 2:1
13810 add.w %d5,%d1 # add in LAMBDA
13811 lsl.w &1,%d1 # put them in bits 3:1
13812 tst.l L_SCR2(%a6) # test sign of original x
13813 bge.b x_pos # if pos, don't set bit 0
13814 addq.l &1,%d1 # if neg, set bit 0
13815x_pos:
13816 lea.l RBDTBL(%pc),%a2 # load rbdtbl base
13817 mov.b (%a2,%d1),%d3 # load d3 with new rmode
13818 lsl.l &4,%d3 # put bits in proper position
13819 fmov.l %d3,%fpcr # load bits into fpu
13820 lsr.l &4,%d3 # put bits in proper position
13821 tst.b %d3 # decode new rmode for pten table
13822 bne.b not_rn # if zero, it is RN
13823 lea.l PTENRN(%pc),%a1 # load a1 with RN table base
13824 bra.b rmode # exit decode
13825not_rn:
13826 lsr.b &1,%d3 # get lsb in carry
13827 bcc.b not_rp2 # if carry clear, it is RM
13828 lea.l PTENRP(%pc),%a1 # load a1 with RP table base
13829 bra.b rmode # exit decode
13830not_rp2:
13831 lea.l PTENRM(%pc),%a1 # load a1 with RM table base
13832rmode:
13833 clr.l %d3 # clr table index
13834e_loop2:
13835 lsr.l &1,%d0 # shift next bit into carry
13836 bcc.b e_next2 # if zero, skip the mul
13837 fmul.x (%a1,%d3),%fp1 # mul by 10**(d3_bit_no)
13838e_next2:
13839 add.l &12,%d3 # inc d3 to next pwrten table entry
13840 tst.l %d0 # test if ISCALE is zero
13841 bne.b e_loop2 # if not, loop
13842
13843# A8. Clr INEX; Force RZ.
13844# The operation in A3 above may have set INEX2.
13845# RZ mode is forced for the scaling operation to insure
13846# only one rounding error. The grs bits are collected in
13847# the INEX flag for use in A10.
13848#
13849# Register usage:
13850# Input/Output
13851
13852 fmov.l &0,%fpsr # clr INEX
13853 fmov.l &rz_mode*0x10,%fpcr # set RZ rounding mode
13854
13855# A9. Scale X -> Y.
13856# The mantissa is scaled to the desired number of significant
13857# digits. The excess digits are collected in INEX2. If mul,
13858# Check d2 for excess 10 exponential value. If not zero,
13859# the iscale value would have caused the pwrten calculation
13860# to overflow. Only a negative iscale can cause this, so
13861# multiply by 10^(d2), which is now only allowed to be 24,
13862# with a multiply by 10^8 and 10^16, which is exact since
13863# 10^24 is exact. If the input was denormalized, we must
13864# create a busy stack frame with the mul command and the
13865# two operands, and allow the fpu to complete the multiply.
13866#
13867# Register usage:
13868# Input/Output
13869# d0: FPCR with RZ mode/Unchanged
13870# d2: 0 or 24/unchanged
13871# d3: x/x
13872# d4: LEN/Unchanged
13873# d5: ICTR:LAMBDA
13874# d6: ILOG/Unchanged
13875# d7: k-factor/Unchanged
13876# a0: ptr for original operand/final result
13877# a1: ptr to PTENRM array/Unchanged
13878# a2: x/x
13879# fp0: float(ILOG)/X adjusted for SCALE (Y)
13880# fp1: 10^ISCALE/Unchanged
13881# fp2: x/x
13882# F_SCR1:x/x
13883# F_SCR2:Abs(X) with $3fff exponent/Unchanged
13884# L_SCR1:x/x
13885# L_SCR2:first word of X packed/Unchanged
13886
13887A9_str:
13888 fmov.x (%a0),%fp0 # load X from memory
13889 fabs.x %fp0 # use abs(X)
13890 tst.w %d5 # LAMBDA is in lower word of d5
13891 bne.b sc_mul # if neg (LAMBDA = 1), scale by mul
13892 fdiv.x %fp1,%fp0 # calculate X / SCALE -> Y to fp0
13893 bra.w A10_st # branch to A10
13894
13895sc_mul:
13896 tst.b BINDEC_FLG(%a6) # check for denorm
13897 beq.w A9_norm # if norm, continue with mul
13898
13899# for DENORM, we must calculate:
13900# fp0 = input_op * 10^ISCALE * 10^24
13901# since the input operand is a DENORM, we can't multiply it directly.
13902# so, we do the multiplication of the exponents and mantissas separately.
13903# in this way, we avoid underflow on intermediate stages of the
13904# multiplication and guarantee a result without exception.
13905 fmovm.x &0x2,-(%sp) # save 10^ISCALE to stack
13906
13907 mov.w (%sp),%d3 # grab exponent
13908 andi.w &0x7fff,%d3 # clear sign
13909 ori.w &0x8000,(%a0) # make DENORM exp negative
13910 add.w (%a0),%d3 # add DENORM exp to 10^ISCALE exp
13911 subi.w &0x3fff,%d3 # subtract BIAS
13912 add.w 36(%a1),%d3
13913 subi.w &0x3fff,%d3 # subtract BIAS
13914 add.w 48(%a1),%d3
13915 subi.w &0x3fff,%d3 # subtract BIAS
13916
13917 bmi.w sc_mul_err # is result is DENORM, punt!!!
13918
13919 andi.w &0x8000,(%sp) # keep sign
13920 or.w %d3,(%sp) # insert new exponent
13921 andi.w &0x7fff,(%a0) # clear sign bit on DENORM again
13922 mov.l 0x8(%a0),-(%sp) # put input op mantissa on stk
13923 mov.l 0x4(%a0),-(%sp)
13924 mov.l &0x3fff0000,-(%sp) # force exp to zero
13925 fmovm.x (%sp)+,&0x80 # load normalized DENORM into fp0
13926 fmul.x (%sp)+,%fp0
13927
13928# fmul.x 36(%a1),%fp0 # multiply fp0 by 10^8
13929# fmul.x 48(%a1),%fp0 # multiply fp0 by 10^16
13930 mov.l 36+8(%a1),-(%sp) # get 10^8 mantissa
13931 mov.l 36+4(%a1),-(%sp)
13932 mov.l &0x3fff0000,-(%sp) # force exp to zero
13933 mov.l 48+8(%a1),-(%sp) # get 10^16 mantissa
13934 mov.l 48+4(%a1),-(%sp)
13935 mov.l &0x3fff0000,-(%sp)# force exp to zero
13936 fmul.x (%sp)+,%fp0 # multiply fp0 by 10^8
13937 fmul.x (%sp)+,%fp0 # multiply fp0 by 10^16
13938 bra.b A10_st
13939
13940sc_mul_err:
13941 bra.b sc_mul_err
13942
13943A9_norm:
13944 tst.w %d2 # test for small exp case
13945 beq.b A9_con # if zero, continue as normal
13946 fmul.x 36(%a1),%fp0 # multiply fp0 by 10^8
13947 fmul.x 48(%a1),%fp0 # multiply fp0 by 10^16
13948A9_con:
13949 fmul.x %fp1,%fp0 # calculate X * SCALE -> Y to fp0
13950
13951# A10. Or in INEX.
13952# If INEX is set, round error occurred. This is compensated
13953# for by 'or-ing' in the INEX2 flag to the lsb of Y.
13954#
13955# Register usage:
13956# Input/Output
13957# d0: FPCR with RZ mode/FPSR with INEX2 isolated
13958# d2: x/x
13959# d3: x/x
13960# d4: LEN/Unchanged
13961# d5: ICTR:LAMBDA
13962# d6: ILOG/Unchanged
13963# d7: k-factor/Unchanged
13964# a0: ptr for original operand/final result
13965# a1: ptr to PTENxx array/Unchanged
13966# a2: x/ptr to FP_SCR1(a6)
13967# fp0: Y/Y with lsb adjusted
13968# fp1: 10^ISCALE/Unchanged
13969# fp2: x/x
13970
13971A10_st:
13972 fmov.l %fpsr,%d0 # get FPSR
13973 fmov.x %fp0,FP_SCR1(%a6) # move Y to memory
13974 lea.l FP_SCR1(%a6),%a2 # load a2 with ptr to FP_SCR1
13975 btst &9,%d0 # check if INEX2 set
13976 beq.b A11_st # if clear, skip rest
13977 or.l &1,8(%a2) # or in 1 to lsb of mantissa
13978 fmov.x FP_SCR1(%a6),%fp0 # write adjusted Y back to fpu
13979
13980
13981# A11. Restore original FPCR; set size ext.
13982# Perform FINT operation in the user's rounding mode. Keep
13983# the size to extended. The sintdo entry point in the sint
13984# routine expects the FPCR value to be in USER_FPCR for
13985# mode and precision. The original FPCR is saved in L_SCR1.
13986
13987A11_st:
13988 mov.l USER_FPCR(%a6),L_SCR1(%a6) # save it for later
13989 and.l &0x00000030,USER_FPCR(%a6) # set size to ext,
13990# ;block exceptions
13991
13992
13993# A12. Calculate YINT = FINT(Y) according to user's rounding mode.
13994# The FPSP routine sintd0 is used. The output is in fp0.
13995#
13996# Register usage:
13997# Input/Output
13998# d0: FPSR with AINEX cleared/FPCR with size set to ext
13999# d2: x/x/scratch
14000# d3: x/x
14001# d4: LEN/Unchanged
14002# d5: ICTR:LAMBDA/Unchanged
14003# d6: ILOG/Unchanged
14004# d7: k-factor/Unchanged
14005# a0: ptr for original operand/src ptr for sintdo
14006# a1: ptr to PTENxx array/Unchanged
14007# a2: ptr to FP_SCR1(a6)/Unchanged
14008# a6: temp pointer to FP_SCR1(a6) - orig value saved and restored
14009# fp0: Y/YINT
14010# fp1: 10^ISCALE/Unchanged
14011# fp2: x/x
14012# F_SCR1:x/x
14013# F_SCR2:Y adjusted for inex/Y with original exponent
14014# L_SCR1:x/original USER_FPCR
14015# L_SCR2:first word of X packed/Unchanged
14016
14017A12_st:
14018 movm.l &0xc0c0,-(%sp) # save regs used by sintd0 {%d0-%d1/%a0-%a1}
14019 mov.l L_SCR1(%a6),-(%sp)
14020 mov.l L_SCR2(%a6),-(%sp)
14021
14022 lea.l FP_SCR1(%a6),%a0 # a0 is ptr to FP_SCR1(a6)
14023 fmov.x %fp0,(%a0) # move Y to memory at FP_SCR1(a6)
14024 tst.l L_SCR2(%a6) # test sign of original operand
14025 bge.b do_fint12 # if pos, use Y
14026 or.l &0x80000000,(%a0) # if neg, use -Y
14027do_fint12:
14028 mov.l USER_FPSR(%a6),-(%sp)
14029# bsr sintdo # sint routine returns int in fp0
14030
14031 fmov.l USER_FPCR(%a6),%fpcr
14032 fmov.l &0x0,%fpsr # clear the AEXC bits!!!
14033## mov.l USER_FPCR(%a6),%d0 # ext prec/keep rnd mode
14034## andi.l &0x00000030,%d0
14035## fmov.l %d0,%fpcr
14036 fint.x FP_SCR1(%a6),%fp0 # do fint()
14037 fmov.l %fpsr,%d0
14038 or.w %d0,FPSR_EXCEPT(%a6)
14039## fmov.l &0x0,%fpcr
14040## fmov.l %fpsr,%d0 # don't keep ccodes
14041## or.w %d0,FPSR_EXCEPT(%a6)
14042
14043 mov.b (%sp),USER_FPSR(%a6)
14044 add.l &4,%sp
14045
14046 mov.l (%sp)+,L_SCR2(%a6)
14047 mov.l (%sp)+,L_SCR1(%a6)
14048 movm.l (%sp)+,&0x303 # restore regs used by sint {%d0-%d1/%a0-%a1}
14049
14050 mov.l L_SCR2(%a6),FP_SCR1(%a6) # restore original exponent
14051 mov.l L_SCR1(%a6),USER_FPCR(%a6) # restore user's FPCR
14052
14053# A13. Check for LEN digits.
14054# If the int operation results in more than LEN digits,
14055# or less than LEN -1 digits, adjust ILOG and repeat from
14056# A6. This test occurs only on the first pass. If the
14057# result is exactly 10^LEN, decrement ILOG and divide
14058# the mantissa by 10. The calculation of 10^LEN cannot
14059# be inexact, since all powers of ten upto 10^27 are exact
14060# in extended precision, so the use of a previous power-of-ten
14061# table will introduce no error.
14062#
14063#
14064# Register usage:
14065# Input/Output
14066# d0: FPCR with size set to ext/scratch final = 0
14067# d2: x/x
14068# d3: x/scratch final = x
14069# d4: LEN/LEN adjusted
14070# d5: ICTR:LAMBDA/LAMBDA:ICTR
14071# d6: ILOG/ILOG adjusted
14072# d7: k-factor/Unchanged
14073# a0: pointer into memory for packed bcd string formation
14074# a1: ptr to PTENxx array/Unchanged
14075# a2: ptr to FP_SCR1(a6)/Unchanged
14076# fp0: int portion of Y/abs(YINT) adjusted
14077# fp1: 10^ISCALE/Unchanged
14078# fp2: x/10^LEN
14079# F_SCR1:x/x
14080# F_SCR2:Y with original exponent/Unchanged
14081# L_SCR1:original USER_FPCR/Unchanged
14082# L_SCR2:first word of X packed/Unchanged
14083
14084A13_st:
14085 swap %d5 # put ICTR in lower word of d5
14086 tst.w %d5 # check if ICTR = 0
14087 bne not_zr # if non-zero, go to second test
14088#
14089# Compute 10^(LEN-1)
14090#
14091 fmov.s FONE(%pc),%fp2 # init fp2 to 1.0
14092 mov.l %d4,%d0 # put LEN in d0
14093 subq.l &1,%d0 # d0 = LEN -1
14094 clr.l %d3 # clr table index
14095l_loop:
14096 lsr.l &1,%d0 # shift next bit into carry
14097 bcc.b l_next # if zero, skip the mul
14098 fmul.x (%a1,%d3),%fp2 # mul by 10**(d3_bit_no)
14099l_next:
14100 add.l &12,%d3 # inc d3 to next pwrten table entry
14101 tst.l %d0 # test if LEN is zero
14102 bne.b l_loop # if not, loop
14103#
14104# 10^LEN-1 is computed for this test and A14. If the input was
14105# denormalized, check only the case in which YINT > 10^LEN.
14106#
14107 tst.b BINDEC_FLG(%a6) # check if input was norm
14108 beq.b A13_con # if norm, continue with checking
14109 fabs.x %fp0 # take abs of YINT
14110 bra test_2
14111#
14112# Compare abs(YINT) to 10^(LEN-1) and 10^LEN
14113#
14114A13_con:
14115 fabs.x %fp0 # take abs of YINT
14116 fcmp.x %fp0,%fp2 # compare abs(YINT) with 10^(LEN-1)
14117 fbge.w test_2 # if greater, do next test
14118 subq.l &1,%d6 # subtract 1 from ILOG
14119 mov.w &1,%d5 # set ICTR
14120 fmov.l &rm_mode*0x10,%fpcr # set rmode to RM
14121 fmul.s FTEN(%pc),%fp2 # compute 10^LEN
14122 bra.w A6_str # return to A6 and recompute YINT
14123test_2:
14124 fmul.s FTEN(%pc),%fp2 # compute 10^LEN
14125 fcmp.x %fp0,%fp2 # compare abs(YINT) with 10^LEN
14126 fblt.w A14_st # if less, all is ok, go to A14
14127 fbgt.w fix_ex # if greater, fix and redo
14128 fdiv.s FTEN(%pc),%fp0 # if equal, divide by 10
14129 addq.l &1,%d6 # and inc ILOG
14130 bra.b A14_st # and continue elsewhere
14131fix_ex:
14132 addq.l &1,%d6 # increment ILOG by 1
14133 mov.w &1,%d5 # set ICTR
14134 fmov.l &rm_mode*0x10,%fpcr # set rmode to RM
14135 bra.w A6_str # return to A6 and recompute YINT
14136#
14137# Since ICTR <> 0, we have already been through one adjustment,
14138# and shouldn't have another; this is to check if abs(YINT) = 10^LEN
14139# 10^LEN is again computed using whatever table is in a1 since the
14140# value calculated cannot be inexact.
14141#
14142not_zr:
14143 fmov.s FONE(%pc),%fp2 # init fp2 to 1.0
14144 mov.l %d4,%d0 # put LEN in d0
14145 clr.l %d3 # clr table index
14146z_loop:
14147 lsr.l &1,%d0 # shift next bit into carry
14148 bcc.b z_next # if zero, skip the mul
14149 fmul.x (%a1,%d3),%fp2 # mul by 10**(d3_bit_no)
14150z_next:
14151 add.l &12,%d3 # inc d3 to next pwrten table entry
14152 tst.l %d0 # test if LEN is zero
14153 bne.b z_loop # if not, loop
14154 fabs.x %fp0 # get abs(YINT)
14155 fcmp.x %fp0,%fp2 # check if abs(YINT) = 10^LEN
14156 fbneq.w A14_st # if not, skip this
14157 fdiv.s FTEN(%pc),%fp0 # divide abs(YINT) by 10
14158 addq.l &1,%d6 # and inc ILOG by 1
14159 addq.l &1,%d4 # and inc LEN
14160 fmul.s FTEN(%pc),%fp2 # if LEN++, the get 10^^LEN
14161
14162# A14. Convert the mantissa to bcd.
14163# The binstr routine is used to convert the LEN digit
14164# mantissa to bcd in memory. The input to binstr is
14165# to be a fraction; i.e. (mantissa)/10^LEN and adjusted
14166# such that the decimal point is to the left of bit 63.
14167# The bcd digits are stored in the correct position in
14168# the final string area in memory.
14169#
14170#
14171# Register usage:
14172# Input/Output
14173# d0: x/LEN call to binstr - final is 0
14174# d1: x/0
14175# d2: x/ms 32-bits of mant of abs(YINT)
14176# d3: x/ls 32-bits of mant of abs(YINT)
14177# d4: LEN/Unchanged
14178# d5: ICTR:LAMBDA/LAMBDA:ICTR
14179# d6: ILOG
14180# d7: k-factor/Unchanged
14181# a0: pointer into memory for packed bcd string formation
14182# /ptr to first mantissa byte in result string
14183# a1: ptr to PTENxx array/Unchanged
14184# a2: ptr to FP_SCR1(a6)/Unchanged
14185# fp0: int portion of Y/abs(YINT) adjusted
14186# fp1: 10^ISCALE/Unchanged
14187# fp2: 10^LEN/Unchanged
14188# F_SCR1:x/Work area for final result
14189# F_SCR2:Y with original exponent/Unchanged
14190# L_SCR1:original USER_FPCR/Unchanged
14191# L_SCR2:first word of X packed/Unchanged
14192
14193A14_st:
14194 fmov.l &rz_mode*0x10,%fpcr # force rz for conversion
14195 fdiv.x %fp2,%fp0 # divide abs(YINT) by 10^LEN
14196 lea.l FP_SCR0(%a6),%a0
14197 fmov.x %fp0,(%a0) # move abs(YINT)/10^LEN to memory
14198 mov.l 4(%a0),%d2 # move 2nd word of FP_RES to d2
14199 mov.l 8(%a0),%d3 # move 3rd word of FP_RES to d3
14200 clr.l 4(%a0) # zero word 2 of FP_RES
14201 clr.l 8(%a0) # zero word 3 of FP_RES
14202 mov.l (%a0),%d0 # move exponent to d0
14203 swap %d0 # put exponent in lower word
14204 beq.b no_sft # if zero, don't shift
14205 sub.l &0x3ffd,%d0 # sub bias less 2 to make fract
14206 tst.l %d0 # check if > 1
14207 bgt.b no_sft # if so, don't shift
14208 neg.l %d0 # make exp positive
14209m_loop:
14210 lsr.l &1,%d2 # shift d2:d3 right, add 0s
14211 roxr.l &1,%d3 # the number of places
14212 dbf.w %d0,m_loop # given in d0
14213no_sft:
14214 tst.l %d2 # check for mantissa of zero
14215 bne.b no_zr # if not, go on
14216 tst.l %d3 # continue zero check
14217 beq.b zer_m # if zero, go directly to binstr
14218no_zr:
14219 clr.l %d1 # put zero in d1 for addx
14220 add.l &0x00000080,%d3 # inc at bit 7
14221 addx.l %d1,%d2 # continue inc
14222 and.l &0xffffff80,%d3 # strip off lsb not used by 882
14223zer_m:
14224 mov.l %d4,%d0 # put LEN in d0 for binstr call
14225 addq.l &3,%a0 # a0 points to M16 byte in result
14226 bsr binstr # call binstr to convert mant
14227
14228
14229# A15. Convert the exponent to bcd.
14230# As in A14 above, the exp is converted to bcd and the
14231# digits are stored in the final string.
14232#
14233# Digits are stored in L_SCR1(a6) on return from BINDEC as:
14234#
14235# 32 16 15 0
14236# -----------------------------------------
14237# | 0 | e3 | e2 | e1 | e4 | X | X | X |
14238# -----------------------------------------
14239#
14240# And are moved into their proper places in FP_SCR0. If digit e4
14241# is non-zero, OPERR is signaled. In all cases, all 4 digits are
14242# written as specified in the 881/882 manual for packed decimal.
14243#
14244# Register usage:
14245# Input/Output
14246# d0: x/LEN call to binstr - final is 0
14247# d1: x/scratch (0);shift count for final exponent packing
14248# d2: x/ms 32-bits of exp fraction/scratch
14249# d3: x/ls 32-bits of exp fraction
14250# d4: LEN/Unchanged
14251# d5: ICTR:LAMBDA/LAMBDA:ICTR
14252# d6: ILOG
14253# d7: k-factor/Unchanged
14254# a0: ptr to result string/ptr to L_SCR1(a6)
14255# a1: ptr to PTENxx array/Unchanged
14256# a2: ptr to FP_SCR1(a6)/Unchanged
14257# fp0: abs(YINT) adjusted/float(ILOG)
14258# fp1: 10^ISCALE/Unchanged
14259# fp2: 10^LEN/Unchanged
14260# F_SCR1:Work area for final result/BCD result
14261# F_SCR2:Y with original exponent/ILOG/10^4
14262# L_SCR1:original USER_FPCR/Exponent digits on return from binstr
14263# L_SCR2:first word of X packed/Unchanged
14264
14265A15_st:
14266 tst.b BINDEC_FLG(%a6) # check for denorm
14267 beq.b not_denorm
14268 ftest.x %fp0 # test for zero
14269 fbeq.w den_zero # if zero, use k-factor or 4933
14270 fmov.l %d6,%fp0 # float ILOG
14271 fabs.x %fp0 # get abs of ILOG
14272 bra.b convrt
14273den_zero:
14274 tst.l %d7 # check sign of the k-factor
14275 blt.b use_ilog # if negative, use ILOG
14276 fmov.s F4933(%pc),%fp0 # force exponent to 4933
14277 bra.b convrt # do it
14278use_ilog:
14279 fmov.l %d6,%fp0 # float ILOG
14280 fabs.x %fp0 # get abs of ILOG
14281 bra.b convrt
14282not_denorm:
14283 ftest.x %fp0 # test for zero
14284 fbneq.w not_zero # if zero, force exponent
14285 fmov.s FONE(%pc),%fp0 # force exponent to 1
14286 bra.b convrt # do it
14287not_zero:
14288 fmov.l %d6,%fp0 # float ILOG
14289 fabs.x %fp0 # get abs of ILOG
14290convrt:
14291 fdiv.x 24(%a1),%fp0 # compute ILOG/10^4
14292 fmov.x %fp0,FP_SCR1(%a6) # store fp0 in memory
14293 mov.l 4(%a2),%d2 # move word 2 to d2
14294 mov.l 8(%a2),%d3 # move word 3 to d3
14295 mov.w (%a2),%d0 # move exp to d0
14296 beq.b x_loop_fin # if zero, skip the shift
14297 sub.w &0x3ffd,%d0 # subtract off bias
14298 neg.w %d0 # make exp positive
14299x_loop:
14300 lsr.l &1,%d2 # shift d2:d3 right
14301 roxr.l &1,%d3 # the number of places
14302 dbf.w %d0,x_loop # given in d0
14303x_loop_fin:
14304 clr.l %d1 # put zero in d1 for addx
14305 add.l &0x00000080,%d3 # inc at bit 6
14306 addx.l %d1,%d2 # continue inc
14307 and.l &0xffffff80,%d3 # strip off lsb not used by 882
14308 mov.l &4,%d0 # put 4 in d0 for binstr call
14309 lea.l L_SCR1(%a6),%a0 # a0 is ptr to L_SCR1 for exp digits
14310 bsr binstr # call binstr to convert exp
14311 mov.l L_SCR1(%a6),%d0 # load L_SCR1 lword to d0
14312 mov.l &12,%d1 # use d1 for shift count
14313 lsr.l %d1,%d0 # shift d0 right by 12
14314 bfins %d0,FP_SCR0(%a6){&4:&12} # put e3:e2:e1 in FP_SCR0
14315 lsr.l %d1,%d0 # shift d0 right by 12
14316 bfins %d0,FP_SCR0(%a6){&16:&4} # put e4 in FP_SCR0
14317 tst.b %d0 # check if e4 is zero
14318 beq.b A16_st # if zero, skip rest
14319 or.l &opaop_mask,USER_FPSR(%a6) # set OPERR & AIOP in USER_FPSR
14320
14321
14322# A16. Write sign bits to final string.
14323# Sigma is bit 31 of initial value; RHO is bit 31 of d6 (ILOG).
14324#
14325# Register usage:
14326# Input/Output
14327# d0: x/scratch - final is x
14328# d2: x/x
14329# d3: x/x
14330# d4: LEN/Unchanged
14331# d5: ICTR:LAMBDA/LAMBDA:ICTR
14332# d6: ILOG/ILOG adjusted
14333# d7: k-factor/Unchanged
14334# a0: ptr to L_SCR1(a6)/Unchanged
14335# a1: ptr to PTENxx array/Unchanged
14336# a2: ptr to FP_SCR1(a6)/Unchanged
14337# fp0: float(ILOG)/Unchanged
14338# fp1: 10^ISCALE/Unchanged
14339# fp2: 10^LEN/Unchanged
14340# F_SCR1:BCD result with correct signs
14341# F_SCR2:ILOG/10^4
14342# L_SCR1:Exponent digits on return from binstr
14343# L_SCR2:first word of X packed/Unchanged
14344
14345A16_st:
14346 clr.l %d0 # clr d0 for collection of signs
14347 and.b &0x0f,FP_SCR0(%a6) # clear first nibble of FP_SCR0
14348 tst.l L_SCR2(%a6) # check sign of original mantissa
14349 bge.b mant_p # if pos, don't set SM
14350 mov.l &2,%d0 # move 2 in to d0 for SM
14351mant_p:
14352 tst.l %d6 # check sign of ILOG
14353 bge.b wr_sgn # if pos, don't set SE
14354 addq.l &1,%d0 # set bit 0 in d0 for SE
14355wr_sgn:
14356 bfins %d0,FP_SCR0(%a6){&0:&2} # insert SM and SE into FP_SCR0
14357
14358# Clean up and restore all registers used.
14359
14360 fmov.l &0,%fpsr # clear possible inex2/ainex bits
14361 fmovm.x (%sp)+,&0xe0 # {%fp0-%fp2}
14362 movm.l (%sp)+,&0x4fc # {%d2-%d7/%a2}
14363 rts
14364
14365 global PTENRN
14366PTENRN:
14367 long 0x40020000,0xA0000000,0x00000000 # 10 ^ 1
14368 long 0x40050000,0xC8000000,0x00000000 # 10 ^ 2
14369 long 0x400C0000,0x9C400000,0x00000000 # 10 ^ 4
14370 long 0x40190000,0xBEBC2000,0x00000000 # 10 ^ 8
14371 long 0x40340000,0x8E1BC9BF,0x04000000 # 10 ^ 16
14372 long 0x40690000,0x9DC5ADA8,0x2B70B59E # 10 ^ 32
14373 long 0x40D30000,0xC2781F49,0xFFCFA6D5 # 10 ^ 64
14374 long 0x41A80000,0x93BA47C9,0x80E98CE0 # 10 ^ 128
14375 long 0x43510000,0xAA7EEBFB,0x9DF9DE8E # 10 ^ 256
14376 long 0x46A30000,0xE319A0AE,0xA60E91C7 # 10 ^ 512
14377 long 0x4D480000,0xC9767586,0x81750C17 # 10 ^ 1024
14378 long 0x5A920000,0x9E8B3B5D,0xC53D5DE5 # 10 ^ 2048
14379 long 0x75250000,0xC4605202,0x8A20979B # 10 ^ 4096
14380
14381 global PTENRP
14382PTENRP:
14383 long 0x40020000,0xA0000000,0x00000000 # 10 ^ 1
14384 long 0x40050000,0xC8000000,0x00000000 # 10 ^ 2
14385 long 0x400C0000,0x9C400000,0x00000000 # 10 ^ 4
14386 long 0x40190000,0xBEBC2000,0x00000000 # 10 ^ 8
14387 long 0x40340000,0x8E1BC9BF,0x04000000 # 10 ^ 16
14388 long 0x40690000,0x9DC5ADA8,0x2B70B59E # 10 ^ 32
14389 long 0x40D30000,0xC2781F49,0xFFCFA6D6 # 10 ^ 64
14390 long 0x41A80000,0x93BA47C9,0x80E98CE0 # 10 ^ 128
14391 long 0x43510000,0xAA7EEBFB,0x9DF9DE8E # 10 ^ 256
14392 long 0x46A30000,0xE319A0AE,0xA60E91C7 # 10 ^ 512
14393 long 0x4D480000,0xC9767586,0x81750C18 # 10 ^ 1024
14394 long 0x5A920000,0x9E8B3B5D,0xC53D5DE5 # 10 ^ 2048
14395 long 0x75250000,0xC4605202,0x8A20979B # 10 ^ 4096
14396
14397 global PTENRM
14398PTENRM:
14399 long 0x40020000,0xA0000000,0x00000000 # 10 ^ 1
14400 long 0x40050000,0xC8000000,0x00000000 # 10 ^ 2
14401 long 0x400C0000,0x9C400000,0x00000000 # 10 ^ 4
14402 long 0x40190000,0xBEBC2000,0x00000000 # 10 ^ 8
14403 long 0x40340000,0x8E1BC9BF,0x04000000 # 10 ^ 16
14404 long 0x40690000,0x9DC5ADA8,0x2B70B59D # 10 ^ 32
14405 long 0x40D30000,0xC2781F49,0xFFCFA6D5 # 10 ^ 64
14406 long 0x41A80000,0x93BA47C9,0x80E98CDF # 10 ^ 128
14407 long 0x43510000,0xAA7EEBFB,0x9DF9DE8D # 10 ^ 256
14408 long 0x46A30000,0xE319A0AE,0xA60E91C6 # 10 ^ 512
14409 long 0x4D480000,0xC9767586,0x81750C17 # 10 ^ 1024
14410 long 0x5A920000,0x9E8B3B5D,0xC53D5DE4 # 10 ^ 2048
14411 long 0x75250000,0xC4605202,0x8A20979A # 10 ^ 4096
14412
14413#########################################################################
14414# binstr(): Converts a 64-bit binary integer to bcd. #
14415# #
14416# INPUT *************************************************************** #
14417# d2:d3 = 64-bit binary integer #
14418# d0 = desired length (LEN) #
14419# a0 = pointer to start in memory for bcd characters #
14420# (This pointer must point to byte 4 of the first #
14421# lword of the packed decimal memory string.) #
14422# #
14423# OUTPUT ************************************************************** #
14424# a0 = pointer to LEN bcd digits representing the 64-bit integer. #
14425# #
14426# ALGORITHM *********************************************************** #
14427# The 64-bit binary is assumed to have a decimal point before #
14428# bit 63. The fraction is multiplied by 10 using a mul by 2 #
14429# shift and a mul by 8 shift. The bits shifted out of the #
14430# msb form a decimal digit. This process is iterated until #
14431# LEN digits are formed. #
14432# #
14433# A1. Init d7 to 1. D7 is the byte digit counter, and if 1, the #
14434# digit formed will be assumed the least significant. This is #
14435# to force the first byte formed to have a 0 in the upper 4 bits. #
14436# #
14437# A2. Beginning of the loop: #
14438# Copy the fraction in d2:d3 to d4:d5. #
14439# #
14440# A3. Multiply the fraction in d2:d3 by 8 using bit-field #
14441# extracts and shifts. The three msbs from d2 will go into d1. #
14442# #
14443# A4. Multiply the fraction in d4:d5 by 2 using shifts. The msb #
14444# will be collected by the carry. #
14445# #
14446# A5. Add using the carry the 64-bit quantities in d2:d3 and d4:d5 #
14447# into d2:d3. D1 will contain the bcd digit formed. #
14448# #
14449# A6. Test d7. If zero, the digit formed is the ms digit. If non- #
14450# zero, it is the ls digit. Put the digit in its place in the #
14451# upper word of d0. If it is the ls digit, write the word #
14452# from d0 to memory. #
14453# #
14454# A7. Decrement d6 (LEN counter) and repeat the loop until zero. #
14455# #
14456#########################################################################
14457
14458# Implementation Notes:
14459#
14460# The registers are used as follows:
14461#
14462# d0: LEN counter
14463# d1: temp used to form the digit
14464# d2: upper 32-bits of fraction for mul by 8
14465# d3: lower 32-bits of fraction for mul by 8
14466# d4: upper 32-bits of fraction for mul by 2
14467# d5: lower 32-bits of fraction for mul by 2
14468# d6: temp for bit-field extracts
14469# d7: byte digit formation word;digit count {0,1}
14470# a0: pointer into memory for packed bcd string formation
14471#
14472
14473 global binstr
14474binstr:
14475 movm.l &0xff00,-(%sp) # {%d0-%d7}
14476
14477#
14478# A1: Init d7
14479#
14480 mov.l &1,%d7 # init d7 for second digit
14481 subq.l &1,%d0 # for dbf d0 would have LEN+1 passes
14482#
14483# A2. Copy d2:d3 to d4:d5. Start loop.
14484#
14485loop:
14486 mov.l %d2,%d4 # copy the fraction before muls
14487 mov.l %d3,%d5 # to d4:d5
14488#
14489# A3. Multiply d2:d3 by 8; extract msbs into d1.
14490#
14491 bfextu %d2{&0:&3},%d1 # copy 3 msbs of d2 into d1
14492 asl.l &3,%d2 # shift d2 left by 3 places
14493 bfextu %d3{&0:&3},%d6 # copy 3 msbs of d3 into d6
14494 asl.l &3,%d3 # shift d3 left by 3 places
14495 or.l %d6,%d2 # or in msbs from d3 into d2
14496#
14497# A4. Multiply d4:d5 by 2; add carry out to d1.
14498#
14499 asl.l &1,%d5 # mul d5 by 2
14500 roxl.l &1,%d4 # mul d4 by 2
14501 swap %d6 # put 0 in d6 lower word
14502 addx.w %d6,%d1 # add in extend from mul by 2
14503#
14504# A5. Add mul by 8 to mul by 2. D1 contains the digit formed.
14505#
14506 add.l %d5,%d3 # add lower 32 bits
14507 nop # ERRATA FIX #13 (Rev. 1.2 6/6/90)
14508 addx.l %d4,%d2 # add with extend upper 32 bits
14509 nop # ERRATA FIX #13 (Rev. 1.2 6/6/90)
14510 addx.w %d6,%d1 # add in extend from add to d1
14511 swap %d6 # with d6 = 0; put 0 in upper word
14512#
14513# A6. Test d7 and branch.
14514#
14515 tst.w %d7 # if zero, store digit & to loop
14516 beq.b first_d # if non-zero, form byte & write
14517sec_d:
14518 swap %d7 # bring first digit to word d7b
14519 asl.w &4,%d7 # first digit in upper 4 bits d7b
14520 add.w %d1,%d7 # add in ls digit to d7b
14521 mov.b %d7,(%a0)+ # store d7b byte in memory
14522 swap %d7 # put LEN counter in word d7a
14523 clr.w %d7 # set d7a to signal no digits done
14524 dbf.w %d0,loop # do loop some more!
14525 bra.b end_bstr # finished, so exit
14526first_d:
14527 swap %d7 # put digit word in d7b
14528 mov.w %d1,%d7 # put new digit in d7b
14529 swap %d7 # put LEN counter in word d7a
14530 addq.w &1,%d7 # set d7a to signal first digit done
14531 dbf.w %d0,loop # do loop some more!
14532 swap %d7 # put last digit in string
14533 lsl.w &4,%d7 # move it to upper 4 bits
14534 mov.b %d7,(%a0)+ # store it in memory string
14535#
14536# Clean up and return with result in fp0.
14537#
14538end_bstr:
14539 movm.l (%sp)+,&0xff # {%d0-%d7}
14540 rts
14541
14542#########################################################################
14543# XDEF **************************************************************** #
14544# facc_in_b(): dmem_read_byte failed #
14545# facc_in_w(): dmem_read_word failed #
14546# facc_in_l(): dmem_read_long failed #
14547# facc_in_d(): dmem_read of dbl prec failed #
14548# facc_in_x(): dmem_read of ext prec failed #
14549# #
14550# facc_out_b(): dmem_write_byte failed #
14551# facc_out_w(): dmem_write_word failed #
14552# facc_out_l(): dmem_write_long failed #
14553# facc_out_d(): dmem_write of dbl prec failed #
14554# facc_out_x(): dmem_write of ext prec failed #
14555# #
14556# XREF **************************************************************** #
14557# _real_access() - exit through access error handler #
14558# #
14559# INPUT *************************************************************** #
14560# None #
14561# #
14562# OUTPUT ************************************************************** #
14563# None #
14564# #
14565# ALGORITHM *********************************************************** #
14566# Flow jumps here when an FP data fetch call gets an error #
14567# result. This means the operating system wants an access error frame #
14568# made out of the current exception stack frame. #
14569# So, we first call restore() which makes sure that any updated #
14570# -(an)+ register gets returned to its pre-exception value and then #
14571# we change the stack to an access error stack frame. #
14572# #
14573#########################################################################
14574
14575facc_in_b:
14576 movq.l &0x1,%d0 # one byte
14577 bsr.w restore # fix An
14578
14579 mov.w &0x0121,EXC_VOFF(%a6) # set FSLW
14580 bra.w facc_finish
14581
14582facc_in_w:
14583 movq.l &0x2,%d0 # two bytes
14584 bsr.w restore # fix An
14585
14586 mov.w &0x0141,EXC_VOFF(%a6) # set FSLW
14587 bra.b facc_finish
14588
14589facc_in_l:
14590 movq.l &0x4,%d0 # four bytes
14591 bsr.w restore # fix An
14592
14593 mov.w &0x0101,EXC_VOFF(%a6) # set FSLW
14594 bra.b facc_finish
14595
14596facc_in_d:
14597 movq.l &0x8,%d0 # eight bytes
14598 bsr.w restore # fix An
14599
14600 mov.w &0x0161,EXC_VOFF(%a6) # set FSLW
14601 bra.b facc_finish
14602
14603facc_in_x:
14604 movq.l &0xc,%d0 # twelve bytes
14605 bsr.w restore # fix An
14606
14607 mov.w &0x0161,EXC_VOFF(%a6) # set FSLW
14608 bra.b facc_finish
14609
14610################################################################
14611
14612facc_out_b:
14613 movq.l &0x1,%d0 # one byte
14614 bsr.w restore # restore An
14615
14616 mov.w &0x00a1,EXC_VOFF(%a6) # set FSLW
14617 bra.b facc_finish
14618
14619facc_out_w:
14620 movq.l &0x2,%d0 # two bytes
14621 bsr.w restore # restore An
14622
14623 mov.w &0x00c1,EXC_VOFF(%a6) # set FSLW
14624 bra.b facc_finish
14625
14626facc_out_l:
14627 movq.l &0x4,%d0 # four bytes
14628 bsr.w restore # restore An
14629
14630 mov.w &0x0081,EXC_VOFF(%a6) # set FSLW
14631 bra.b facc_finish
14632
14633facc_out_d:
14634 movq.l &0x8,%d0 # eight bytes
14635 bsr.w restore # restore An
14636
14637 mov.w &0x00e1,EXC_VOFF(%a6) # set FSLW
14638 bra.b facc_finish
14639
14640facc_out_x:
14641 mov.l &0xc,%d0 # twelve bytes
14642 bsr.w restore # restore An
14643
14644 mov.w &0x00e1,EXC_VOFF(%a6) # set FSLW
14645
14646# here's where we actually create the access error frame from the
14647# current exception stack frame.
14648facc_finish:
14649 mov.l USER_FPIAR(%a6),EXC_PC(%a6) # store current PC
14650
14651 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1
14652 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
14653 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1
14654
14655 unlk %a6
14656
14657 mov.l (%sp),-(%sp) # store SR, hi(PC)
14658 mov.l 0x8(%sp),0x4(%sp) # store lo(PC)
14659 mov.l 0xc(%sp),0x8(%sp) # store EA
14660 mov.l &0x00000001,0xc(%sp) # store FSLW
14661 mov.w 0x6(%sp),0xc(%sp) # fix FSLW (size)
14662 mov.w &0x4008,0x6(%sp) # store voff
14663
14664 btst &0x5,(%sp) # supervisor or user mode?
14665 beq.b facc_out2 # user
14666 bset &0x2,0xd(%sp) # set supervisor TM bit
14667
14668facc_out2:
14669 bra.l _real_access
14670
14671##################################################################
14672
14673# if the effective addressing mode was predecrement or postincrement,
14674# the emulation has already changed its value to the correct post-
14675# instruction value. but since we're exiting to the access error
14676# handler, then AN must be returned to its pre-instruction value.
14677# we do that here.
14678restore:
14679 mov.b EXC_OPWORD+0x1(%a6),%d1
14680 andi.b &0x38,%d1 # extract opmode
14681 cmpi.b %d1,&0x18 # postinc?
14682 beq.w rest_inc
14683 cmpi.b %d1,&0x20 # predec?
14684 beq.w rest_dec
14685 rts
14686
14687rest_inc:
14688 mov.b EXC_OPWORD+0x1(%a6),%d1
14689 andi.w &0x0007,%d1 # fetch An
14690
14691 mov.w (tbl_rest_inc.b,%pc,%d1.w*2),%d1
14692 jmp (tbl_rest_inc.b,%pc,%d1.w*1)
14693
14694tbl_rest_inc:
14695 short ri_a0 - tbl_rest_inc
14696 short ri_a1 - tbl_rest_inc
14697 short ri_a2 - tbl_rest_inc
14698 short ri_a3 - tbl_rest_inc
14699 short ri_a4 - tbl_rest_inc
14700 short ri_a5 - tbl_rest_inc
14701 short ri_a6 - tbl_rest_inc
14702 short ri_a7 - tbl_rest_inc
14703
14704ri_a0:
14705 sub.l %d0,EXC_DREGS+0x8(%a6) # fix stacked a0
14706 rts
14707ri_a1:
14708 sub.l %d0,EXC_DREGS+0xc(%a6) # fix stacked a1
14709 rts
14710ri_a2:
14711 sub.l %d0,%a2 # fix a2
14712 rts
14713ri_a3:
14714 sub.l %d0,%a3 # fix a3
14715 rts
14716ri_a4:
14717 sub.l %d0,%a4 # fix a4
14718 rts
14719ri_a5:
14720 sub.l %d0,%a5 # fix a5
14721 rts
14722ri_a6:
14723 sub.l %d0,(%a6) # fix stacked a6
14724 rts
14725# if it's a fmove out instruction, we don't have to fix a7
14726# because we hadn't changed it yet. if it's an opclass two
14727# instruction (data moved in) and the exception was in supervisor
14728# mode, then also also wasn't updated. if it was user mode, then
14729# restore the correct a7 which is in the USP currently.
14730ri_a7:
14731 cmpi.b EXC_VOFF(%a6),&0x30 # move in or out?
14732 bne.b ri_a7_done # out
14733
14734 btst &0x5,EXC_SR(%a6) # user or supervisor?
14735 bne.b ri_a7_done # supervisor
14736 movc %usp,%a0 # restore USP
14737 sub.l %d0,%a0
14738 movc %a0,%usp
14739ri_a7_done:
14740 rts
14741
14742# need to invert adjustment value if the <ea> was predec
14743rest_dec:
14744 neg.l %d0
14745 bra.b rest_inc