51b9f7d879dd714d677b9c04fd0ac0a3795316a7
[linux-2.6.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 # undeflow 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
3029         mov.l           0x2(%sp),0x8(%sp)       # store ea
3030         mov.l           &0x09428001,0xc(%sp)    # store fslw
3031
3032 iea_acc_done:
3033         btst            &0x5,(%sp)              # user or supervisor mode?
3034         beq.b           iea_acc_done2           # user
3035         bset            &0x2,0xd(%sp)           # set supervisor TM bit
3036
3037 iea_acc_done2:
3038         bra.l           _real_access
3039
3040 iea_dacc:
3041         lea             -LOCAL_SIZE(%a6),%sp
3042
3043         movc            %pcr,%d1
3044         btst            &0x1,%d1
3045         bne.b           iea_dacc_cont
3046         fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1 on stack
3047         fmovm.l         LOCAL_SIZE+USER_FPCR(%sp),%fpcr,%fpsr,%fpiar # restore ctrl regs
3048 iea_dacc_cont:
3049         mov.l           (%a6),%a6
3050
3051         mov.l           0x4+LOCAL_SIZE(%sp),-0x8+0x4+LOCAL_SIZE(%sp)
3052         mov.w           0x8+LOCAL_SIZE(%sp),-0x8+0x8+LOCAL_SIZE(%sp)
3053         mov.w           &0x4008,-0x8+0xa+LOCAL_SIZE(%sp)
3054         mov.l           %a0,-0x8+0xc+LOCAL_SIZE(%sp)
3055         mov.w           %d0,-0x8+0x10+LOCAL_SIZE(%sp)
3056         mov.w           &0x0001,-0x8+0x12+LOCAL_SIZE(%sp)
3057
3058         movm.l          LOCAL_SIZE+EXC_DREGS(%sp),&0x0303 # restore d0-d1/a0-a1
3059         add.w           &LOCAL_SIZE-0x4,%sp
3060
3061         bra.b           iea_acc_done
3062
3063 #########################################################################
3064 # XDEF **************************************************************** #
3065 #       _fpsp_operr(): 060FPSP entry point for FP Operr exception.      #
3066 #                                                                       #
3067 #       This handler should be the first code executed upon taking the  #
3068 #       FP Operand Error exception in an operating system.              #
3069 #                                                                       #
3070 # XREF **************************************************************** #
3071 #       _imem_read_long() - read instruction longword                   #
3072 #       fix_skewed_ops() - adjust src operand in fsave frame            #
3073 #       _real_operr() - "callout" to operating system operr handler     #
3074 #       _dmem_write_{byte,word,long}() - store data to mem (opclass 3)  #
3075 #       store_dreg_{b,w,l}() - store data to data regfile (opclass 3)   #
3076 #       facc_out_{b,w,l}() - store to memory took access error (opcl 3) #
3077 #                                                                       #
3078 # INPUT *************************************************************** #
3079 #       - The system stack contains the FP Operr exception frame        #
3080 #       - The fsave frame contains the source operand                   #
3081 #                                                                       #
3082 # OUTPUT ************************************************************** #
3083 #       No access error:                                                #
3084 #       - The system stack is unchanged                                 #
3085 #       - The fsave frame contains the adjusted src op for opclass 0,2  #
3086 #                                                                       #
3087 # ALGORITHM *********************************************************** #
3088 #       In a system where the FP Operr exception is enabled, the goal   #
3089 # is to get to the handler specified at _real_operr(). But, on the 060, #
3090 # for opclass zero and two instruction taking this exception, the       #
3091 # input operand in the fsave frame may be incorrect for some cases      #
3092 # and needs to be corrected. This handler calls fix_skewed_ops() to     #
3093 # do just this and then exits through _real_operr().                    #
3094 #       For opclass 3 instructions, the 060 doesn't store the default   #
3095 # operr result out to memory or data register file as it should.        #
3096 # This code must emulate the move out before finally exiting through    #
3097 # _real_inex(). The move out, if to memory, is performed using          #
3098 # _mem_write() "callout" routines that may return a failing result.     #
3099 # In this special case, the handler must exit through facc_out()        #
3100 # which creates an access error stack frame from the current operr      #
3101 # stack frame.                                                          #
3102 #                                                                       #
3103 #########################################################################
3104
3105         global          _fpsp_operr
3106 _fpsp_operr:
3107
3108         link.w          %a6,&-LOCAL_SIZE        # init stack frame
3109
3110         fsave           FP_SRC(%a6)             # grab the "busy" frame
3111
3112         movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3113         fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3114         fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
3115
3116 # the FPIAR holds the "current PC" of the faulting instruction
3117         mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3118
3119         mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3120         addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3121         bsr.l           _imem_read_long         # fetch the instruction words
3122         mov.l           %d0,EXC_OPWORD(%a6)
3123
3124 ##############################################################################
3125
3126         btst            &13,%d0                 # is instr an fmove out?
3127         bne.b           foperr_out              # fmove out
3128
3129
3130 # here, we simply see if the operand in the fsave frame needs to be "unskewed".
3131 # this would be the case for opclass two operations with a source infinity or
3132 # denorm operand in the sgl or dbl format. NANs also become skewed, but can't
3133 # cause an operr so we don't need to check for them here.
3134         lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3135         bsr.l           fix_skewed_ops          # fix src op
3136
3137 foperr_exit:
3138         fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3139         fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3140         movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3141
3142         frestore        FP_SRC(%a6)
3143
3144         unlk            %a6
3145         bra.l           _real_operr
3146
3147 ########################################################################
3148
3149 #
3150 # the hardware does not save the default result to memory on enabled
3151 # operand error exceptions. we do this here before passing control to
3152 # the user operand error handler.
3153 #
3154 # byte, word, and long destination format operations can pass
3155 # through here. we simply need to test the sign of the src
3156 # operand and save the appropriate minimum or maximum integer value
3157 # to the effective address as pointed to by the stacked effective address.
3158 #
3159 # although packed opclass three operations can take operand error
3160 # exceptions, they won't pass through here since they are caught
3161 # first by the unsupported data format exception handler. that handler
3162 # sends them directly to _real_operr() if necessary.
3163 #
3164 foperr_out:
3165
3166         mov.w           FP_SRC_EX(%a6),%d1      # fetch exponent
3167         andi.w          &0x7fff,%d1
3168         cmpi.w          %d1,&0x7fff
3169         bne.b           foperr_out_not_qnan
3170 # the operand is either an infinity or a QNAN.
3171         tst.l           FP_SRC_LO(%a6)
3172         bne.b           foperr_out_qnan
3173         mov.l           FP_SRC_HI(%a6),%d1
3174         andi.l          &0x7fffffff,%d1
3175         beq.b           foperr_out_not_qnan
3176 foperr_out_qnan:
3177         mov.l           FP_SRC_HI(%a6),L_SCR1(%a6)
3178         bra.b           foperr_out_jmp
3179
3180 foperr_out_not_qnan:
3181         mov.l           &0x7fffffff,%d1
3182         tst.b           FP_SRC_EX(%a6)
3183         bpl.b           foperr_out_not_qnan2
3184         addq.l          &0x1,%d1
3185 foperr_out_not_qnan2:
3186         mov.l           %d1,L_SCR1(%a6)
3187
3188 foperr_out_jmp:
3189         bfextu          %d0{&19:&3},%d0         # extract dst format field
3190         mov.b           1+EXC_OPWORD(%a6),%d1   # extract <ea> mode,reg
3191         mov.w           (tbl_operr.b,%pc,%d0.w*2),%a0
3192         jmp             (tbl_operr.b,%pc,%a0)
3193
3194 tbl_operr:
3195         short           foperr_out_l - tbl_operr # long word integer
3196         short           tbl_operr    - tbl_operr # sgl prec shouldn't happen
3197         short           tbl_operr    - tbl_operr # ext prec shouldn't happen
3198         short           foperr_exit  - tbl_operr # packed won't enter here
3199         short           foperr_out_w - tbl_operr # word integer
3200         short           tbl_operr    - tbl_operr # dbl prec shouldn't happen
3201         short           foperr_out_b - tbl_operr # byte integer
3202         short           tbl_operr    - tbl_operr # packed won't enter here
3203
3204 foperr_out_b:
3205         mov.b           L_SCR1(%a6),%d0         # load positive default result
3206         cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3207         ble.b           foperr_out_b_save_dn    # yes
3208         mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3209         bsr.l           _dmem_write_byte        # write the default result
3210
3211         tst.l           %d1                     # did dstore fail?
3212         bne.l           facc_out_b              # yes
3213
3214         bra.w           foperr_exit
3215 foperr_out_b_save_dn:
3216         andi.w          &0x0007,%d1
3217         bsr.l           store_dreg_b            # store result to regfile
3218         bra.w           foperr_exit
3219
3220 foperr_out_w:
3221         mov.w           L_SCR1(%a6),%d0         # load positive default result
3222         cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3223         ble.b           foperr_out_w_save_dn    # yes
3224         mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3225         bsr.l           _dmem_write_word        # write the default result
3226
3227         tst.l           %d1                     # did dstore fail?
3228         bne.l           facc_out_w              # yes
3229
3230         bra.w           foperr_exit
3231 foperr_out_w_save_dn:
3232         andi.w          &0x0007,%d1
3233         bsr.l           store_dreg_w            # store result to regfile
3234         bra.w           foperr_exit
3235
3236 foperr_out_l:
3237         mov.l           L_SCR1(%a6),%d0         # load positive default result
3238         cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3239         ble.b           foperr_out_l_save_dn    # yes
3240         mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3241         bsr.l           _dmem_write_long        # write the default result
3242
3243         tst.l           %d1                     # did dstore fail?
3244         bne.l           facc_out_l              # yes
3245
3246         bra.w           foperr_exit
3247 foperr_out_l_save_dn:
3248         andi.w          &0x0007,%d1
3249         bsr.l           store_dreg_l            # store result to regfile
3250         bra.w           foperr_exit
3251
3252 #########################################################################
3253 # XDEF **************************************************************** #
3254 #       _fpsp_snan(): 060FPSP entry point for FP SNAN exception.        #
3255 #                                                                       #
3256 #       This handler should be the first code executed upon taking the  #
3257 #       FP Signalling NAN exception in an operating system.             #
3258 #                                                                       #
3259 # XREF **************************************************************** #
3260 #       _imem_read_long() - read instruction longword                   #
3261 #       fix_skewed_ops() - adjust src operand in fsave frame            #
3262 #       _real_snan() - "callout" to operating system SNAN handler       #
3263 #       _dmem_write_{byte,word,long}() - store data to mem (opclass 3)  #
3264 #       store_dreg_{b,w,l}() - store data to data regfile (opclass 3)   #
3265 #       facc_out_{b,w,l,d,x}() - store to mem took acc error (opcl 3)   #
3266 #       _calc_ea_fout() - fix An if <ea> is -() or ()+; also get <ea>   #
3267 #                                                                       #
3268 # INPUT *************************************************************** #
3269 #       - The system stack contains the FP SNAN exception frame         #
3270 #       - The fsave frame contains the source operand                   #
3271 #                                                                       #
3272 # OUTPUT ************************************************************** #
3273 #       No access error:                                                #
3274 #       - The system stack is unchanged                                 #
3275 #       - The fsave frame contains the adjusted src op for opclass 0,2  #
3276 #                                                                       #
3277 # ALGORITHM *********************************************************** #
3278 #       In a system where the FP SNAN exception is enabled, the goal    #
3279 # is to get to the handler specified at _real_snan(). But, on the 060,  #
3280 # for opclass zero and two instructions taking this exception, the      #
3281 # input operand in the fsave frame may be incorrect for some cases      #
3282 # and needs to be corrected. This handler calls fix_skewed_ops() to     #
3283 # do just this and then exits through _real_snan().                     #
3284 #       For opclass 3 instructions, the 060 doesn't store the default   #
3285 # SNAN result out to memory or data register file as it should.         #
3286 # This code must emulate the move out before finally exiting through    #
3287 # _real_snan(). The move out, if to memory, is performed using          #
3288 # _mem_write() "callout" routines that may return a failing result.     #
3289 # In this special case, the handler must exit through facc_out()        #
3290 # which creates an access error stack frame from the current SNAN       #
3291 # stack frame.                                                          #
3292 #       For the case of an extended precision opclass 3 instruction,    #
3293 # if the effective addressing mode was -() or ()+, then the address     #
3294 # register must get updated by calling _calc_ea_fout(). If the <ea>     #
3295 # was -(a7) from supervisor mode, then the exception frame currently    #
3296 # on the system stack must be carefully moved "down" to make room       #
3297 # for the operand being moved.                                          #
3298 #                                                                       #
3299 #########################################################################
3300
3301         global          _fpsp_snan
3302 _fpsp_snan:
3303
3304         link.w          %a6,&-LOCAL_SIZE        # init stack frame
3305
3306         fsave           FP_SRC(%a6)             # grab the "busy" frame
3307
3308         movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3309         fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3310         fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
3311
3312 # the FPIAR holds the "current PC" of the faulting instruction
3313         mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3314
3315         mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3316         addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3317         bsr.l           _imem_read_long         # fetch the instruction words
3318         mov.l           %d0,EXC_OPWORD(%a6)
3319
3320 ##############################################################################
3321
3322         btst            &13,%d0                 # is instr an fmove out?
3323         bne.w           fsnan_out               # fmove out
3324
3325
3326 # here, we simply see if the operand in the fsave frame needs to be "unskewed".
3327 # this would be the case for opclass two operations with a source infinity or
3328 # denorm operand in the sgl or dbl format. NANs also become skewed and must be
3329 # fixed here.
3330         lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3331         bsr.l           fix_skewed_ops          # fix src op
3332
3333 fsnan_exit:
3334         fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3335         fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3336         movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3337
3338         frestore        FP_SRC(%a6)
3339
3340         unlk            %a6
3341         bra.l           _real_snan
3342
3343 ########################################################################
3344
3345 #
3346 # the hardware does not save the default result to memory on enabled
3347 # snan exceptions. we do this here before passing control to
3348 # the user snan handler.
3349 #
3350 # byte, word, long, and packed destination format operations can pass
3351 # through here. since packed format operations already were handled by
3352 # fpsp_unsupp(), then we need to do nothing else for them here.
3353 # for byte, word, and long, we simply need to test the sign of the src
3354 # operand and save the appropriate minimum or maximum integer value
3355 # to the effective address as pointed to by the stacked effective address.
3356 #
3357 fsnan_out:
3358
3359         bfextu          %d0{&19:&3},%d0         # extract dst format field
3360         mov.b           1+EXC_OPWORD(%a6),%d1   # extract <ea> mode,reg
3361         mov.w           (tbl_snan.b,%pc,%d0.w*2),%a0
3362         jmp             (tbl_snan.b,%pc,%a0)
3363
3364 tbl_snan:
3365         short           fsnan_out_l - tbl_snan # long word integer
3366         short           fsnan_out_s - tbl_snan # sgl prec shouldn't happen
3367         short           fsnan_out_x - tbl_snan # ext prec shouldn't happen
3368         short           tbl_snan    - tbl_snan # packed needs no help
3369         short           fsnan_out_w - tbl_snan # word integer
3370         short           fsnan_out_d - tbl_snan # dbl prec shouldn't happen
3371         short           fsnan_out_b - tbl_snan # byte integer
3372         short           tbl_snan    - tbl_snan # packed needs no help
3373
3374 fsnan_out_b:
3375         mov.b           FP_SRC_HI(%a6),%d0      # load upper byte of SNAN
3376         bset            &6,%d0                  # set SNAN bit
3377         cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3378         ble.b           fsnan_out_b_dn          # yes
3379         mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3380         bsr.l           _dmem_write_byte        # write the default result
3381
3382         tst.l           %d1                     # did dstore fail?
3383         bne.l           facc_out_b              # yes
3384
3385         bra.w           fsnan_exit
3386 fsnan_out_b_dn:
3387         andi.w          &0x0007,%d1
3388         bsr.l           store_dreg_b            # store result to regfile
3389         bra.w           fsnan_exit
3390
3391 fsnan_out_w:
3392         mov.w           FP_SRC_HI(%a6),%d0      # load upper word of SNAN
3393         bset            &14,%d0                 # set SNAN bit
3394         cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3395         ble.b           fsnan_out_w_dn          # yes
3396         mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3397         bsr.l           _dmem_write_word        # write the default result
3398
3399         tst.l           %d1                     # did dstore fail?
3400         bne.l           facc_out_w              # yes
3401
3402         bra.w           fsnan_exit
3403 fsnan_out_w_dn:
3404         andi.w          &0x0007,%d1
3405         bsr.l           store_dreg_w            # store result to regfile
3406         bra.w           fsnan_exit
3407
3408 fsnan_out_l:
3409         mov.l           FP_SRC_HI(%a6),%d0      # load upper longword of SNAN
3410         bset            &30,%d0                 # set SNAN bit
3411         cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3412         ble.b           fsnan_out_l_dn          # yes
3413         mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3414         bsr.l           _dmem_write_long        # write the default result
3415
3416         tst.l           %d1                     # did dstore fail?
3417         bne.l           facc_out_l              # yes
3418
3419         bra.w           fsnan_exit
3420 fsnan_out_l_dn:
3421         andi.w          &0x0007,%d1
3422         bsr.l           store_dreg_l            # store result to regfile
3423         bra.w           fsnan_exit
3424
3425 fsnan_out_s:
3426         cmpi.b          %d1,&0x7                # is <ea> mode a data reg?
3427         ble.b           fsnan_out_d_dn          # yes
3428         mov.l           FP_SRC_EX(%a6),%d0      # fetch SNAN sign
3429         andi.l          &0x80000000,%d0         # keep sign
3430         ori.l           &0x7fc00000,%d0         # insert new exponent,SNAN bit
3431         mov.l           FP_SRC_HI(%a6),%d1      # load mantissa
3432         lsr.l           &0x8,%d1                # shift mantissa for sgl
3433         or.l            %d1,%d0                 # create sgl SNAN
3434         mov.l           EXC_EA(%a6),%a0         # pass: <ea> of default result
3435         bsr.l           _dmem_write_long        # write the default result
3436
3437         tst.l           %d1                     # did dstore fail?
3438         bne.l           facc_out_l              # yes
3439
3440         bra.w           fsnan_exit
3441 fsnan_out_d_dn:
3442         mov.l           FP_SRC_EX(%a6),%d0      # fetch SNAN sign
3443         andi.l          &0x80000000,%d0         # keep sign
3444         ori.l           &0x7fc00000,%d0         # insert new exponent,SNAN bit
3445         mov.l           %d1,-(%sp)
3446         mov.l           FP_SRC_HI(%a6),%d1      # load mantissa
3447         lsr.l           &0x8,%d1                # shift mantissa for sgl
3448         or.l            %d1,%d0                 # create sgl SNAN
3449         mov.l           (%sp)+,%d1
3450         andi.w          &0x0007,%d1
3451         bsr.l           store_dreg_l            # store result to regfile
3452         bra.w           fsnan_exit
3453
3454 fsnan_out_d:
3455         mov.l           FP_SRC_EX(%a6),%d0      # fetch SNAN sign
3456         andi.l          &0x80000000,%d0         # keep sign
3457         ori.l           &0x7ff80000,%d0         # insert new exponent,SNAN bit
3458         mov.l           FP_SRC_HI(%a6),%d1      # load hi mantissa
3459         mov.l           %d0,FP_SCR0_EX(%a6)     # store to temp space
3460         mov.l           &11,%d0                 # load shift amt
3461         lsr.l           %d0,%d1
3462         or.l            %d1,FP_SCR0_EX(%a6)     # create dbl hi
3463         mov.l           FP_SRC_HI(%a6),%d1      # load hi mantissa
3464         andi.l          &0x000007ff,%d1
3465         ror.l           %d0,%d1
3466         mov.l           %d1,FP_SCR0_HI(%a6)     # store to temp space
3467         mov.l           FP_SRC_LO(%a6),%d1      # load lo mantissa
3468         lsr.l           %d0,%d1
3469         or.l            %d1,FP_SCR0_HI(%a6)     # create dbl lo
3470         lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
3471         mov.l           EXC_EA(%a6),%a1         # pass: dst addr
3472         movq.l          &0x8,%d0                # pass: size of 8 bytes
3473         bsr.l           _dmem_write             # write the default result
3474
3475         tst.l           %d1                     # did dstore fail?
3476         bne.l           facc_out_d              # yes
3477
3478         bra.w           fsnan_exit
3479
3480 # for extended precision, if the addressing mode is pre-decrement or
3481 # post-increment, then the address register did not get updated.
3482 # in addition, for pre-decrement, the stacked <ea> is incorrect.
3483 fsnan_out_x:
3484         clr.b           SPCOND_FLG(%a6)         # clear special case flag
3485
3486         mov.w           FP_SRC_EX(%a6),FP_SCR0_EX(%a6)
3487         clr.w           2+FP_SCR0(%a6)
3488         mov.l           FP_SRC_HI(%a6),%d0
3489         bset            &30,%d0
3490         mov.l           %d0,FP_SCR0_HI(%a6)
3491         mov.l           FP_SRC_LO(%a6),FP_SCR0_LO(%a6)
3492
3493         btst            &0x5,EXC_SR(%a6)        # supervisor mode exception?
3494         bne.b           fsnan_out_x_s           # yes
3495
3496         mov.l           %usp,%a0                # fetch user stack pointer
3497         mov.l           %a0,EXC_A7(%a6)         # save on stack for calc_ea()
3498         mov.l           (%a6),EXC_A6(%a6)
3499
3500         bsr.l           _calc_ea_fout           # find the correct ea,update An
3501         mov.l           %a0,%a1
3502         mov.l           %a0,EXC_EA(%a6)         # stack correct <ea>
3503
3504         mov.l           EXC_A7(%a6),%a0
3505         mov.l           %a0,%usp                # restore user stack pointer
3506         mov.l           EXC_A6(%a6),(%a6)
3507
3508 fsnan_out_x_save:
3509         lea             FP_SCR0(%a6),%a0        # pass: ptr to operand
3510         movq.l          &0xc,%d0                # pass: size of extended
3511         bsr.l           _dmem_write             # write the default result
3512
3513         tst.l           %d1                     # did dstore fail?
3514         bne.l           facc_out_x              # yes
3515
3516         bra.w           fsnan_exit
3517
3518 fsnan_out_x_s:
3519         mov.l           (%a6),EXC_A6(%a6)
3520
3521         bsr.l           _calc_ea_fout           # find the correct ea,update An
3522         mov.l           %a0,%a1
3523         mov.l           %a0,EXC_EA(%a6)         # stack correct <ea>
3524
3525         mov.l           EXC_A6(%a6),(%a6)
3526
3527         cmpi.b          SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)?
3528         bne.b           fsnan_out_x_save        # no
3529
3530 # the operation was "fmove.x SNAN,-(a7)" from supervisor mode.
3531         fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3532         fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3533         movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3534
3535         frestore        FP_SRC(%a6)
3536
3537         mov.l           EXC_A6(%a6),%a6         # restore frame pointer
3538
3539         mov.l           LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp)
3540         mov.l           LOCAL_SIZE+EXC_PC+0x2(%sp),LOCAL_SIZE+EXC_PC+0x2-0xc(%sp)
3541         mov.l           LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp)
3542
3543         mov.l           LOCAL_SIZE+FP_SCR0_EX(%sp),LOCAL_SIZE+EXC_SR(%sp)
3544         mov.l           LOCAL_SIZE+FP_SCR0_HI(%sp),LOCAL_SIZE+EXC_PC+0x2(%sp)
3545         mov.l           LOCAL_SIZE+FP_SCR0_LO(%sp),LOCAL_SIZE+EXC_EA(%sp)
3546
3547         add.l           &LOCAL_SIZE-0x8,%sp
3548
3549         bra.l           _real_snan
3550
3551 #########################################################################
3552 # XDEF **************************************************************** #
3553 #       _fpsp_inex(): 060FPSP entry point for FP Inexact exception.     #
3554 #                                                                       #
3555 #       This handler should be the first code executed upon taking the  #
3556 #       FP Inexact exception in an operating system.                    #
3557 #                                                                       #
3558 # XREF **************************************************************** #
3559 #       _imem_read_long() - read instruction longword                   #
3560 #       fix_skewed_ops() - adjust src operand in fsave frame            #
3561 #       set_tag_x() - determine optype of src/dst operands              #
3562 #       store_fpreg() - store opclass 0 or 2 result to FP regfile       #
3563 #       unnorm_fix() - change UNNORM operands to NORM or ZERO           #
3564 #       load_fpn2() - load dst operand from FP regfile                  #
3565 #       smovcr() - emulate an "fmovcr" instruction                      #
3566 #       fout() - emulate an opclass 3 instruction                       #
3567 #       tbl_unsupp - add of table of emulation routines for opclass 0,2 #
3568 #       _real_inex() - "callout" to operating system inexact handler    #
3569 #                                                                       #
3570 # INPUT *************************************************************** #
3571 #       - The system stack contains the FP Inexact exception frame      #
3572 #       - The fsave frame contains the source operand                   #
3573 #                                                                       #
3574 # OUTPUT ************************************************************** #
3575 #       - The system stack is unchanged                                 #
3576 #       - The fsave frame contains the adjusted src op for opclass 0,2  #
3577 #                                                                       #
3578 # ALGORITHM *********************************************************** #
3579 #       In a system where the FP Inexact exception is enabled, the goal #
3580 # is to get to the handler specified at _real_inex(). But, on the 060,  #
3581 # for opclass zero and two instruction taking this exception, the       #
3582 # hardware doesn't store the correct result to the destination FP       #
3583 # register as did the '040 and '881/2. This handler must emulate the    #
3584 # instruction in order to get this value and then store it to the       #
3585 # correct register before calling _real_inex().                         #
3586 #       For opclass 3 instructions, the 060 doesn't store the default   #
3587 # inexact result out to memory or data register file as it should.      #
3588 # This code must emulate the move out by calling fout() before finally  #
3589 # exiting through _real_inex().                                         #
3590 #                                                                       #
3591 #########################################################################
3592
3593         global          _fpsp_inex
3594 _fpsp_inex:
3595
3596         link.w          %a6,&-LOCAL_SIZE        # init stack frame
3597
3598         fsave           FP_SRC(%a6)             # grab the "busy" frame
3599
3600         movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3601         fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3602         fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
3603
3604 # the FPIAR holds the "current PC" of the faulting instruction
3605         mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3606
3607         mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3608         addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3609         bsr.l           _imem_read_long         # fetch the instruction words
3610         mov.l           %d0,EXC_OPWORD(%a6)
3611
3612 ##############################################################################
3613
3614         btst            &13,%d0                 # is instr an fmove out?
3615         bne.w           finex_out               # fmove out
3616
3617
3618 # the hardware, for "fabs" and "fneg" w/ a long source format, puts the
3619 # longword integer directly into the upper longword of the mantissa along
3620 # w/ an exponent value of 0x401e. we convert this to extended precision here.
3621         bfextu          %d0{&19:&3},%d0         # fetch instr size
3622         bne.b           finex_cont              # instr size is not long
3623         cmpi.w          FP_SRC_EX(%a6),&0x401e  # is exponent 0x401e?
3624         bne.b           finex_cont              # no
3625         fmov.l          &0x0,%fpcr
3626         fmov.l          FP_SRC_HI(%a6),%fp0     # load integer src
3627         fmov.x          %fp0,FP_SRC(%a6)        # store integer as extended precision
3628         mov.w           &0xe001,0x2+FP_SRC(%a6)
3629
3630 finex_cont:
3631         lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3632         bsr.l           fix_skewed_ops          # fix src op
3633
3634 # Here, we zero the ccode and exception byte field since we're going to
3635 # emulate the whole instruction. Notice, though, that we don't kill the
3636 # INEX1 bit. This is because a packed op has long since been converted
3637 # to extended before arriving here. Therefore, we need to retain the
3638 # INEX1 bit from when the operand was first converted.
3639         andi.l          &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field
3640
3641         fmov.l          &0x0,%fpcr              # zero current control regs
3642         fmov.l          &0x0,%fpsr
3643
3644         bfextu          EXC_EXTWORD(%a6){&0:&6},%d1 # extract upper 6 of cmdreg
3645         cmpi.b          %d1,&0x17               # is op an fmovecr?
3646         beq.w           finex_fmovcr            # yes
3647
3648         lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3649         bsr.l           set_tag_x               # tag the operand type
3650         mov.b           %d0,STAG(%a6)           # maybe NORM,DENORM
3651
3652 # bits four and five of the fp extension word separate the monadic and dyadic
3653 # operations that can pass through fpsp_inex(). remember that fcmp and ftst
3654 # will never take this exception, but fsincos will.
3655         btst            &0x5,1+EXC_CMDREG(%a6)  # is operation monadic or dyadic?
3656         beq.b           finex_extract           # monadic
3657
3658         btst            &0x4,1+EXC_CMDREG(%a6)  # is operation an fsincos?
3659         bne.b           finex_extract           # yes
3660
3661         bfextu          EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg
3662         bsr.l           load_fpn2               # load dst into FP_DST
3663
3664         lea             FP_DST(%a6),%a0         # pass: ptr to dst op
3665         bsr.l           set_tag_x               # tag the operand type
3666         cmpi.b          %d0,&UNNORM             # is operand an UNNORM?
3667         bne.b           finex_op2_done          # no
3668         bsr.l           unnorm_fix              # yes; convert to NORM,DENORM,or ZERO
3669 finex_op2_done:
3670         mov.b           %d0,DTAG(%a6)           # save dst optype tag
3671
3672 finex_extract:
3673         clr.l           %d0
3674         mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec/mode
3675
3676         mov.b           1+EXC_CMDREG(%a6),%d1
3677         andi.w          &0x007f,%d1             # extract extension
3678
3679         lea             FP_SRC(%a6),%a0
3680         lea             FP_DST(%a6),%a1
3681
3682         mov.l           (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr
3683         jsr             (tbl_unsupp.l,%pc,%d1.l*1)
3684
3685 # the operation has been emulated. the result is in fp0.
3686 finex_save:
3687         bfextu          EXC_CMDREG(%a6){&6:&3},%d0
3688         bsr.l           store_fpreg
3689
3690 finex_exit:
3691         fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3692         fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3693         movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3694
3695         frestore        FP_SRC(%a6)
3696
3697         unlk            %a6
3698         bra.l           _real_inex
3699
3700 finex_fmovcr:
3701         clr.l           %d0
3702         mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec,mode
3703         mov.b           1+EXC_CMDREG(%a6),%d1
3704         andi.l          &0x0000007f,%d1         # pass rom offset
3705         bsr.l           smovcr
3706         bra.b           finex_save
3707
3708 ########################################################################
3709
3710 #
3711 # the hardware does not save the default result to memory on enabled
3712 # inexact exceptions. we do this here before passing control to
3713 # the user inexact handler.
3714 #
3715 # byte, word, and long destination format operations can pass
3716 # through here. so can double and single precision.
3717 # although packed opclass three operations can take inexact
3718 # exceptions, they won't pass through here since they are caught
3719 # first by the unsupported data format exception handler. that handler
3720 # sends them directly to _real_inex() if necessary.
3721 #
3722 finex_out:
3723
3724         mov.b           &NORM,STAG(%a6)         # src is a NORM
3725
3726         clr.l           %d0
3727         mov.b           FPCR_MODE(%a6),%d0      # pass rnd prec,mode
3728
3729         andi.l          &0xffff00ff,USER_FPSR(%a6) # zero exception field
3730
3731         lea             FP_SRC(%a6),%a0         # pass ptr to src operand
3732
3733         bsr.l           fout                    # store the default result
3734
3735         bra.b           finex_exit
3736
3737 #########################################################################
3738 # XDEF **************************************************************** #
3739 #       _fpsp_dz(): 060FPSP entry point for FP DZ exception.            #
3740 #                                                                       #
3741 #       This handler should be the first code executed upon taking      #
3742 #       the FP DZ exception in an operating system.                     #
3743 #                                                                       #
3744 # XREF **************************************************************** #
3745 #       _imem_read_long() - read instruction longword from memory       #
3746 #       fix_skewed_ops() - adjust fsave operand                         #
3747 #       _real_dz() - "callout" exit point from FP DZ handler            #
3748 #                                                                       #
3749 # INPUT *************************************************************** #
3750 #       - The system stack contains the FP DZ exception stack.          #
3751 #       - The fsave frame contains the source operand.                  #
3752 #                                                                       #
3753 # OUTPUT ************************************************************** #
3754 #       - The system stack contains the FP DZ exception stack.          #
3755 #       - The fsave frame contains the adjusted source operand.         #
3756 #                                                                       #
3757 # ALGORITHM *********************************************************** #
3758 #       In a system where the DZ exception is enabled, the goal is to   #
3759 # get to the handler specified at _real_dz(). But, on the 060, when the #
3760 # exception is taken, the input operand in the fsave state frame may    #
3761 # be incorrect for some cases and need to be adjusted. So, this package #
3762 # adjusts the operand using fix_skewed_ops() and then branches to       #
3763 # _real_dz().                                                           #
3764 #                                                                       #
3765 #########################################################################
3766
3767         global          _fpsp_dz
3768 _fpsp_dz:
3769
3770         link.w          %a6,&-LOCAL_SIZE        # init stack frame
3771
3772         fsave           FP_SRC(%a6)             # grab the "busy" frame
3773
3774         movm.l          &0x0303,EXC_DREGS(%a6)  # save d0-d1/a0-a1
3775         fmovm.l         %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs
3776         fmovm.x         &0xc0,EXC_FPREGS(%a6)   # save fp0-fp1 on stack
3777
3778 # the FPIAR holds the "current PC" of the faulting instruction
3779         mov.l           USER_FPIAR(%a6),EXC_EXTWPTR(%a6)
3780
3781         mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
3782         addq.l          &0x4,EXC_EXTWPTR(%a6)   # incr instruction ptr
3783         bsr.l           _imem_read_long         # fetch the instruction words
3784         mov.l           %d0,EXC_OPWORD(%a6)
3785
3786 ##############################################################################
3787
3788
3789 # here, we simply see if the operand in the fsave frame needs to be "unskewed".
3790 # this would be the case for opclass two operations with a source zero
3791 # in the sgl or dbl format.
3792         lea             FP_SRC(%a6),%a0         # pass: ptr to src op
3793         bsr.l           fix_skewed_ops          # fix src op
3794
3795 fdz_exit:
3796         fmovm.x         EXC_FPREGS(%a6),&0xc0   # restore fp0-fp1
3797         fmovm.l         USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs
3798         movm.l          EXC_DREGS(%a6),&0x0303  # restore d0-d1/a0-a1
3799
3800         frestore        FP_SRC(%a6)
3801
3802         unlk            %a6
3803         bra.l           _real_dz
3804
3805 #########################################################################
3806 # XDEF **************************************************************** #
3807 #       _fpsp_fline(): 060FPSP entry point for "Line F emulator"        #
3808 #                      exception when the "reduced" version of the      #
3809 #                      FPSP is implemented that does not emulate        #
3810 #                      FP unimplemented instructions.                   #
3811 #                                                                       #
3812 #       This handler should be the first code executed upon taking a    #
3813 #       "Line F Emulator" exception in an operating system integrating  #
3814 #       the reduced version of 060FPSP.                                 #
3815 #                                                                       #
3816 # XREF **************************************************************** #
3817 #       _real_fpu_disabled() - Handle "FPU disabled" exceptions         #
3818 #       _real_fline() - Handle all other cases (treated equally)        #
3819 #                                                                       #
3820 # INPUT *************************************************************** #
3821 #       - The system stack contains a "Line F Emulator" exception       #
3822 #         stack frame.                                                  #
3823 #                                                                       #
3824 # OUTPUT ************************************************************** #
3825 #       - The system stack is unchanged.                                #
3826 #                                                                       #
3827 # ALGORITHM *********************************************************** #
3828 #       When a "Line F Emulator" exception occurs in a system where     #
3829 # "FPU Unimplemented" instructions will not be emulated, the exception  #
3830 # can occur because then FPU is disabled or the instruction is to be    #
3831 # classifed as "Line F". This module determines which case exists and   #
3832 # calls the appropriate "callout".                                      #
3833 #                                                                       #
3834 #########################################################################
3835
3836         global          _fpsp_fline
3837 _fpsp_fline:
3838
3839 # check to see if the FPU is disabled. if so, jump to the OS entry
3840 # point for that condition.
3841         cmpi.w          0x6(%sp),&0x402c
3842         beq.l           _real_fpu_disabled
3843
3844         bra.l           _real_fline
3845
3846 #########################################################################
3847 # XDEF **************************************************************** #
3848 #       _dcalc_ea(): calc correct <ea> from <ea> stacked on exception   #
3849 #                                                                       #
3850 # XREF **************************************************************** #
3851 #       inc_areg() - increment an address register                      #
3852 #       dec_areg() - decrement an address register                      #
3853 #                                                                       #
3854 # INPUT *************************************************************** #
3855 #       d0 = number of bytes to adjust <ea> by                          #
3856 #                                                                       #
3857 # OUTPUT ************************************************************** #
3858 #       None                                                            #
3859 #                                                                       #
3860 # ALGORITHM *********************************************************** #
3861 # "Dummy" CALCulate Effective Address:                                  #
3862 #       The stacked <ea> for FP unimplemented instructions and opclass  #
3863 #       two packed instructions is correct with the exception of...     #
3864 #                                                                       #
3865 #       1) -(An)   : The register is not updated regardless of size.    #
3866 #                    Also, for extended precision and packed, the       #
3867 #                    stacked <ea> value is 8 bytes too big              #
3868 #       2) (An)+   : The register is not updated.                       #
3869 #       3) #<data> : The upper longword of the immediate operand is     #
3870 #                    stacked b,w,l and s sizes are completely stacked.  #
3871 #                    d,x, and p are not.                                #
3872 #                                                                       #
3873 #########################################################################
3874
3875         global          _dcalc_ea
3876 _dcalc_ea:
3877         mov.l           %d0, %a0                # move # bytes to %a0
3878
3879         mov.b           1+EXC_OPWORD(%a6), %d0  # fetch opcode word
3880         mov.l           %d0, %d1                # make a copy
3881
3882         andi.w          &0x38, %d0              # extract mode field
3883         andi.l          &0x7, %d1               # extract reg  field
3884
3885         cmpi.b          %d0,&0x18               # is mode (An)+ ?
3886         beq.b           dcea_pi                 # yes
3887
3888         cmpi.b          %d0,&0x20               # is mode -(An) ?
3889         beq.b           dcea_pd                 # yes
3890
3891         or.w            %d1,%d0                 # concat mode,reg
3892         cmpi.b          %d0,&0x3c               # is mode #<data>?
3893
3894         beq.b           dcea_imm                # yes
3895
3896         mov.l           EXC_EA(%a6),%a0         # return <ea>
3897         rts
3898
3899 # need to set immediate data flag here since we'll need to do
3900 # an imem_read to fetch this later.
3901 dcea_imm:
3902         mov.b           &immed_flg,SPCOND_FLG(%a6)
3903         lea             ([USER_FPIAR,%a6],0x4),%a0 # no; return <ea>
3904         rts
3905
3906 # here, the <ea> is stacked correctly. however, we must update the
3907 # address register...
3908 dcea_pi:
3909         mov.l           %a0,%d0                 # pass amt to inc by
3910         bsr.l           inc_areg                # inc addr register
3911
3912         mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
3913         rts
3914
3915 # the <ea> is stacked correctly for all but extended and packed which
3916 # the <ea>s are 8 bytes too large.
3917 # it would make no sense to have a pre-decrement to a7 in supervisor
3918 # mode so we don't even worry about this tricky case here : )
3919 dcea_pd:
3920         mov.l           %a0,%d0                 # pass amt to dec by
3921         bsr.l           dec_areg                # dec addr register
3922
3923         mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
3924
3925         cmpi.b          %d0,&0xc                # is opsize ext or packed?
3926         beq.b           dcea_pd2                # yes
3927         rts
3928 dcea_pd2:
3929         sub.l           &0x8,%a0                # correct <ea>
3930         mov.l           %a0,EXC_EA(%a6)         # put correct <ea> on stack
3931         rts
3932
3933 #########################################################################
3934 # XDEF **************************************************************** #
3935 #       _calc_ea_fout(): calculate correct stacked <ea> for extended    #
3936 #                        and packed data opclass 3 operations.          #
3937 #                                                                       #
3938 # XREF **************************************************************** #
3939 #       None                                                            #
3940 #                                                                       #
3941 # INPUT *************************************************************** #
3942 #       None                                                            #
3943 #                                                                       #
3944 # OUTPUT ************************************************************** #
3945 #       a0 = return correct effective address                           #
3946 #                                                                       #
3947 # ALGORITHM *********************************************************** #
3948 #       For opclass 3 extended and packed data operations, the <ea>     #
3949 # stacked for the exception is incorrect for -(an) and (an)+ addressing #
3950 # modes. Also, while we're at it, the index register itself must get    #
3951 # updated.                                                              #
3952 #       So, for -(an), we must subtract 8 off of the stacked <ea> value #
3953 # and return that value as the correct <ea> and store that value in An. #
3954 # For (an)+, the stacked <ea> is correct but we must adjust An by +12.  #
3955 #                                                                       #
3956 #########################################################################
3957
3958 # This calc_ea is currently used to retrieve the correct <ea>
3959 # for fmove outs of type extended and packed.
3960         global          _calc_ea_fout
3961 _calc_ea_fout:
3962         mov.b           1+EXC_OPWORD(%a6),%d0   # fetch opcode word
3963         mov.l           %d0,%d1                 # make a copy
3964
3965         andi.w          &0x38,%d0               # extract mode field
3966         andi.l          &0x7,%d1                # extract reg  field
3967
3968         cmpi.b          %d0,&0x18               # is mode (An)+ ?
3969         beq.b           ceaf_pi                 # yes
3970
3971         cmpi.b          %d0,&0x20               # is mode -(An) ?
3972         beq.w           ceaf_pd                 # yes
3973
3974         mov.l           EXC_EA(%a6),%a0         # stacked <ea> is correct
3975         rts
3976
3977 # (An)+ : extended and packed fmove out
3978 #       : stacked <ea> is correct
3979 #       : "An" not updated
3980 ceaf_pi:
3981         mov.w           (tbl_ceaf_pi.b,%pc,%d1.w*2),%d1
3982         mov.l           EXC_EA(%a6),%a0
3983         jmp             (tbl_ceaf_pi.b,%pc,%d1.w*1)
3984
3985         swbeg           &0x8
3986 tbl_ceaf_pi:
3987         short           ceaf_pi0 - tbl_ceaf_pi
3988         short           ceaf_pi1 - tbl_ceaf_pi
3989         short           ceaf_pi2 - tbl_ceaf_pi
3990         short           ceaf_pi3 - tbl_ceaf_pi
3991         short           ceaf_pi4 - tbl_ceaf_pi
3992         short           ceaf_pi5 - tbl_ceaf_pi
3993         short           ceaf_pi6 - tbl_ceaf_pi
3994         short           ceaf_pi7 - tbl_ceaf_pi
3995
3996 ceaf_pi0:
3997         addi.l          &0xc,EXC_DREGS+0x8(%a6)
3998         rts
3999 ceaf_pi1:
4000         addi.l          &0xc,EXC_DREGS+0xc(%a6)
4001         rts
4002 ceaf_pi2:
4003         add.l           &0xc,%a2
4004         rts
4005 ceaf_pi3:
4006         add.l           &0xc,%a3
4007         rts
4008 ceaf_pi4:
4009         add.l           &0xc,%a4
4010         rts
4011 ceaf_pi5:
4012         add.l           &0xc,%a5
4013         rts
4014 ceaf_pi6:
4015         addi.l          &0xc,EXC_A6(%a6)
4016         rts
4017 ceaf_pi7:
4018         mov.b           &mia7_flg,SPCOND_FLG(%a6)
4019         addi.l          &0xc,EXC_A7(%a6)
4020         rts
4021
4022 # -(An) : extended and packed fmove out
4023 #       : stacked <ea> = actual <ea> + 8
4024 #       : "An" not updated
4025 ceaf_pd:
4026         mov.w           (tbl_ceaf_pd.b,%pc,%d1.w*2),%d1
4027         mov.l           EXC_EA(%a6),%a0
4028         sub.l           &0x8,%a0
4029         sub.l           &0x8,EXC_EA(%a6)
4030         jmp             (tbl_ceaf_pd.b,%pc,%d1.w*1)
4031
4032         swbeg           &0x8
4033 tbl_ceaf_pd:
4034         short           ceaf_pd0 - tbl_ceaf_pd
4035         short           ceaf_pd1 - tbl_ceaf_pd
4036         short           ceaf_pd2 - tbl_ceaf_pd
4037         short           ceaf_pd3 - tbl_ceaf_pd
4038         short           ceaf_pd4 - tbl_ceaf_pd
4039         short           ceaf_pd5 - tbl_ceaf_pd
4040         short           ceaf_pd6 - tbl_ceaf_pd
4041         short           ceaf_pd7 - tbl_ceaf_pd
4042
4043 ceaf_pd0:
4044         mov.l           %a0,EXC_DREGS+0x8(%a6)
4045         rts
4046 ceaf_pd1:
4047         mov.l           %a0,EXC_DREGS+0xc(%a6)
4048         rts
4049 ceaf_pd2:
4050         mov.l           %a0,%a2
4051         rts
4052 ceaf_pd3:
4053         mov.l           %a0,%a3
4054         rts
4055 ceaf_pd4:
4056         mov.l           %a0,%a4
4057         rts
4058 ceaf_pd5:
4059         mov.l           %a0,%a5
4060         rts
4061 ceaf_pd6:
4062         mov.l           %a0,EXC_A6(%a6)
4063         rts
4064 ceaf_pd7:
4065         mov.l           %a0,EXC_A7(%a6)
4066         mov.b           &mda7_flg,SPCOND_FLG(%a6)
4067         rts
4068
4069 #
4070 # This table holds the offsets of the emulation routines for each individual
4071 # math operation relative to the address of this table. Included are
4072 # routines like fadd/fmul/fabs. The transcendentals ARE NOT. This is because
4073 # this table is for the version if the 060FPSP without transcendentals.
4074 # The location within the table is determined by the extension bits of the
4075 # operation longword.
4076 #
4077
4078         swbeg           &109
4079 tbl_unsupp:
4080         long            fin             - tbl_unsupp    # 00: fmove
4081         long            fint            - tbl_unsupp    # 01: fint
4082         long            tbl_unsupp      - tbl_unsupp    # 02: fsinh
4083         long            fintrz          - tbl_unsupp    # 03: fintrz
4084         long            fsqrt           - tbl_unsupp    # 04: fsqrt
4085         long            tbl_unsupp      - tbl_unsupp
4086         long            tbl_unsupp      - tbl_unsupp    # 06: flognp1
4087         long            tbl_unsupp      - tbl_unsupp
4088         long            tbl_unsupp      - tbl_unsupp    # 08: fetoxm1
4089         long            tbl_unsupp      - tbl_unsupp    # 09: ftanh
4090         long            tbl_unsupp      - tbl_unsupp    # 0a: fatan
4091         long            tbl_unsupp      - tbl_unsupp
4092         long            tbl_unsupp      - tbl_unsupp    # 0c: fasin
4093         long            tbl_unsupp      - tbl_unsupp    # 0d: fatanh
4094         long            tbl_unsupp      - tbl_unsupp    # 0e: fsin
4095         long            tbl_unsupp      - tbl_unsupp    # 0f: ftan
4096         long            tbl_unsupp      - tbl_unsupp    # 10: fetox
4097         long            tbl_unsupp      - tbl_unsupp    # 11: ftwotox
4098         long            tbl_unsupp      - tbl_unsupp    # 12: ftentox
4099         long            tbl_unsupp      - tbl_unsupp
4100         long            tbl_unsupp      - tbl_unsupp    # 14: flogn
4101         long            tbl_unsupp      - tbl_unsupp    # 15: flog10
4102         long            tbl_unsupp      - tbl_unsupp    # 16: flog2
4103         long            tbl_unsupp      - tbl_unsupp
4104         long            fabs            - tbl_unsupp    # 18: fabs
4105         long            tbl_unsupp      - tbl_unsupp    # 19: fcosh
4106         long            fneg            - tbl_unsupp    # 1a: fneg
4107         long            tbl_unsupp      - tbl_unsupp
4108         long            tbl_unsupp      - tbl_unsupp    # 1c: facos
4109         long            tbl_unsupp      - tbl_unsupp    # 1d: fcos
4110         long            tbl_unsupp      - tbl_unsupp    # 1e: fgetexp
4111         long            tbl_unsupp      - tbl_unsupp    # 1f: fgetman
4112         long            fdiv            - tbl_unsupp    # 20: fdiv
4113         long            tbl_unsupp      - tbl_unsupp    # 21: fmod
4114         long            fadd            - tbl_unsupp    # 22: fadd
4115         long            fmul            - tbl_unsupp    # 23: fmul
4116         long            fsgldiv         - tbl_unsupp    # 24: fsgldiv
4117         long            tbl_unsupp      - tbl_unsupp    # 25: frem
4118         long            tbl_unsupp      - tbl_unsupp    # 26: fscale
4119         long            fsglmul         - tbl_unsupp    # 27: fsglmul
4120         long            fsub            - tbl_unsupp    # 28: fsub
4121         long            tbl_unsupp      - tbl_unsupp
4122         long            tbl_unsupp      - tbl_unsupp
4123         long            tbl_unsupp      - tbl_unsupp
4124         long            tbl_unsupp      - tbl_unsupp
4125         long            tbl_unsupp      - tbl_unsupp
4126         long            tbl_unsupp      - tbl_unsupp
4127         long            tbl_unsupp      - tbl_unsupp
4128         long            tbl_unsupp      - tbl_unsupp    # 30: fsincos
4129         long            tbl_unsupp      - tbl_unsupp    # 31: fsincos
4130         long            tbl_unsupp      - tbl_unsupp    # 32: fsincos
4131         long            tbl_unsupp      - tbl_unsupp    # 33: fsincos
4132         long            tbl_unsupp      - tbl_unsupp    # 34: fsincos
4133         long            tbl_unsupp      - tbl_unsupp    # 35: fsincos
4134         long            tbl_unsupp      - tbl_unsupp    # 36: fsincos
4135         long            tbl_unsupp      - tbl_unsupp    # 37: fsincos
4136         long            fcmp            - tbl_unsupp    # 38: fcmp
4137         long            tbl_unsupp      - tbl_unsupp
4138         long            ftst            - tbl_unsupp    # 3a: ftst
4139         long            tbl_unsupp      - tbl_unsupp
4140         long            tbl_unsupp      - tbl_unsupp
4141         long            tbl_unsupp      - tbl_unsupp
4142         long            tbl_unsupp      - tbl_unsupp
4143         long            tbl_unsupp      - tbl_unsupp
4144         long            fsin            - tbl_unsupp    # 40: fsmove
4145         long            fssqrt          - tbl_unsupp    # 41: fssqrt
4146         long            tbl_unsupp      - tbl_unsupp
4147         long            tbl_unsupp      - tbl_unsupp
4148         long            fdin            - tbl_unsupp    # 44: fdmove
4149         long            fdsqrt          - tbl_unsupp    # 45: fdsqrt
4150         long            tbl_unsupp      - tbl_unsupp
4151         long            tbl_unsupp      - tbl_unsupp
4152         long            tbl_unsupp      - tbl_unsupp
4153         long            tbl_unsupp      - tbl_unsupp
4154         long            tbl_unsupp      - tbl_unsupp
4155         long            tbl_unsupp      - tbl_unsupp
4156         long            tbl_unsupp      - tbl_unsupp
4157         long            tbl_unsupp      - tbl_unsupp
4158         long            tbl_unsupp      - tbl_unsupp
4159         long            tbl_unsupp      - tbl_unsupp
4160         long            tbl_unsupp      - tbl_unsupp
4161         long            tbl_unsupp      - tbl_unsupp
4162         long            tbl_unsupp      - tbl_unsupp
4163         long            tbl_unsupp      - tbl_unsupp
4164         long            tbl_unsupp      - tbl_unsupp
4165         long            tbl_unsupp      - tbl_unsupp
4166         long            tbl_unsupp      - tbl_unsupp
4167         long            tbl_unsupp      - tbl_unsupp
4168         long            fsabs           - tbl_unsupp    # 58: fsabs
4169         long            tbl_unsupp      - tbl_unsupp
4170         long            fsneg           - tbl_unsupp    # 5a: fsneg
4171         long            tbl_unsupp      - tbl_unsupp
4172         long            fdabs           - tbl_unsupp    # 5c: fdabs
4173         long            tbl_unsupp      - tbl_unsupp
4174         long            fdneg           - tbl_unsupp    # 5e: fdneg
4175         long            tbl_unsupp      - tbl_unsupp
4176         long            fsdiv           - tbl_unsupp    # 60: fsdiv
4177         long            tbl_unsupp      - tbl_unsupp
4178         long            fsadd           - tbl_unsupp    # 62: fsadd
4179         long            fsmul           - tbl_unsupp    # 63: fsmul
4180         long            fddiv           - tbl_unsupp    # 64: fddiv
4181         long            tbl_unsupp      - tbl_unsupp
4182         long            fdadd           - tbl_unsupp    # 66: fdadd
4183         long            fdmul           - tbl_unsupp    # 67: fdmul
4184         long            fssub           - tbl_unsupp    # 68: fssub
4185         long            tbl_unsupp      - tbl_unsupp
4186         long            tbl_unsupp      - tbl_unsupp
4187         long            tbl_unsupp      - tbl_unsupp
4188         long            fdsub           - tbl_unsupp    # 6c: fdsub
4189
4190 #################################################
4191 # Add this here so non-fp modules can compile.
4192 # (smovcr is called from fpsp_inex.)
4193         global          smovcr
4194 smovcr:
4195         bra.b           smovcr
4196
4197 #########################################################################
4198 # XDEF **************************************************************** #
4199 #       fmovm_dynamic(): emulate "fmovm" dynamic instruction            #
4200 #                                                                       #
4201 # XREF **************************************************************** #
4202 #       fetch_dreg() - fetch data register                              #
4203 #       {i,d,}mem_read() - fetch data from memory                       #
4204 #       _mem_write() - write data to memory                             #
4205 #       iea_iacc() - instruction memory access error occurred           #
4206 #       iea_dacc() - data memory access error occurred                  #
4207 #       restore() - restore An index regs if access error occurred      #
4208 #                                                                       #
4209 # INPUT *************************************************************** #
4210 #       None                                                            #
4211 #                                                                       #
4212 # OUTPUT ************************************************************** #
4213 #       If instr is "fmovm Dn,-(A7)" from supervisor mode,              #
4214 #               d0 = size of dump                                       #
4215 #               d1 = Dn                                                 #
4216 #       Else if instruction access error,                               #
4217 #               d0 = FSLW                                               #
4218 #       Else if data access error,                                      #
4219 #               d0 = FSLW                                               #
4220 #               a0 = address of fault                                   #
4221 #       Else                                                            #
4222 #               none.                                                   #
4223 #                                                                       #
4224 # ALGORITHM *********************************************************** #
4225 #       The effective address must be calculated since this is entered  #
4226 # from an "Unimplemented Effective Address" exception handler. So, we   #
4227 # have our own fcalc_ea() routine here. If an access error is flagged   #
4228 # by a _{i,d,}mem_read() call, we must exit through the special         #
4229 # handler.                                                              #
4230 #       The data register is determined and its value loaded to get the #
4231 # string of FP registers affected. This value is used as an index into  #
4232 # a lookup table such that we can determine the number of bytes         #
4233 # involved.                                                             #
4234 #       If the instruction is "fmovm.x <ea>,Dn", a _mem_read() is used  #
4235 # to read in all FP values. Again, _mem_read() may fail and require a   #
4236 # special exit.                                                         #
4237 #       If the instruction is "fmovm.x DN,<ea>", a _mem_write() is used #
4238 # to write all FP values. _mem_write() may also fail.                   #
4239 #       If the instruction is "fmovm.x DN,-(a7)" from supervisor mode,  #
4240 # then we return the size of the dump and the string to the caller      #
4241 # so that the move can occur outside of this routine. This special      #
4242 # case is required so that moves to the system stack are handled        #
4243 # correctly.                                                            #
4244 #                                                                       #
4245 # DYNAMIC:                                                              #
4246 #       fmovm.x dn, <ea>                                                #
4247 #       fmovm.x <ea>, dn                                                #
4248 #                                                                       #
4249 #             <WORD 1>                <WORD2>                           #
4250 #       1111 0010 00 |<ea>|     11@& 1000 0$$$ 0000                     #
4251 #                                                                       #
4252 #       & = (0): predecrement addressing mode                           #
4253 #           (1): postincrement or control addressing mode               #
4254 #       @ = (0): move listed regs from memory to the FPU                #
4255 #           (1): move listed regs from the FPU to memory                #
4256 #       $$$    : index of data register holding reg select mask         #
4257 #                                                                       #
4258 # NOTES:                                                                #
4259 #       If the data register holds a zero, then the                     #
4260 #       instruction is a nop.                                           #
4261 #                                                                       #
4262 #########################################################################
4263
4264         global          fmovm_dynamic
4265 fmovm_dynamic:
4266
4267 # extract the data register in which the bit string resides...
4268         mov.b           1+EXC_EXTWORD(%a6),%d1  # fetch extword
4269         andi.w          &0x70,%d1               # extract reg bits
4270         lsr.b           &0x4,%d1                # shift into lo bits
4271
4272 # fetch the bit string into d0...
4273         bsr.l           fetch_dreg              # fetch reg string
4274
4275         andi.l          &0x000000ff,%d0         # keep only lo byte
4276
4277         mov.l           %d0,-(%sp)              # save strg
4278         mov.b           (tbl_fmovm_size.w,%pc,%d0),%d0
4279         mov.l           %d0,-(%sp)              # save size
4280         bsr.l           fmovm_calc_ea           # calculate <ea>
4281         mov.l           (%sp)+,%d0              # restore size
4282         mov.l           (%sp)+,%d1              # restore strg
4283
4284 # if the bit string is a zero, then the operation is a no-op
4285 # but, make sure that we've calculated ea and advanced the opword pointer
4286         beq.w           fmovm_data_done
4287
4288 # separate move ins from move outs...
4289         btst            &0x5,EXC_EXTWORD(%a6)   # is it a move in or out?
4290         beq.w           fmovm_data_in           # it's a move out
4291
4292 #############
4293 # MOVE OUT: #
4294 #############
4295 fmovm_data_out:
4296         btst            &0x4,EXC_EXTWORD(%a6)   # control or predecrement?
4297         bne.w           fmovm_out_ctrl          # control
4298
4299 ############################
4300 fmovm_out_predec:
4301 # for predecrement mode, the bit string is the opposite of both control
4302 # operations and postincrement mode. (bit7 = FP7 ... bit0 = FP0)
4303 # here, we convert it to be just like the others...
4304         mov.b           (tbl_fmovm_convert.w,%pc,%d1.w*1),%d1
4305
4306         btst            &0x5,EXC_SR(%a6)        # user or supervisor mode?
4307         beq.b           fmovm_out_ctrl          # user
4308
4309 fmovm_out_predec_s:
4310         cmpi.b          SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)?
4311         bne.b           fmovm_out_ctrl
4312
4313 # the operation was unfortunately an: fmovm.x dn,-(sp)
4314 # called from supervisor mode.
4315 # we're also passing "size" and "strg" back to the calling routine
4316         rts
4317
4318 ############################
4319 fmovm_out_ctrl:
4320         mov.l           %a0,%a1                 # move <ea> to a1
4321
4322         sub.l           %d0,%sp                 # subtract size of dump
4323         lea             (%sp),%a0
4324
4325         tst.b           %d1                     # should FP0 be moved?
4326         bpl.b           fmovm_out_ctrl_fp1      # no
4327
4328         mov.l           0x0+EXC_FP0(%a6),(%a0)+ # yes
4329         mov.l           0x4+EXC_FP0(%a6),(%a0)+
4330         mov.l           0x8+EXC_FP0(%a6),(%a0)+
4331
4332 fmovm_out_ctrl_fp1:
4333         lsl.b           &0x1,%d1                # should FP1 be moved?
4334         bpl.b           fmovm_out_ctrl_fp2      # no
4335
4336         mov.l           0x0+EXC_FP1(%a6),(%a0)+ # yes
4337         mov.l           0x4+EXC_FP1(%a6),(%a0)+
4338         mov.l           0x8+EXC_FP1(%a6),(%a0)+
4339
4340 fmovm_out_ctrl_fp2:
4341         lsl.b           &0x1,%d1                # should FP2 be moved?
4342         bpl.b           fmovm_out_ctrl_fp3      # no
4343
4344         fmovm.x         &0x20,(%a0)             # yes
4345         add.l           &0xc,%a0
4346
4347 fmovm_out_ctrl_fp3:
4348         lsl.b           &0x1,%d1                # should FP3 be moved?
4349         bpl.b           fmovm_out_ctrl_fp4      # no
4350
4351         fmovm.x         &0x10,(%a0)             # yes
4352         add.l           &0xc,%a0
4353
4354 fmovm_out_ctrl_fp4:
4355         lsl.b           &0x1,%d1                # should FP4 be moved?
4356         bpl.b           fmovm_out_ctrl_fp5      # no
4357
4358         fmovm.x         &0x08,(%a0)             # yes
4359         add.l           &0xc,%a0
4360
4361 fmovm_out_ctrl_fp5:
4362         lsl.b           &0x1,%d1                # should FP5 be moved?
4363         bpl.b           fmovm_out_ctrl_fp6      # no
4364
4365         fmovm.x         &0x04,(%a0)             # yes
4366         add.l           &0xc,%a0
4367
4368 fmovm_out_ctrl_fp6:
4369         lsl.b           &0x1,%d1                # should FP6 be moved?
4370         bpl.b           fmovm_out_ctrl_fp7      # no
4371
4372         fmovm.x         &0x02,(%a0)             # yes
4373         add.l           &0xc,%a0
4374
4375 fmovm_out_ctrl_fp7:
4376         lsl.b           &0x1,%d1                # should FP7 be moved?
4377         bpl.b           fmovm_out_ctrl_done     # no
4378
4379         fmovm.x         &0x01,(%a0)             # yes
4380         add.l           &0xc,%a0
4381
4382 fmovm_out_ctrl_done:
4383         mov.l           %a1,L_SCR1(%a6)
4384
4385         lea             (%sp),%a0               # pass: supervisor src
4386         mov.l           %d0,-(%sp)              # save size
4387         bsr.l           _dmem_write             # copy data to user mem
4388
4389         mov.l           (%sp)+,%d0
4390         add.l           %d0,%sp                 # clear fpreg data from stack
4391
4392         tst.l           %d1                     # did dstore err?
4393         bne.w           fmovm_out_err           # yes
4394
4395         rts
4396
4397 ############
4398 # MOVE IN: #
4399 ############
4400 fmovm_data_in:
4401         mov.l           %a0,L_SCR1(%a6)
4402
4403         sub.l           %d0,%sp                 # make room for fpregs
4404         lea             (%sp),%a1
4405
4406         mov.l           %d1,-(%sp)              # save bit string for later
4407         mov.l           %d0,-(%sp)              # save # of bytes
4408
4409         bsr.l           _dmem_read              # copy data from user mem
4410
4411         mov.l           (%sp)+,%d0              # retrieve # of bytes
4412
4413         tst.l           %d1                     # did dfetch fail?
4414         bne.w           fmovm_in_err            # yes
4415
4416         mov.l           (%sp)+,%d1              # load bit string
4417
4418         lea             (%sp),%a0               # addr of stack
4419
4420         tst.b           %d1                     # should FP0 be moved?
4421         bpl.b           fmovm_data_in_fp1       # no
4422
4423         mov.l           (%a0)+,0x0+EXC_FP0(%a6) # yes
4424         mov.l           (%a0)+,0x4+EXC_FP0(%a6)
4425         mov.l           (%a0)+,0x8+EXC_FP0(%a6)
4426
4427 fmovm_data_in_fp1:
4428         lsl.b           &0x1,%d1                # should FP1 be moved?
4429         bpl.b           fmovm_data_in_fp2       # no
4430
4431         mov.l           (%a0)+,0x0+EXC_FP1(%a6) # yes
4432         mov.l           (%a0)+,0x4+EXC_FP1(%a6)
4433         mov.l           (%a0)+,0x8+EXC_FP1(%a6)
4434
4435 fmovm_data_in_fp2:
4436         lsl.b           &0x1,%d1                # should FP2 be moved?
4437         bpl.b           fmovm_data_in_fp3       # no
4438
4439         fmovm.x         (%a0)+,&0x20            # yes
4440
4441 fmovm_data_in_fp3:
4442         lsl.b           &0x1,%d1                # should FP3 be moved?
4443         bpl.b           fmovm_data_in_fp4       # no
4444
4445         fmovm.x         (%a0)+,&0x10            # yes
4446
4447 fmovm_data_in_fp4:
4448         lsl.b           &0x1,%d1                # should FP4 be moved?
4449         bpl.b           fmovm_data_in_fp5       # no
4450
4451         fmovm.x         (%a0)+,&0x08            # yes
4452
4453 fmovm_data_in_fp5:
4454         lsl.b           &0x1,%d1                # should FP5 be moved?
4455         bpl.b           fmovm_data_in_fp6       # no
4456
4457         fmovm.x         (%a0)+,&0x04            # yes
4458
4459 fmovm_data_in_fp6:
4460         lsl.b           &0x1,%d1                # should FP6 be moved?
4461         bpl.b           fmovm_data_in_fp7       # no
4462
4463         fmovm.x         (%a0)+,&0x02            # yes
4464
4465 fmovm_data_in_fp7:
4466         lsl.b           &0x1,%d1                # should FP7 be moved?
4467         bpl.b           fmovm_data_in_done      # no
4468
4469         fmovm.x         (%a0)+,&0x01            # yes
4470
4471 fmovm_data_in_done:
4472         add.l           %d0,%sp                 # remove fpregs from stack
4473         rts
4474
4475 #####################################
4476
4477 fmovm_data_done:
4478         rts
4479
4480 ##############################################################################
4481
4482 #
4483 # table indexed by the operation's bit string that gives the number
4484 # of bytes that will be moved.
4485 #
4486 # number of bytes = (# of 1's in bit string) * 12(bytes/fpreg)
4487 #
4488 tbl_fmovm_size:
4489         byte    0x00,0x0c,0x0c,0x18,0x0c,0x18,0x18,0x24
4490         byte    0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4491         byte    0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4492         byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4493         byte    0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4494         byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4495         byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4496         byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4497         byte    0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4498         byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4499         byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4500         byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4501         byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4502         byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4503         byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4504         byte    0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4505         byte    0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30
4506         byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4507         byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4508         byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4509         byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4510         byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4511         byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4512         byte    0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4513         byte    0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c
4514         byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4515         byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4516         byte    0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4517         byte    0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48
4518         byte    0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4519         byte    0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54
4520         byte    0x3c,0x48,0x48,0x54,0x48,0x54,0x54,0x60
4521
4522 #
4523 # table to convert a pre-decrement bit string into a post-increment
4524 # or control bit string.
4525 # ex:   0x00    ==>     0x00
4526 #       0x01    ==>     0x80
4527 #       0x02    ==>     0x40
4528 #               .
4529 #               .
4530 #       0xfd    ==>     0xbf
4531 #       0xfe    ==>     0x7f
4532 #       0xff    ==>     0xff
4533 #
4534 tbl_fmovm_convert:
4535         byte    0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0
4536         byte    0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0
4537         byte    0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8
4538         byte    0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8
4539         byte    0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4
4540         byte    0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4
4541         byte    0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec
4542         byte    0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc
4543         byte    0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2
4544         byte    0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2
4545         byte    0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea
4546         byte    0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa
4547         byte    0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6
4548         byte    0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6
4549         byte    0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee
4550         byte    0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe
4551         byte    0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1
4552         byte    0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1
4553         byte    0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9
4554         byte    0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9
4555         byte    0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5
4556         byte    0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5
4557         byte    0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed
4558         byte    0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd
4559         byte    0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3
4560         byte    0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3
4561         byte    0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb
4562         byte    0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb
4563         byte    0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7
4564         byte    0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7
4565         byte    0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef
4566         byte    0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
4567
4568         global          fmovm_calc_ea
4569 ###############################################
4570 # _fmovm_calc_ea: calculate effective address #
4571 ###############################################
4572 fmovm_calc_ea:
4573         mov.l           %d0,%a0                 # move # bytes to a0
4574
4575 # currently, MODE and REG are taken from the EXC_OPWORD. this could be
4576 # easily changed if they were inputs passed in registers.
4577         mov.w           EXC_OPWORD(%a6),%d0     # fetch opcode word
4578         mov.w           %d0,%d1                 # make a copy
4579
4580         andi.w          &0x3f,%d0               # extract mode field
4581         andi.l          &0x7,%d1                # extract reg  field
4582
4583 # jump to the corresponding function for each {MODE,REG} pair.
4584         mov.w           (tbl_fea_mode.b,%pc,%d0.w*2),%d0 # fetch jmp distance
4585         jmp             (tbl_fea_mode.b,%pc,%d0.w*1) # jmp to correct ea mode
4586
4587         swbeg           &64
4588 tbl_fea_mode:
4589         short           tbl_fea_mode    -       tbl_fea_mode
4590         short           tbl_fea_mode    -       tbl_fea_mode
4591         short           tbl_fea_mode    -       tbl_fea_mode
4592         short           tbl_fea_mode    -       tbl_fea_mode
4593         short           tbl_fea_mode    -       tbl_fea_mode
4594         short           tbl_fea_mode    -       tbl_fea_mode
4595         short           tbl_fea_mode    -       tbl_fea_mode
4596         short           tbl_fea_mode    -       tbl_fea_mode
4597
4598         short           tbl_fea_mode    -       tbl_fea_mode
4599         short           tbl_fea_mode    -       tbl_fea_mode
4600         short           tbl_fea_mode    -       tbl_fea_mode
4601         short           tbl_fea_mode    -       tbl_fea_mode
4602         short           tbl_fea_mode    -       tbl_fea_mode
4603         short           tbl_fea_mode    -       tbl_fea_mode
4604         short           tbl_fea_mode    -       tbl_fea_mode
4605         short           tbl_fea_mode    -       tbl_fea_mode
4606
4607         short           faddr_ind_a0    -       tbl_fea_mode
4608         short           faddr_ind_a1    -       tbl_fea_mode
4609         short           faddr_ind_a2    -       tbl_fea_mode
4610         short           faddr_ind_a3    -       tbl_fea_mode
4611         short           faddr_ind_a4    -       tbl_fea_mode
4612         short           faddr_ind_a5    -       tbl_fea_mode
4613         short           faddr_ind_a6    -       tbl_fea_mode
4614         short           faddr_ind_a7    -       tbl_fea_mode
4615
4616         short           faddr_ind_p_a0  -       tbl_fea_mode
4617         short           faddr_ind_p_a1  -       tbl_fea_mode
4618         short           faddr_ind_p_a2  -       tbl_fea_mode
4619         short           faddr_ind_p_a3  -       tbl_fea_mode
4620         short           faddr_ind_p_a4  -       tbl_fea_mode
4621         short           faddr_ind_p_a5  -       tbl_fea_mode
4622         short           faddr_ind_p_a6  -       tbl_fea_mode
4623         short           faddr_ind_p_a7  -       tbl_fea_mode
4624
4625         short           faddr_ind_m_a0  -       tbl_fea_mode
4626         short           faddr_ind_m_a1  -       tbl_fea_mode
4627         short           faddr_ind_m_a2  -       tbl_fea_mode
4628         short           faddr_ind_m_a3  -       tbl_fea_mode
4629         short           faddr_ind_m_a4  -       tbl_fea_mode
4630         short           faddr_ind_m_a5  -       tbl_fea_mode
4631         short           faddr_ind_m_a6  -       tbl_fea_mode
4632         short           faddr_ind_m_a7  -       tbl_fea_mode
4633
4634         short           faddr_ind_disp_a0       -       tbl_fea_mode
4635         short           faddr_ind_disp_a1       -       tbl_fea_mode
4636         short           faddr_ind_disp_a2       -       tbl_fea_mode
4637         short           faddr_ind_disp_a3       -       tbl_fea_mode
4638         short           faddr_ind_disp_a4       -       tbl_fea_mode
4639         short           faddr_ind_disp_a5       -       tbl_fea_mode
4640         short           faddr_ind_disp_a6       -       tbl_fea_mode
4641         short           faddr_ind_disp_a7       -       tbl_fea_mode
4642
4643         short           faddr_ind_ext   -       tbl_fea_mode
4644         short           faddr_ind_ext   -       tbl_fea_mode
4645         short           faddr_ind_ext   -       tbl_fea_mode
4646         short           faddr_ind_ext   -       tbl_fea_mode
4647         short           faddr_ind_ext   -       tbl_fea_mode
4648         short           faddr_ind_ext   -       tbl_fea_mode
4649         short           faddr_ind_ext   -       tbl_fea_mode
4650         short           faddr_ind_ext   -       tbl_fea_mode
4651
4652         short           fabs_short      -       tbl_fea_mode
4653         short           fabs_long       -       tbl_fea_mode
4654         short           fpc_ind         -       tbl_fea_mode
4655         short           fpc_ind_ext     -       tbl_fea_mode
4656         short           tbl_fea_mode    -       tbl_fea_mode
4657         short           tbl_fea_mode    -       tbl_fea_mode
4658         short           tbl_fea_mode    -       tbl_fea_mode
4659         short           tbl_fea_mode    -       tbl_fea_mode
4660
4661 ###################################
4662 # Address register indirect: (An) #
4663 ###################################
4664 faddr_ind_a0:
4665         mov.l           EXC_DREGS+0x8(%a6),%a0  # Get current a0
4666         rts
4667
4668 faddr_ind_a1:
4669         mov.l           EXC_DREGS+0xc(%a6),%a0  # Get current a1
4670         rts
4671
4672 faddr_ind_a2:
4673         mov.l           %a2,%a0                 # Get current a2
4674         rts
4675
4676 faddr_ind_a3:
4677         mov.l           %a3,%a0                 # Get current a3
4678         rts
4679
4680 faddr_ind_a4:
4681         mov.l           %a4,%a0                 # Get current a4
4682         rts
4683
4684 faddr_ind_a5:
4685         mov.l           %a5,%a0                 # Get current a5
4686         rts
4687
4688 faddr_ind_a6:
4689         mov.l           (%a6),%a0               # Get current a6
4690         rts
4691
4692 faddr_ind_a7:
4693         mov.l           EXC_A7(%a6),%a0         # Get current a7
4694         rts
4695
4696 #####################################################
4697 # Address register indirect w/ postincrement: (An)+ #
4698 #####################################################
4699 faddr_ind_p_a0:
4700         mov.l           EXC_DREGS+0x8(%a6),%d0  # Get current a0
4701         mov.l           %d0,%d1
4702         add.l           %a0,%d1                 # Increment
4703         mov.l           %d1,EXC_DREGS+0x8(%a6)  # Save incr value
4704         mov.l           %d0,%a0
4705         rts
4706
4707 faddr_ind_p_a1:
4708         mov.l           EXC_DREGS+0xc(%a6),%d0  # Get current a1
4709         mov.l           %d0,%d1
4710         add.l           %a0,%d1                 # Increment
4711         mov.l           %d1,EXC_DREGS+0xc(%a6)  # Save incr value
4712         mov.l           %d0,%a0
4713         rts
4714
4715 faddr_ind_p_a2:
4716         mov.l           %a2,%d0                 # Get current a2
4717         mov.l           %d0,%d1
4718         add.l           %a0,%d1                 # Increment
4719         mov.l           %d1,%a2                 # Save incr value
4720         mov.l           %d0,%a0
4721         rts
4722
4723 faddr_ind_p_a3:
4724         mov.l           %a3,%d0                 # Get current a3
4725         mov.l           %d0,%d1
4726         add.l           %a0,%d1                 # Increment
4727         mov.l           %d1,%a3                 # Save incr value
4728         mov.l           %d0,%a0
4729         rts
4730
4731 faddr_ind_p_a4:
4732         mov.l           %a4,%d0                 # Get current a4
4733         mov.l           %d0,%d1
4734         add.l           %a0,%d1                 # Increment
4735         mov.l           %d1,%a4                 # Save incr value
4736         mov.l           %d0,%a0
4737         rts
4738
4739 faddr_ind_p_a5:
4740         mov.l           %a5,%d0                 # Get current a5
4741         mov.l           %d0,%d1
4742         add.l           %a0,%d1                 # Increment
4743         mov.l           %d1,%a5                 # Save incr value
4744         mov.l           %d0,%a0
4745         rts
4746
4747 faddr_ind_p_a6:
4748         mov.l           (%a6),%d0               # Get current a6
4749         mov.l           %d0,%d1
4750         add.l           %a0,%d1                 # Increment
4751         mov.l           %d1,(%a6)               # Save incr value
4752         mov.l           %d0,%a0
4753         rts
4754
4755 faddr_ind_p_a7:
4756         mov.b           &mia7_flg,SPCOND_FLG(%a6) # set "special case" flag
4757
4758         mov.l           EXC_A7(%a6),%d0         # Get current a7
4759         mov.l           %d0,%d1
4760         add.l           %a0,%d1                 # Increment
4761         mov.l           %d1,EXC_A7(%a6)         # Save incr value
4762         mov.l           %d0,%a0
4763         rts
4764
4765 ####################################################
4766 # Address register indirect w/ predecrement: -(An) #
4767 ####################################################
4768 faddr_ind_m_a0:
4769         mov.l           EXC_DREGS+0x8(%a6),%d0  # Get current a0
4770         sub.l           %a0,%d0                 # Decrement
4771         mov.l           %d0,EXC_DREGS+0x8(%a6)  # Save decr value
4772         mov.l           %d0,%a0
4773         rts
4774
4775 faddr_ind_m_a1:
4776         mov.l           EXC_DREGS+0xc(%a6),%d0  # Get current a1
4777         sub.l           %a0,%d0                 # Decrement
4778         mov.l           %d0,EXC_DREGS+0xc(%a6)  # Save decr value
4779         mov.l           %d0,%a0
4780         rts
4781
4782 faddr_ind_m_a2:
4783         mov.l           %a2,%d0                 # Get current a2
4784         sub.l           %a0,%d0                 # Decrement
4785         mov.l           %d0,%a2                 # Save decr value
4786         mov.l           %d0,%a0
4787         rts
4788
4789 faddr_ind_m_a3:
4790         mov.l           %a3,%d0                 # Get current a3
4791         sub.l           %a0,%d0                 # Decrement
4792         mov.l           %d0,%a3                 # Save decr value
4793         mov.l           %d0,%a0
4794         rts
4795
4796 faddr_ind_m_a4:
4797         mov.l           %a4,%d0                 # Get current a4
4798         sub.l           %a0,%d0                 # Decrement
4799         mov.l           %d0,%a4                 # Save decr value
4800         mov.l           %d0,%a0
4801         rts
4802
4803 faddr_ind_m_a5:
4804         mov.l           %a5,%d0                 # Get current a5
4805         sub.l           %a0,%d0                 # Decrement
4806         mov.l           %d0,%a5                 # Save decr value
4807         mov.l           %d0,%a0
4808         rts
4809
4810 faddr_ind_m_a6:
4811         mov.l           (%a6),%d0               # Get current a6
4812         sub.l           %a0,%d0                 # Decrement
4813         mov.l           %d0,(%a6)               # Save decr value
4814         mov.l           %d0,%a0
4815         rts
4816
4817 faddr_ind_m_a7:
4818         mov.b           &mda7_flg,SPCOND_FLG(%a6) # set "special case" flag
4819
4820         mov.l           EXC_A7(%a6),%d0         # Get current a7
4821         sub.l           %a0,%d0                 # Decrement
4822         mov.l           %d0,EXC_A7(%a6)         # Save decr value
4823         mov.l           %d0,%a0
4824         rts
4825
4826 ########################################################
4827 # Address register indirect w/ displacement: (d16, An) #
4828 ########################################################
4829 faddr_ind_disp_a0:
4830         mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4831         addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4832         bsr.l           _imem_read_word
4833
4834         tst.l           %d1                     # did ifetch fail?
4835         bne.l           iea_iacc                # yes
4836
4837         mov.w           %d0,%a0                 # sign extend displacement
4838
4839         add.l           EXC_DREGS+0x8(%a6),%a0  # a0 + d16
4840         rts
4841
4842 faddr_ind_disp_a1:
4843         mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4844         addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4845         bsr.l           _imem_read_word
4846
4847         tst.l           %d1                     # did ifetch fail?
4848         bne.l           iea_iacc                # yes
4849
4850         mov.w           %d0,%a0                 # sign extend displacement
4851
4852         add.l           EXC_DREGS+0xc(%a6),%a0  # a1 + d16
4853         rts
4854
4855 faddr_ind_disp_a2:
4856         mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4857         addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4858         bsr.l           _imem_read_word
4859
4860         tst.l           %d1                     # did ifetch fail?
4861         bne.l           iea_iacc                # yes
4862
4863         mov.w           %d0,%a0                 # sign extend displacement
4864
4865         add.l           %a2,%a0                 # a2 + d16
4866         rts
4867
4868 faddr_ind_disp_a3:
4869         mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4870         addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4871         bsr.l           _imem_read_word
4872
4873         tst.l           %d1                     # did ifetch fail?
4874         bne.l           iea_iacc                # yes
4875
4876         mov.w           %d0,%a0                 # sign extend displacement
4877
4878         add.l           %a3,%a0                 # a3 + d16
4879         rts
4880
4881 faddr_ind_disp_a4:
4882         mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4883         addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4884         bsr.l           _imem_read_word
4885
4886         tst.l           %d1                     # did ifetch fail?
4887         bne.l           iea_iacc                # yes
4888
4889         mov.w           %d0,%a0                 # sign extend displacement
4890
4891         add.l           %a4,%a0                 # a4 + d16
4892         rts
4893
4894 faddr_ind_disp_a5:
4895         mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4896         addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4897         bsr.l           _imem_read_word
4898
4899         tst.l           %d1                     # did ifetch fail?
4900         bne.l           iea_iacc                # yes
4901
4902         mov.w           %d0,%a0                 # sign extend displacement
4903
4904         add.l           %a5,%a0                 # a5 + d16
4905         rts
4906
4907 faddr_ind_disp_a6:
4908         mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4909         addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4910         bsr.l           _imem_read_word
4911
4912         tst.l           %d1                     # did ifetch fail?
4913         bne.l           iea_iacc                # yes
4914
4915         mov.w           %d0,%a0                 # sign extend displacement
4916
4917         add.l           (%a6),%a0               # a6 + d16
4918         rts
4919
4920 faddr_ind_disp_a7:
4921         mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4922         addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4923         bsr.l           _imem_read_word
4924
4925         tst.l           %d1                     # did ifetch fail?
4926         bne.l           iea_iacc                # yes
4927
4928         mov.w           %d0,%a0                 # sign extend displacement
4929
4930         add.l           EXC_A7(%a6),%a0         # a7 + d16
4931         rts
4932
4933 ########################################################################
4934 # Address register indirect w/ index(8-bit displacement): (d8, An, Xn) #
4935 #    "       "         "    w/   "  (base displacement): (bd, An, Xn)  #
4936 # Memory indirect postindexed: ([bd, An], Xn, od)                      #
4937 # Memory indirect preindexed: ([bd, An, Xn], od)                       #
4938 ########################################################################
4939 faddr_ind_ext:
4940         addq.l          &0x8,%d1
4941         bsr.l           fetch_dreg              # fetch base areg
4942         mov.l           %d0,-(%sp)
4943
4944         mov.l           EXC_EXTWPTR(%a6),%a0    # fetch instruction addr
4945         addq.l          &0x2,EXC_EXTWPTR(%a6)   # incr instruction ptr
4946         bsr.l           _imem_read_word         # fetch extword in d0
4947
4948         tst.l           %d1                     # did ifetch fail?
4949         bne.l           iea_iacc                # yes
4950
4951         mov.l           (%sp)+,%a0
4952
4953         btst            &0x8,%d0
4954         bne.w           fcalc_mem_ind
4955
4956         mov.l           %d0,L_SCR1(%a6)         # hold opword
4957
4958         mov.l           %d0,%d1
4959         rol.w           &0x4,%d1
4960         andi.w          &0xf,%d1                # extract index regno
4961
4962 # count on fetch_dreg() not to alter a0...
4963         bsr.l           fetch_dreg              # fetch index
4964
4965         mov.l           %d2,-(%sp)              # save d2
4966         mov.l           L_SCR1(%a6),%d2         # fetch opword
4967
4968         btst            &0xb,%d2                # is it word or long?
4969         bne.b           faii8_long
4970         ext.l           %d0                     # sign extend word index
4971 faii8_long:
4972         mov.l           %d2,%d1
4973         rol.w           &0x7,%d1
4974         andi.l          &0x3,%d1                # extract scale value
4975
4976         lsl.l           %d1,%d0                 # shift index by scale
4977
4978         extb.l          %d2                     # sign extend displacement
4979         add.l           %d2,%d0                 # index + disp
4980         add.l           %d0,%a0                 # An + (index + disp)
4981
4982         mov.l           (%sp)+,%d2              # restore old d2
4983         rts
4984
4985 ###########################
4986 # Absolute short: (XXX).W #
4987 ###########################
4988 fabs_short:
4989         mov.l       &