Merge branch 'master' of ssh://master.kernel.org/pub/scm/linux/kernel/git/linville...
[kernel.git] / arch / m68k / ifpsp060 / src / pfpsp.S
1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
3 M68000 Hi-Performance Microprocessor Division
4 M68060 Software Package
5 Production Release P1.00 -- October 10, 1994
6
7 M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.
8
9 THE SOFTWARE is provided on an "AS IS" basis and without warranty.
10 To the maximum extent permitted by applicable law,
11 MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
12 INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
13 and any warranty against infringement with regard to the SOFTWARE
14 (INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
15
16 To the maximum extent permitted by applicable law,
17 IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
18 (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
19 BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
20 ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
21 Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
22
23 You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
24 so long as this entire notice is retained without alteration in any modified and/or
25 redistributed versions, and that such modified versions are clearly identified as such.
26 No licenses are granted by implication, estoppel or otherwise under any patents
27 or 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
42 set     _off_bsun,      0x00
43 set     _off_snan,      0x04
44 set     _off_operr,     0x08
45 set     _off_ovfl,      0x0c
46 set     _off_unfl,      0x10
47 set     _off_dz,        0x14
48 set     _off_inex,      0x18
49 set     _off_fline,     0x1c
50 set     _off_fpu_dis,   0x20
51 set     _off_trap,      0x24
52 set     _off_trace,     0x28
53 set     _off_access,    0x2c
54 set     _off_done,      0x30
55
56 set     _off_imr,       0x40
57 set     _off_dmr,       0x44
58 set     _off_dmw,       0x48
59 set     _off_irw,       0x4c
60 set     _off_irl,       0x50
61 set     _off_drb,       0x54
62 set     _off_drw,       0x58
63 set     _off_drl,       0x5c
64 set     _off_dwb,       0x60
65 set     _off_dww,       0x64
66 set     _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
294 set LOCAL_SIZE,         192                     # stack frame size(bytes)
295 set LV,                 -LOCAL_SIZE             # stack offset
296
297 set EXC_SR,             0x4                     # stack status register
298 set EXC_PC,             0x6                     # stack pc
299 set EXC_VOFF,           0xa                     # stacked vector offset
300 set EXC_EA,             0xc                     # stacked <ea>
301
302 set EXC_FP,             0x0                     # frame pointer
303
304 set EXC_AREGS,          -68                     # offset of all address regs
305 set EXC_DREGS,          -100                    # offset of all data regs
306 set EXC_FPREGS,         -36                     # offset of all fp regs
307
308 set EXC_A7,             EXC_AREGS+(7*4)         # offset of saved a7
309 set OLD_A7,             EXC_AREGS+(6*4)         # extra copy of saved a7
310 set EXC_A6,             EXC_AREGS+(6*4)         # offset of saved a6
311 set EXC_A5,             EXC_AREGS+(5*4)
312 set EXC_A4,             EXC_AREGS+(4*4)
313 set EXC_A3,             EXC_AREGS+(3*4)
314 set EXC_A2,             EXC_AREGS+(2*4)
315 set EXC_A1,             EXC_AREGS+(1*4)
316 set EXC_A0,             EXC_AREGS+(0*4)
317 set EXC_D7,             EXC_DREGS+(7*4)
318 set EXC_D6,             EXC_DREGS+(6*4)
319 set EXC_D5,             EXC_DREGS+(5*4)
320 set EXC_D4,             EXC_DREGS+(4*4)
321 set EXC_D3,             EXC_DREGS+(3*4)
322 set EXC_D2,             EXC_DREGS+(2*4)
323 set EXC_D1,             EXC_DREGS+(1*4)
324 set EXC_D0,             EXC_DREGS+(0*4)
325
326 set EXC_FP0,            EXC_FPREGS+(0*12)       # offset of saved fp0
327 set EXC_FP1,            EXC_FPREGS+(1*12)       # offset of saved fp1
328 set EXC_FP2,            EXC_FPREGS+(2*12)       # offset of saved fp2 (not used)
329
330 set FP_SCR1,            LV+80                   # fp scratch 1
331 set FP_SCR1_EX,         FP_SCR1+0
332 set FP_SCR1_SGN,        FP_SCR1+2
333 set FP_SCR1_HI,         FP_SCR1+4
334 set FP_SCR1_LO,         FP_SCR1+8
335
336 set FP_SCR0,            LV+68                   # fp scratch 0
337 set FP_SCR0_EX,         FP_SCR0+0
338 set FP_SCR0_SGN,        FP_SCR0+2
339 set FP_SCR0_HI,         FP_SCR0+4
340 set FP_SCR0_LO,         FP_SCR0+8
341
342 set FP_DST,             LV+56                   # fp destination operand
343 set FP_DST_EX,          FP_DST+0
344 set FP_DST_SGN,         FP_DST+2
345 set FP_DST_HI,          FP_DST+4
346 set FP_DST_LO,          FP_DST+8
347
348 set FP_SRC,             LV+44                   # fp source operand
349 set FP_SRC_EX,          FP_SRC+0
350 set FP_SRC_SGN,         FP_SRC+2
351 set FP_SRC_HI,          FP_SRC+4
352 set FP_SRC_LO,          FP_SRC+8
353
354 set USER_FPIAR,         LV+40                   # FP instr address register
355
356 set USER_FPSR,          LV+36                   # FP status register
357 set FPSR_CC,            USER_FPSR+0             # FPSR condition codes
358 set FPSR_QBYTE,         USER_FPSR+1             # FPSR qoutient byte
359 set FPSR_EXCEPT,        USER_FPSR+2             # FPSR exception status byte
360 set FPSR_AEXCEPT,       USER_FPSR+3             # FPSR accrued exception byte
361
362 set USER_FPCR,          LV+32                   # FP control register
363 set FPCR_ENABLE,        USER_FPCR+2             # FPCR exception enable
364 set FPCR_MODE,          USER_FPCR+3             # FPCR rounding mode control
365
366 set L_SCR3,             LV+28                   # integer scratch 3
367 set L_SCR2,             LV+24                   # integer scratch 2
368 set L_SCR1,             LV+20                   # integer scratch 1
369
370 set STORE_FLG,          LV+19                   # flag: operand store (ie. not fcmp/ftst)
371
372 set EXC_TEMP2,          LV+24                   # temporary space
373 set EXC_TEMP,           LV+16                   # temporary space
374
375 set DTAG,               LV+15                   # destination operand type
376 set STAG,               LV+14                   # source operand type
377
378 set SPCOND_FLG,         LV+10                   # flag: special case (see below)
379
380 set EXC_CC,             LV+8                    # saved condition codes
381 set EXC_EXTWPTR,        LV+4                    # saved current PC (active)
382 set EXC_EXTWORD,        LV+2                    # saved extension word
383 set EXC_CMDREG,         LV+2                    # saved extension word
384 set EXC_OPWORD,         LV+0                    # saved operation word
385
386 ################################
387
388 # Helpful macros
389
390 set FTEMP,              0                       # offsets within an
391 set FTEMP_EX,           0                       # extended precision
392 set FTEMP_SGN,          2                       # value saved in memory.
393 set FTEMP_HI,           4
394 set FTEMP_LO,           8
395 set FTEMP_GRS,          12
396
397 set LOCAL,              0                       # offsets within an
398 set LOCAL_EX,           0                       # extended precision
399 set LOCAL_SGN,          2                       # value saved in memory.
400 set LOCAL_HI,           4
401 set LOCAL_LO,           8
402 set LOCAL_GRS,          12
403
404 set DST,                0                       # offsets within an
405 set DST_EX,             0                       # extended precision
406 set DST_HI,             4                       # value saved in memory.
407 set DST_LO,             8
408
409 set SRC,                0                       # offsets within an
410 set SRC_EX,             0                       # extended precision
411 set SRC_HI,             4                       # value saved in memory.
412 set SRC_LO,             8
413
414 set SGL_LO,             0x3f81                  # min sgl prec exponent
415 set SGL_HI,             0x407e                  # max sgl prec exponent
416 set DBL_LO,             0x3c01                  # min dbl prec exponent
417 set DBL_HI,             0x43fe                  # max dbl prec exponent
418 set EXT_LO,             0x0                     # min ext prec exponent
419 set EXT_HI,             0x7ffe                  # max ext prec exponent
420
421 set EXT_BIAS,           0x3fff                  # extended precision bias
422 set SGL_BIAS,           0x007f                  # single precision bias
423 set DBL_BIAS,           0x03ff                  # double precision bias
424
425 set NORM,               0x00                    # operand type for STAG/DTAG
426 set ZERO,               0x01                    # operand type for STAG/DTAG
427 set INF,                0x02                    # operand type for STAG/DTAG
428 set QNAN,               0x03                    # operand type for STAG/DTAG
429 set DENORM,             0x04                    # operand type for STAG/DTAG
430 set SNAN,               0x05                    # operand type for STAG/DTAG
431 set UNNORM,             0x06                    # operand type for STAG/DTAG
432
433 ##################
434 # FPSR/FPCR bits #
435 ##################
436 set neg_bit,            0x3                     # negative result
437 set z_bit,              0x2                     # zero result
438 set inf_bit,            0x1                     # infinite result
439 set nan_bit,            0x0                     # NAN result
440
441 set q_sn_bit,           0x7                     # sign bit of quotient byte
442
443 set bsun_bit,           7                       # branch on unordered
444 set snan_bit,           6                       # signalling NAN
445 set operr_bit,          5                       # operand error
446 set ovfl_bit,           4                       # overflow
447 set unfl_bit,           3                       # underflow
448 set dz_bit,             2                       # divide by zero
449 set inex2_bit,          1                       # inexact result 2
450 set inex1_bit,          0                       # inexact result 1
451
452 set aiop_bit,           7                       # accrued inexact operation bit
453 set aovfl_bit,          6                       # accrued overflow bit
454 set aunfl_bit,          5                       # accrued underflow bit
455 set adz_bit,            4                       # accrued dz bit
456 set ainex_bit,          3                       # accrued inexact bit
457
458 #############################
459 # FPSR individual bit masks #
460 #############################
461 set neg_mask,           0x08000000              # negative bit mask (lw)
462 set inf_mask,           0x02000000              # infinity bit mask (lw)
463 set z_mask,             0x04000000              # zero bit mask (lw)
464 set nan_mask,           0x01000000              # nan bit mask (lw)
465
466 set neg_bmask,          0x08                    # negative bit mask (byte)
467 set inf_bmask,          0x02                    # infinity bit mask (byte)
468 set z_bmask,            0x04                    # zero bit mask (byte)
469 set nan_bmask,          0x01                    # nan bit mask (byte)
470
471 set bsun_mask,          0x00008000              # bsun exception mask
472 set snan_mask,          0x00004000              # snan exception mask
473 set operr_mask,         0x00002000              # operr exception mask
474 set ovfl_mask,          0x00001000              # overflow exception mask
475 set unfl_mask,          0x00000800              # underflow exception mask
476 set dz_mask,            0x00000400              # dz exception mask
477 set inex2_mask,         0x00000200              # inex2 exception mask
478 set inex1_mask,         0x00000100              # inex1 exception mask
479
480 set aiop_mask,          0x00000080              # accrued illegal operation
481 set aovfl_mask,         0x00000040              # accrued overflow
482 set aunfl_mask,         0x00000020              # accrued underflow
483 set adz_mask,           0x00000010              # accrued divide by zero
484 set ainex_mask,         0x00000008              # accrued inexact
485
486 ######################################
487 # FPSR combinations used in the FPSP #
488 ######################################
489 set dzinf_mask,         inf_mask+dz_mask+adz_mask
490 set opnan_mask,         nan_mask+operr_mask+aiop_mask
491 set nzi_mask,           0x01ffffff              #clears N, Z, and I
492 set unfinx_mask,        unfl_mask+inex2_mask+aunfl_mask+ainex_mask
493 set unf2inx_mask,       unfl_mask+inex2_mask+ainex_mask
494 set ovfinx_mask,        ovfl_mask+inex2_mask+aovfl_mask+ainex_mask
495 set inx1a_mask,         inex1_mask+ainex_mask
496 set inx2a_mask,         inex2_mask+ainex_mask
497 set snaniop_mask,       nan_mask+snan_mask+aiop_mask
498 set snaniop2_mask,      snan_mask+aiop_mask
499 set naniop_mask,        nan_mask+aiop_mask
500 set neginf_mask,        neg_mask+inf_mask
501 set infaiop_mask,       inf_mask+aiop_mask
502 set negz_mask,          neg_mask+z_mask
503 set opaop_mask,         operr_mask+aiop_mask
504 set unfl_inx_mask,      unfl_mask+aunfl_mask+ainex_mask
505 set ovfl_inx_mask,      ovfl_mask+aovfl_mask+ainex_mask
506
507 #########
508 # misc. #
509 #########
510 set rnd_stky_bit,       29                      # stky bit pos in longword
511
512 set sign_bit,           0x7                     # sign bit
513 set signan_bit,         0x6                     # signalling nan bit
514
515 set sgl_thresh,         0x3f81                  # minimum sgl exponent
516 set dbl_thresh,         0x3c01                  # minimum dbl exponent
517
518 set x_mode,             0x0                     # extended precision
519 set s_mode,             0x4                     # single precision
520 set d_mode,             0x8                     # double precision
521
522 set rn_mode,            0x0                     # round-to-nearest
523 set rz_mode,            0x1                     # round-to-zero
524 set rm_mode,            0x2                     # round-tp-minus-infinity
525 set rp_mode,            0x3                     # round-to-plus-infinity
526
527 set mantissalen,        64                      # length of mantissa in bits
528
529 set BYTE,               1                       # len(byte) == 1 byte
530 set WORD,               2                       # len(word) == 2 bytes
531 set LONG,               4                       # len(longword) == 2 bytes
532
533 set BSUN_VEC,           0xc0                    # bsun    vector offset
534 set INEX_VEC,           0xc4                    # inexact vector offset
535 set DZ_VEC,             0xc8                    # dz      vector offset
536 set UNFL_VEC,           0xcc                    # unfl    vector offset
537 set OPERR_VEC,          0xd0                    # operr   vector offset
538 set OVFL_VEC,           0xd4                    # ovfl    vector offset
539 set SNAN_VEC,           0xd8                    # snan    vector offset
540
541 ###########################
542 # SPecial CONDition FLaGs #
543 ###########################
544 set ftrapcc_flg,        0x01                    # flag bit: ftrapcc exception
545 set fbsun_flg,          0x02                    # flag bit: bsun exception
546 set mia7_flg,           0x04                    # flag bit: (a7)+ <ea>
547 set mda7_flg,           0x08                    # flag bit: -(a7) <ea>
548 set fmovm_flg,          0x40                    # flag bit: fmovm instruction
549 set immed_flg,          0x80                    # flag bit: &<data> <ea>
550
551 set ftrapcc_bit,        0x0
552 set fbsun_bit,          0x1
553 set mia7_bit,           0x2
554 set mda7_bit,           0x3
555 set immed_bit,          0x7
556
557 ##################################
558 # TRANSCENDENTAL "LAST-OP" FLAGS #
559 ##################################
560 set FMUL_OP,            0x0                     # fmul instr performed last
561 set FDIV_OP,            0x1                     # fdiv performed last
562 set FADD_OP,            0x2                     # fadd performed last
563 set FMOV_OP,            0x3                     # fmov performed last
564
565 #############
566 # CONSTANTS #
567 #############
568 T1:     long            0x40C62D38,0xD3D64634   # 16381 LOG2 LEAD
569 T2:     long            0x3D6F90AE,0xB1E75CC7   # 16381 LOG2 TRAIL
570
571 PI:     long            0x40000000,0xC90FDAA2,0x2168C235,0x00000000
572 PIBY2:  long            0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000
573
574 TWOBYPI:
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
684 fovfl_op2_done:
685         mov.b           %d0,DTAG(%a6)           # save dst optype tag
686
687 fovfl_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()!
740 fovfl_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().
757 fovfl_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 ########################################################################
775 fovfl_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
927 funfl_op2_done:
928         mov.b           %d0,DTAG(%a6)           # save dst optype tag
929
930 funfl_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
975 funfl_chkinex:
976         btst            &inex2_bit,FPCR_ENABLE(%a6)
977         bne.b           funfl_inex_on
978
979 funfl_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()!
991 funfl_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
1002 funfl_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 # underflow occurred but is disabled. meanwhile, inexact is enabled. Therefore,
1018 # we must jump to real_inex().
1019 funfl_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
1031 funfl_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 #######################################################################
1049 funfl_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
1215 fu_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.
1222 fu_s:
1223         lea             0x4+EXC_EA(%a6),%a0     # load old a7'
1224         mov.l           %a0,EXC_A7(%a6)         # save on stack
1225
1226 fu_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
1274 fu_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
1293 fu_op2_done:
1294         mov.b           %d0,DTAG(%a6)           # save dst optype tag
1295
1296 fu_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
1325 fu_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
1335 fu_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
1345 fu_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
1363 fu_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 #
1383 fu_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.
1397 fu_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
1414 tbl_except:
1415         short           0xe000,0xe006,0xe004,0xe005
1416         short           0xe003,0xe002,0xe001,0xe001
1417
1418 fu_in_exc_unfl:
1419         mov.w           &0x4,%d0
1420         bra.b           fu_in_exc_exit
1421 fu_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
1430 fix_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
1438 fso_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
1447 fso_sgl_dnrm_zero:
1448         andi.l          &0x7fffffff,LOCAL_HI(%a0) # clear j-bit
1449         beq.b           fso_zero                # it's a skewed zero
1450 fso_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
1459 fso_zero:
1460         andi.w          &0x8000,LOCAL_EX(%a0)   # clear bogus exponent
1461         rts
1462
1463 fso_infnan:
1464         andi.b          &0x7f,LOCAL_HI(%a0)     # clear j-bit
1465         ori.w           &0x7fff,LOCAL_EX(%a0)   # make exponent = $7fff
1466         rts
1467
1468 fso_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
1477 fso_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
1482 fso_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.
1496 fu_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
1526 fu_out_denorm:
1527         mov.b           &DENORM,STAG(%a6)
1528 fu_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
1553 fu_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
1568 fu_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,
1582 fu_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
1614 fu_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
1625 fu_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 #
1648 fu_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.
1654 fu_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
1663 tbl_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.
1675 fu_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
1690 fu_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
1705 fu_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
1725 fu_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
1734 fu_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
1750 fu_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.
1786 fu_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 #########################################################################
1805 fu_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
1838 fu_op2_done_p:
1839         mov.b           %d0,DTAG(%a6)           # save dst optype tag
1840
1841 fu_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
1870 fu_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
1880 fu_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
1888 fu_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".
1903 fu_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
1923 fu_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
1941 fu_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 #
1961 fu_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!!!
1978 fu_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
1985 fu_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
2001 tbl_except_p:
2002         short           0xe000,0xe006,0xe004,0xe005
2003         short           0xe003,0xe002,0xe001,0xe001
2004
2005 fu_in_exc_ovfl_p:
2006         mov.w           &0x3,%d0
2007         bra.w           fu_in_exc_exit_p
2008
2009 fu_in_exc_unfl_p:
2010         mov.w           &0x4,%d0
2011         bra.w           fu_in_exc_exit_p
2012
2013 fu_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 #               *****************       *****************
2054 fu_trace_p:
2055         mov.w           &0x2024,0x6(%sp)
2056         fmov.l          %fpiar,0x8(%sp)
2057
2058         bra.l           _real_trace
2059
2060 #########################################################
2061 #########################################################
2062 fu_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
2084 fu_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
2110 fu_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
2119 fu_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".
2134 fu_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
2159 fu_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.
2168 fu_out_exc_p:
2169         cmpi.b          %d0,&0x1a
2170         bgt.w           fu_inex_p2
2171         beq.w           fu_operr_p
2172
2173 fu_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
2181 fu_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
2213 fu_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
2221 fu_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
2253 fu_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
2261 fu_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
2301 funimp_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
2309 funimp_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
2323 funimp_skew_sgl_not:
2324         rts
2325
2326 funimp_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
2344 fss_dbl_denorm_done:
2345         bset            &0x7,FP_SRC_HI(%a6)     # set j-bit
2346         mov.w           %d0,FP_SRC_EX(%a6)      # insert new exponent
2347 funimp_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 #
2501 iea_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
2518 iea_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
2542 iea_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
2547 iea_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
2558 iea_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
2566 iea_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
2580 iea_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
2589 iea_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.
2624 iea_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
2628 iea_op_store:
2629         bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno
2630         bsr.l           store_fpreg             # store the result
2631
2632 iea_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
2647 iea_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
2657 iea_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.
2664 iea_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
2677 iea_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
2681 tbl_iea_except:
2682         short           0xe002, 0xe006, 0xe004, 0xe005
2683         short           0xe003, 0xe002, 0xe001, 0xe001
2684
2685 iea_op_exc_ovfl:
2686         mov.w           &0xe005,2+FP_SRC(%a6)
2687         bra.b           iea_op_exit2
2688
2689 iea_op_exc_unfl:
2690         mov.w           &0xe003,2+FP_SRC(%a6)
2691
2692 iea_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 #                                       *****************
2726 iea_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 #########################################################################
2735 iea_fmovm:
2736         btst            &14,%d0                 # ctrl or data reg
2737         beq.w           iea_fmovm_ctrl
2738
2739 iea_fmovm_data:
2740
2741         btst            &0x5,EXC_SR(%a6)        # user or supervisor mode
2742         bne.b           iea_fmovm_data_s
2743
2744 iea_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
2752 iea_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.
2767 iea_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
2786 iea_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.
2804 iea_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
2832 iea_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
2839 iea_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
2847 fm_1:
2848         lsl.b           &0x1,%d1
2849         bpl.b           fm_2
2850         fmovm.x         &0x40,(0x4+0x8,%a6,%d0)
2851         addi.l          &0xc,%d0
2852 fm_2:
2853         lsl.b           &0x1,%d1
2854         bpl.b           fm_3
2855         fmovm.x         &0x20,(0x4+0x8,%a6,%d0)
2856         addi.l          &0xc,%d0
2857 fm_3:
2858         lsl.b           &0x1,%d1
2859         bpl.b           fm_4
2860         fmovm.x         &0x10,(0x4+0x8,%a6,%d0)
2861         addi.l          &0xc,%d0
2862 fm_4:
2863         lsl.b           &0x1,%d1
2864         bpl.b           fm_5
2865         fmovm.x         &0x08,(0x4+0x8,%a6,%d0)
2866         addi.l          &0xc,%d0
2867 fm_5:
2868         lsl.b           &0x1,%d1
2869         bpl.b           fm_6
2870         fmovm.x         &0x04,(0x4+0x8,%a6,%d0)
2871         addi.l          &0xc,%d0
2872 fm_6:
2873         lsl.b           &0x1,%d1
2874         bpl.b           fm_7
2875         fmovm.x         &0x02,(0x4+0x8,%a6,%d0)
2876         addi.l          &0xc,%d0
2877 fm_7:
2878         lsl.b           &0x1,%d1
2879         bpl.b           fm_end
2880         fmovm.x         &0x01,(0x4+0x8,%a6,%d0)
2881 fm_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 #########################################################################
2892 iea_fmovm_ctrl:
2893
2894         bsr.l           fmovm_ctrl              # load ctrl regs
2895
2896 iea_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
2932 iea_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.
2949 iea_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.
2967 iea_dis_immed:
2968         mov.l           &0x10,%d0               # 16 bytes of instruction
2969         bra.b           iea_dis_cont
2970 iea_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.
2984 iea_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
2989 iea_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
3014 iea_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
3020 iea_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