1/*        $NetBSD: fp.S,v 1.60 2025/05/03 02:00:46 riastradh Exp $    */
2
3/*
4 * Copyright (c) 1992, 1993
5 *        The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Ralph Campbell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 *        @(#)fp.s  8.1 (Berkeley) 6/10/93
35 */
36
37#ifdef _KERNEL_OPT
38#include "opt_cputype.h"
39#endif
40
41#include <sys/cdefs.h>
42
43#include <mips/asm.h>
44#include <mips/trap.h>
45#include <mips/cpuregs.h>
46
47#include <mips/locore.h>
48
49#include "assym.h"
50
51#define SEXP_INF    0xff
52#define DEXP_INF    0x7ff
53#define SEXP_BIAS   127
54#define DEXP_BIAS   1023
55#define SEXP_MIN    -126
56#define DEXP_MIN    -1022
57#define SEXP_MAX    127
58#define DEXP_MAX    1023
59#define WEXP_MAX    30                  /* maximum unbiased exponent for int */
60#define WEXP_MIN    -1                  /* minimum unbiased exponent for int */
61#define SFRAC_BITS  23
62#define DFRAC_BITS  52
63#define SIMPL_ONE   0x00800000
64#define DIMPL_ONE   0x00100000
65#define SLEAD_ZEROS 31 - 23
66#define DLEAD_ZEROS 31 - 20
67#define STICKYBIT   1
68#define GUARDBIT    0x80000000
69#define SSIGNAL_NAN 0x00400000
70#define DSIGNAL_NAN 0x00080000
71#define SQUIET_NAN  0x003fffff
72#define DQUIET_NAN0 0x0007ffff
73#define DQUIET_NAN1 0xffffffff
74#define INT_MIN               0x80000000
75#define INT_MAX               0x7fffffff
76
77#define COND_UNORDERED        0x1
78#define COND_EQUAL  0x2
79#define COND_LESS   0x4
80#define COND_SIGNAL 0x8
81
82#if defined(FPEMUL)
83#if defined(__mips_o32) || defined(__mips_o64)
84#define FPX_L                           INT_L
85#define FPX_S                           INT_S
86#define   FPX_SCALESHIFT                INT_SCALESHIFT
87#else
88#define FPX_L                           LONG_L
89#define FPX_S                           LONG_S
90#define   FPX_SCALESHIFT                LONG_SCALESHIFT
91#define DFPX_L                          REG_L
92#define DFPX_S                          REG_S
93#define   DFPX_SCALESHIFT               REG_SCALESHIFT
94#define   SZDFREG                       SZREG
95#define   DFPX_REGMASK                  (0x1F << DFPX_SCALESHIFT)
96#define   DFPX_REGEVENMASK    (0x1E << DFPX_SCALESHIFT)
97#endif
98#define   SZFREG                        (1 << FPX_SCALESHIFT)
99#define   FPX_REGMASK                   (0x1F << FPX_SCALESHIFT)
100#define   FPX_REGEVENMASK               (0x1E << FPX_SCALESHIFT)
101#define   REG_REGMASK                   (0x1F << REG_SCALESHIFT)
102#endif
103
104/* insns are reordered in the way as MIPS architecture imposes */
105          .set      reorder
106
107/*----------------------------------------------------------------------------
108 *
109 * mips_emul_fp --
110 *
111 *        Emulate unimplemented floating point operations.
112 *        This routine should only be called by mips_fpu_intr().
113 *
114 *        mips_emul_fp(uint32_t instr, struct trapframe *tf, uint32_t cause)
115 *
116 * Results:
117 *        None.
118 *
119 * Side effects:
120 *        Floating point registers are modified according to instruction.
121 *
122 *----------------------------------------------------------------------------
123 */
124#if defined(__mips_o32) || defined(__mips_o64)
125#define   CALLFRAME_FRAME               (CALLFRAME_SIZ + 1*SZREG)     /* a1 slot */
126#define   CALLFRAME_CAUSE               (CALLFRAME_SIZ + 2*SZREG)     /* a2 slot */
127#endif
128#if defined(__mips_n32) || defined(__mips_n64)
129#define   CALLFRAME_FRAME               (1*SZREG)
130#define   CALLFRAME_CAUSE               (2*SZREG)
131#if CALLFRAME_RA == CALLFRAME_FRAME || CALLFRAME_RA == CALLFRAME_CAUSE
132#error N32/N64 ABI callframe error
133#endif
134#endif
135NESTED(mips_emul_fp, CALLFRAME_SIZ, ra)
136          PTR_SUBU sp, CALLFRAME_SIZ
137          REG_S     ra, CALLFRAME_RA(sp)
138          REG_S     a1, CALLFRAME_FRAME(sp)
139          REG_S     a2, CALLFRAME_CAUSE(sp)
140/*
141 * Decode the FMT field (bits 25-21) and FUNCTION field (bits 5-0).
142 */
143          srl       v0, a0, 21 - PTR_SCALESHIFT   # get FMT field
144          andi      v0, v0, 0x1F << PTR_SCALESHIFT          # mask FMT field
145#ifdef FPEMUL
146          PTR_L     t0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
147          PTR_L     a3, fmt_tbl(v0)                         # switch on FUNC & FMT
148          INT_L     a2, PCB_FPREGS+FRAME_FSR(t0)
149#else
150          cfc1      a2, MIPS_FCSR                           # get exception register
151          PTR_L     a3, fmt_tbl(v0)                         # switch on FUNC & FMT
152          and       a2, a2, ~MIPS_FCSR_CAUSE      # clear exception
153          ctc1      a2, MIPS_FCSR
154#endif
155          j         a3
156
157single_op:
158          andi      v0, a0, 0x3F                  # get FUNC field
159          sll       v0, v0, PTR_SCALESHIFT
160          PTR_L     t9, func_single_tbl(v0)
161          j         t9
162double_op:
163          andi      v0, a0, 0x3F                  # get FUNC field
164          sll       v0, v0, PTR_SCALESHIFT
165          PTR_L     t9, func_double_tbl(v0)
166          j         t9
167single_fixed_op:
168          andi      v0, a0, 0x3F                  # get FUNC field
169          sll       v0, v0, PTR_SCALESHIFT
170          PTR_L     t9, func_single_fixed_tbl(v0)
171          j         t9
172long_fixed_op:
173          andi      v0, a0, 0x3F                  # get FUNC field
174          sll       v0, v0, PTR_SCALESHIFT
175          PTR_L     t9, func_long_fixed_tbl(v0)
176          j         t9
177#if (defined(__mips_n32) || defined(__mips_n64)) && 0
178paired_single_op:
179          andi      v0, a0, 0x3F                  # get FUNC field
180          sll       v0, v0, PTR_SCALESHIFT
181          PTR_L     t9, func_paired_single_tbl(v0)
182          j         t9
183#else
184#define   paired_single_op    ill
185#endif
186
187#ifndef FPEMUL
188#define   mfromc1             ill
189#define   dmfromc1  ill
190#define   cfromc1             ill
191#define   mtoc1               ill
192#define   dmtoc1              ill
193#define   ctoc1               ill
194#define   branchc1  ill
195#elif !(defined(__mips_n32) || defined(__mips_n64))
196#define   dmfromc1  ill
197#define   dmtoc1              ill
198#endif
199#define   branchc1any2        ill
200#define   branchc1any4        ill
201#define   pairedsingle_op     ill
202
203/*
204 * Single Precisions functions
205 */
206#define   recip_s             ill
207#define   recip1_s  ill
208#define   recip2_s  ill
209#define round_l_s   ill
210#define trunc_l_s   ill
211#define ceil_l_s    ill
212#define floor_l_s   ill
213#define cvt_l_s               ill
214#define cvt_ps_s    ill
215#define   movcf_s             ill
216#define   movn_s              ill
217#define   movz_s              ill
218#define   rsqrt_s             ill
219#define   rsqrt1_s  ill
220#define   rsqrt2_s  ill
221#ifndef MIPS3_PLUS
222#define sqrt_s                ill
223#define round_w_s   ill
224#define trunc_w_s   ill
225#define ceil_w_s    ill
226#define floor_w_s   ill
227#endif
228
229/*
230 * Double Precisions functions
231 */
232#ifndef MIPS3_PLUS
233#define sqrt_d                ill
234#define round_w_d   ill
235#define trunc_w_d   ill
236#define ceil_w_d    ill
237#define floor_w_d   ill
238#endif
239#define round_l_d   ill
240#define   ceil_l_d  ill
241#define trunc_l_d   ill
242#define   floor_l_d ill
243#define   recip_d             ill
244#define   recip1_d  ill
245#define   recip2_d  ill
246#define   cvt_l_d             ill
247#define   movcf_d             ill
248#define   movz_d              ill
249#define   movn_d              ill
250#define   recip_d             ill
251#define   rsqrt_d             ill
252#define   rsqrt1_d  ill
253#define   rsqrt2_d  ill
254
255/*
256 * Long Fixed functions
257 */
258#define   cvt_s_l             ill
259#define   cvt_d_l             ill
260#define   cvt_s_pu  ill
261
262/*
263 * Paired Single functions
264 */
265#define   addr_ps             ill
266#define   abs_ps              ill
267#define   add_ps              ill
268#define   cmp_ps              ill
269#define   cvt_ps_pl ill
270#define   cvt_ps_pw ill
271#define   movcf_ps  ill
272#define   movz_ps             ill
273#define   movn_ps             ill
274#define   mov_ps              ill
275#define   mul_ps              ill
276#define   mulr_ps             ill
277#define   neg_ps              ill
278#define   recip1_ps ill
279#define   recip2_ps ill
280#define   rsqrt1_ps ill
281#define   rsqrt2_ps ill
282#define   sub_ps              ill
283
284          .rdata
285fmt_tbl:
286          PTR_WORD mfromc1    # sub 0             mfc1
287          PTR_WORD dmfromc1   # sub 1             dmfc1
288          PTR_WORD cfromc1    # sub 2             cfc1
289          PTR_WORD ill                  # sub 3             mfhc1               MIPS32r2
290          PTR_WORD mtoc1                # sub 4             mtc1
291          PTR_WORD dmtoc1               # sub 5             dmtc1
292          PTR_WORD ctoc1                # sub 6             ctc1
293          PTR_WORD ill                  # sub 7             mthc1               MIPS32r2
294          PTR_WORD branchc1   # sub 8             bc1
295          PTR_WORD branchc1any2         # sub 9             bc1any2             MIPS-3D ASE
296          PTR_WORD branchc1any4         # sub 10  bc1any4             MIPS-3D ASE
297          PTR_WORD ill                  # sub 11
298          PTR_WORD ill                  # sub 12
299          PTR_WORD ill                  # sub 13
300          PTR_WORD ill                  # sub 14
301          PTR_WORD ill                  # sub 15
302          PTR_WORD single_op  # sub 16  S
303          PTR_WORD double_op  # sub 17  D
304          PTR_WORD ill                  # sub 18
305          PTR_WORD ill                  # sub 19
306          PTR_WORD single_fixed_op # sub 20       W
307          PTR_WORD long_fixed_op        # sub 21  L
308          PTR_WORD paired_single_op # sub 22      PS
309          PTR_WORD ill                  # sub 23
310          PTR_WORD ill                  # sub 24
311          PTR_WORD ill                  # sub 25
312          PTR_WORD ill                  # sub 26
313          PTR_WORD ill                  # sub 27
314          PTR_WORD ill                  # sub 28
315          PTR_WORD ill                  # sub 29
316          PTR_WORD ill                  # sub 30
317          PTR_WORD ill                  # sub 31
318
319func_single_tbl:
320          PTR_WORD add_s                # func  0 00        ADD.S
321          PTR_WORD sub_s                # func  1 01        SUB.S
322          PTR_WORD mul_s                # func  2 02        MUL.S
323          PTR_WORD div_s                # func  3 03        DIV.S
324          PTR_WORD sqrt_s               # func  4 04        SQRT.S
325          PTR_WORD abs_s                # func  5 05        ABS.S
326          PTR_WORD mov_s                # func  6 06        MOV.S
327          PTR_WORD neg_s                # func  7 07        NEG.S
328          PTR_WORD round_l_s  # func  8 10        ROUND.L.S MIPS3/MIPS64
329          PTR_WORD trunc_l_s  # func  9 11        TRUNC.L.S MIPS3/MIPS64
330          PTR_WORD ceil_l_s   # func 10 12        CEIL.L.S  MIPS3/MIPS64
331          PTR_WORD floor_l_s  # func 11 13        FLOOR.L.S MIPS3/MIPS64
332          PTR_WORD round_w_s  # func 12 14        ROUND.W.S
333          PTR_WORD trunc_w_s  # func 13 15        TRUNC.W.S
334          PTR_WORD ceil_w_s   # func 14 16        CEIL.W.S
335          PTR_WORD floor_w_s  # func 15 17        FLOOR.W.S
336          PTR_WORD ill                  # func 16 20
337          PTR_WORD movcf_s    # func 17 21        MOVCF.S             MIPS32
338          PTR_WORD movz_s               # func 18 22        MOVZ.S              MIPS32
339          PTR_WORD movn_s               # func 19 23        MOVN.S              MIPS32
340          PTR_WORD ill                  # func 20 24
341          PTR_WORD recip_s    # func 21 25        RECIP.S             MIPS32r2
342          PTR_WORD rsqrt_s    # func 22 26        RSQRT.S             MIPS32r2
343          PTR_WORD ill                  # func 23 27
344          PTR_WORD ill                  # func 24 30
345          PTR_WORD ill                  # func 25 31
346          PTR_WORD ill                  # func 26 32
347          PTR_WORD ill                  # func 27 33
348          PTR_WORD recip2_s   # func 28 34        RECIP2.S  MIPS-3D ASE
349          PTR_WORD recip1_s   # func 29 35        RECIP1.S  MIPS-3D ASE
350          PTR_WORD rsqrt1_s   # func 30 36        RSQRT1.S  MIPS-3D ASE
351          PTR_WORD rsqrt2_s   # func 31 37        RSQRT2.S  MIPS-3D ASE
352          PTR_WORD ill                  # func 32 40
353          PTR_WORD cvt_d_s    # func 33 41        CVT.D.S
354          PTR_WORD ill                  # func 34 42
355          PTR_WORD ill                  # func 35 43
356          PTR_WORD cvt_w_s    # func 36 44        CVT.W.S
357          PTR_WORD cvt_l_s    # func 37 45        CVT.L.S             MIPS3/MIPS64
358          PTR_WORD cvt_ps_s   # func 38 46        CVT.PS.S  MIPS32r2
359          PTR_WORD ill                  # func 39 47
360          PTR_WORD ill                  # func 40 50
361          PTR_WORD ill                  # func 41 51
362          PTR_WORD ill                  # func 42 52
363          PTR_WORD ill                  # func 43 53
364          PTR_WORD ill                  # func 44 54
365          PTR_WORD ill                  # func 45 55
366          PTR_WORD ill                  # func 46 56
367          PTR_WORD ill                  # func 47 57
368          PTR_WORD cmp_s                # func 48 60        C.F.S
369          PTR_WORD cmp_s                # func 49 61        C.UN.S
370          PTR_WORD cmp_s                # func 50 62        C.EQ.S
371          PTR_WORD cmp_s                # func 51 63        C.UEQ.S
372          PTR_WORD cmp_s                # func 52 64        C.OLT.S
373          PTR_WORD cmp_s                # func 53 65        C.ULT.S
374          PTR_WORD cmp_s                # func 54 66        C.OLE.S
375          PTR_WORD cmp_s                # func 55 67        C.ULE.S
376          PTR_WORD cmp_s                # func 56 70        C.SF.S
377          PTR_WORD cmp_s                # func 57 71        C.NGLE.S
378          PTR_WORD cmp_s                # func 58 72        C.SEQ.S
379          PTR_WORD cmp_s                # func 59 73        C.NGL.S
380          PTR_WORD cmp_s                # func 60 74        C.LT.S
381          PTR_WORD cmp_s                # func 61 75        C.NGE.S
382          PTR_WORD cmp_s                # func 62 76        C.LE.S
383          PTR_WORD cmp_s                # func 63 77        C.NGT.S
384
385func_double_tbl:
386          PTR_WORD add_d                # func  0 00        ADD.D
387          PTR_WORD sub_d                # func  1 01        SUB.D
388          PTR_WORD mul_d                # func  2 02        MUL.D
389          PTR_WORD div_d                # func  3 03        DIV.D
390          PTR_WORD sqrt_d               # func  4 04        SQRT.D
391          PTR_WORD abs_d                # func  5 05        ABS.D
392          PTR_WORD mov_d                # func  6 06        MOV.D
393          PTR_WORD neg_d                # func  7 07        NEG.D
394          PTR_WORD round_l_d  # func  8 10        ROUND.L.D MIPS3/MIPS64
395          PTR_WORD trunc_l_d  # func  9 11        TRUNC.L.D MIPS3/MIPS64
396          PTR_WORD ceil_l_d   # func 10 12        CEIL.L.D  MIPS3/MIPS64
397          PTR_WORD floor_l_d  # func 11 13        FLOOR.L.D MIPS3/MIPS64
398          PTR_WORD round_w_d  # func 12 14        ROUND.W.D
399          PTR_WORD trunc_w_d  # func 13 15        TRUNC.W.D
400          PTR_WORD ceil_w_d   # func 14 16        CEIL.W.D
401          PTR_WORD floor_w_d  # func 15 17        FLOOR.W.D
402          PTR_WORD ill                  # func 16 20
403          PTR_WORD movcf_d    # func 17 21        MOVCF.D             MIPS32
404          PTR_WORD movz_d               # func 18 22        MOVZ.D              MIPS32
405          PTR_WORD movn_d               # func 19 23        MOVN.D              MIPS32
406          PTR_WORD ill                  # func 20 24
407          PTR_WORD recip_d    # func 21 25        RECIP.D             MIPS32r2
408          PTR_WORD rsqrt_d    # func 22 26        RSQRT.D             MIPS32r2
409          PTR_WORD ill                  # func 23 27
410          PTR_WORD ill                  # func 24 30
411          PTR_WORD ill                  # func 25 31
412          PTR_WORD ill                  # func 26 32
413          PTR_WORD ill                  # func 27 33
414          PTR_WORD recip2_d   # func 28 34        RECIP2.D  MIPS-3D ASE
415          PTR_WORD recip2_d   # func 29 35        RECIP1.D  MIPS-3D ASE
416          PTR_WORD rsqrt1_d   # func 30 36        RSQRT1.D  MIPS-3D ASE
417          PTR_WORD rsqrt2_d   # func 31 37        RSQRT2.D  MIPS-3D ASE
418          PTR_WORD cvt_s_d    # func 32 40        CVT.S.D
419          PTR_WORD ill                  # func 33 41
420          PTR_WORD ill                  # func 34 42
421          PTR_WORD ill                  # func 35 43
422          PTR_WORD cvt_w_d    # func 36 44        CVT.W.D
423          PTR_WORD cvt_l_d    # func 37 45        CVT.L.D             MIPS3/MIPS64
424          PTR_WORD ill                  # func 38 46
425          PTR_WORD ill                  # func 39 47
426          PTR_WORD ill                  # func 40 50
427          PTR_WORD ill                  # func 41 51
428          PTR_WORD ill                  # func 42 52
429          PTR_WORD ill                  # func 43 53
430          PTR_WORD ill                  # func 44 54
431          PTR_WORD ill                  # func 45 55
432          PTR_WORD ill                  # func 46 56
433          PTR_WORD ill                  # func 47 57
434          PTR_WORD cmp_d                # func 48 60        C.F.D
435          PTR_WORD cmp_d                # func 49 61        C.UN.D
436          PTR_WORD cmp_d                # func 50 62        C.EQ.D
437          PTR_WORD cmp_d                # func 51 63        C.UEQ.D
438          PTR_WORD cmp_d                # func 52 64        C.OLT.D
439          PTR_WORD cmp_d                # func 53 65        C.ULT.D
440          PTR_WORD cmp_d                # func 54 66        C.OLE.D
441          PTR_WORD cmp_d                # func 55 67        C.ULE.D
442          PTR_WORD cmp_d                # func 56 70        C.SF.D
443          PTR_WORD cmp_d                # func 57 71        C.NGLE.D
444          PTR_WORD cmp_d                # func 58 72        C.SEQ.D
445          PTR_WORD cmp_d                # func 59 73        C.NGL.D
446          PTR_WORD cmp_d                # func 60 74        C.LT.D
447          PTR_WORD cmp_d                # func 61 75        C.NGE.D
448          PTR_WORD cmp_d                # func 62 76        C.LE.D
449          PTR_WORD cmp_d                # func 63 77        C.NGT.D
450
451func_single_fixed_tbl:
452          PTR_WORD ill                  # func  0 00
453          PTR_WORD ill                  # func  1 01
454          PTR_WORD ill                  # func  2 02
455          PTR_WORD ill                  # func  3 03
456          PTR_WORD ill                  # func  4 04
457          PTR_WORD ill                  # func  5 05
458          PTR_WORD ill                  # func  6 06
459          PTR_WORD ill                  # func  7 07
460          PTR_WORD ill                  # func  8 10
461          PTR_WORD ill                  # func  9 11
462          PTR_WORD ill                  # func 10 12
463          PTR_WORD ill                  # func 11 13
464          PTR_WORD ill                  # func 12 14
465          PTR_WORD ill                  # func 13 15
466          PTR_WORD ill                  # func 14 16
467          PTR_WORD ill                  # func 15 17
468          PTR_WORD ill                  # func 16 20
469          PTR_WORD ill                  # func 17 21
470          PTR_WORD ill                  # func 18 22
471          PTR_WORD ill                  # func 19 23
472          PTR_WORD ill                  # func 20 24
473          PTR_WORD ill                  # func 21 25
474          PTR_WORD ill                  # func 22 26
475          PTR_WORD ill                  # func 23 27
476          PTR_WORD ill                  # func 24 30
477          PTR_WORD ill                  # func 25 31
478          PTR_WORD ill                  # func 26 32
479          PTR_WORD ill                  # func 27 33
480          PTR_WORD ill                  # func 28 34
481          PTR_WORD ill                  # func 29 35
482          PTR_WORD ill                  # func 30 36
483          PTR_WORD ill                  # func 31 37
484          PTR_WORD cvt_s_w    # func 32 40        CVT.S.W
485          PTR_WORD cvt_d_w    # func 33 41        CVT.D.W
486          PTR_WORD ill                  # func 34 42
487          PTR_WORD ill                  # func 35 43
488          PTR_WORD ill                  # func 36 44
489          PTR_WORD ill                  # func 37 45
490          PTR_WORD cvt_ps_pw  # func 38 46        CVT.PS.PW MIPS-3D ASE
491          PTR_WORD ill                  # func 39 47
492          PTR_WORD ill                  # func 40 50
493          PTR_WORD ill                  # func 41 51
494          PTR_WORD ill                  # func 42 52
495          PTR_WORD ill                  # func 43 53
496          PTR_WORD ill                  # func 44 54
497          PTR_WORD ill                  # func 45 55
498          PTR_WORD ill                  # func 46 56
499          PTR_WORD ill                  # func 47 57
500          PTR_WORD ill                  # func 48 60
501          PTR_WORD ill                  # func 49 61
502          PTR_WORD ill                  # func 50 62
503          PTR_WORD ill                  # func 51 63
504          PTR_WORD ill                  # func 52 64
505          PTR_WORD ill                  # func 53 65
506          PTR_WORD ill                  # func 54 66
507          PTR_WORD ill                  # func 55 67
508          PTR_WORD ill                  # func 56 70
509          PTR_WORD ill                  # func 57 71
510          PTR_WORD ill                  # func 58 72
511          PTR_WORD ill                  # func 59 73
512          PTR_WORD ill                  # func 60 74
513          PTR_WORD ill                  # func 61 75
514          PTR_WORD ill                  # func 62 76
515          PTR_WORD ill                  # func 63 77
516
517func_long_fixed_tbl:
518          PTR_WORD ill                  # func  0 00
519          PTR_WORD ill                  # func  1 01
520          PTR_WORD ill                  # func  2 02
521          PTR_WORD ill                  # func  3 03
522          PTR_WORD ill                  # func  4 04
523          PTR_WORD ill                  # func  5 05
524          PTR_WORD ill                  # func  6 06
525          PTR_WORD ill                  # func  7 07
526          PTR_WORD ill                  # func  8 10
527          PTR_WORD ill                  # func  9 11
528          PTR_WORD ill                  # func 10 12
529          PTR_WORD ill                  # func 11 13
530          PTR_WORD ill                  # func 12 14
531          PTR_WORD ill                  # func 13 15
532          PTR_WORD ill                  # func 14 16
533          PTR_WORD ill                  # func 15 17
534          PTR_WORD ill                  # func 16 20
535          PTR_WORD ill                  # func 17 21
536          PTR_WORD ill                  # func 18 22
537          PTR_WORD ill                  # func 19 23
538          PTR_WORD ill                  # func 20 24
539          PTR_WORD ill                  # func 21 25
540          PTR_WORD ill                  # func 22 26
541          PTR_WORD ill                  # func 23 27
542          PTR_WORD ill                  # func 24 30
543          PTR_WORD ill                  # func 25 31
544          PTR_WORD ill                  # func 26 32
545          PTR_WORD ill                  # func 27 33
546          PTR_WORD ill                  # func 28 34
547          PTR_WORD ill                  # func 29 35
548          PTR_WORD ill                  # func 30 36
549          PTR_WORD ill                  # func 31 37
550          PTR_WORD cvt_s_l    # func 32 40        CVT.S.L             MIPS3/MIPS64
551          PTR_WORD cvt_d_l    # func 33 41        CVT.D.L             MIPS3/MIPS64
552          PTR_WORD ill                  # func 34 42
553          PTR_WORD ill                  # func 35 43
554          PTR_WORD ill                  # func 36 44
555          PTR_WORD ill                  # func 37 45
556          PTR_WORD cvt_ps_pl  # func 38 46        CVT.PS.PL MIPS-3D ASE
557          PTR_WORD ill                  # func 39 47
558          PTR_WORD ill                  # func 40 50
559          PTR_WORD ill                  # func 41 51
560          PTR_WORD ill                  # func 42 52
561          PTR_WORD ill                  # func 43 53
562          PTR_WORD ill                  # func 44 54
563          PTR_WORD ill                  # func 45 55
564          PTR_WORD ill                  # func 46 56
565          PTR_WORD ill                  # func 47 57
566          PTR_WORD ill                  # func 48 60
567          PTR_WORD ill                  # func 49 61
568          PTR_WORD ill                  # func 50 62
569          PTR_WORD ill                  # func 51 63
570          PTR_WORD ill                  # func 52 64
571          PTR_WORD ill                  # func 53 65
572          PTR_WORD ill                  # func 54 66
573          PTR_WORD ill                  # func 55 67
574          PTR_WORD ill                  # func 56 70
575          PTR_WORD ill                  # func 57 71
576          PTR_WORD ill                  # func 58 72
577          PTR_WORD ill                  # func 59 73
578          PTR_WORD ill                  # func 60 74
579          PTR_WORD ill                  # func 61 75
580          PTR_WORD ill                  # func 62 76
581          PTR_WORD ill                  # func 63 77
582
583#if defined(MIPS3_PLUS) && 0
584func_paired_single_tbl:
585          PTR_WORD add_ps               # func  0 00        ADD.PS
586          PTR_WORD sub_ps               # func  1 01        SUB.PS
587          PTR_WORD mul_ps               # func  2 02        MUL.PS
588          PTR_WORD ill                  # func  3 03
589          PTR_WORD ill                  # func  4 04
590          PTR_WORD abs_ps               # func  5 05        ABS.PS
591          PTR_WORD mov_ps               # func  6 06        MOV.PS
592          PTR_WORD neg_ps               # func  7 07        NEG.PS
593          PTR_WORD ill                  # func  8 10
594          PTR_WORD ill                  # func  9 11
595          PTR_WORD ill                  # func 10 12
596          PTR_WORD ill                  # func 11 13
597          PTR_WORD ill                  # func 12 14
598          PTR_WORD ill                  # func 13 15
599          PTR_WORD ill                  # func 14 16
600          PTR_WORD ill                  # func 15 17
601          PTR_WORD ill                  # func 16 20
602          PTR_WORD movcf_ps   # func 17 21        MOVCF.PS  MIPS32
603          PTR_WORD movz_ps    # func 18 22        MOVZ.PS             MIPS32
604          PTR_WORD movn_ps    # func 19 23        MOVN.PS             MIPS32
605          PTR_WORD ill                  # func 20 24
606          PTR_WORD ill                  # func 21 25
607          PTR_WORD ill                  # func 22 26
608          PTR_WORD ill                  # func 23 27
609          PTR_WORD addr_ps    # func 24 30        ADDR.PS             MIPS-3D ASE
610          PTR_WORD ill                  # func 25 31
611          PTR_WORD mulr_ps    # func 26 32        MULR.PS             MIPS-3D ASE
612          PTR_WORD ill                  # func 27 33
613          PTR_WORD recip2_ps  # func 28 34        RECIP2.PS MIPS-3D ASE
614          PTR_WORD recip1_ps  # func 29 35        RECIP1.PS MIPS-3D ASE
615          PTR_WORD rsqrt1_ps  # func 30 36        RSQRT1.PS MIPS-3D ASE
616          PTR_WORD rsqrt2_ps  # func 31 37        RSQRT2.PS MIPS-3D ASE
617          PTR_WORD cvt_s_pu   # func 32 40        CVT.S.PU
618          PTR_WORD ill                  # func 33 41
619          PTR_WORD ill                  # func 34 42
620          PTR_WORD ill                  # func 35 43
621          PTR_WORD ill                  # func 36 44        CVT.PW.PS
622          PTR_WORD ill                  # func 37 45
623          PTR_WORD ill                  # func 38 46
624          PTR_WORD ill                  # func 39 47
625          PTR_WORD ill                  # func 40 50        CVT.S.PL
626          PTR_WORD ill                  # func 41 51
627          PTR_WORD ill                  # func 42 52
628          PTR_WORD ill                  # func 43 53
629          PTR_WORD ill                  # func 44 54        PLL.PS
630          PTR_WORD ill                  # func 45 55        PLU.PS
631          PTR_WORD ill                  # func 46 56        PUL.PS
632          PTR_WORD ill                  # func 47 57        PUU.PS
633          PTR_WORD cmp_ps               # func 48 60        C.F
634          PTR_WORD cmp_ps               # func 49 61        C.UN
635          PTR_WORD cmp_ps               # func 50 62        C.EQ
636          PTR_WORD cmp_ps               # func 51 63        C.UEQ
637          PTR_WORD cmp_ps               # func 52 64        C.OLT
638          PTR_WORD cmp_ps               # func 53 65        C.ULT
639          PTR_WORD cmp_ps               # func 54 66        C.OLE
640          PTR_WORD cmp_ps               # func 55 67        C.ULE
641          PTR_WORD cmp_ps               # func 56 70        C.SF
642          PTR_WORD cmp_ps               # func 57 71        C.NGLE
643          PTR_WORD cmp_ps               # func 58 72        C.SEQ
644          PTR_WORD cmp_ps               # func 59 73        C.NGL
645          PTR_WORD cmp_ps               # func 60 74        C.LT
646          PTR_WORD cmp_ps               # func 61 75        C.NGE
647          PTR_WORD cmp_ps               # func 62 76        C.LE
648          PTR_WORD cmp_ps               # func 63 77        C.NGT
649#endif
650
651          .text
652
653#ifdef FPEMUL
654mfromc1:
655          srl       t1, a0, 11-FPX_SCALESHIFT     # fs is in bits 15:11
656          PTR_L     t0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
657          andi      t1, t1, FPX_REGMASK
658          PTR_ADDU t0, t0, t1
659
660          FPX_L     v0, PCB_FPREGS+FRAME_FP0(t0)
661
662          srl       t0, a0, 16-REG_SCALESHIFT
663          andi      t0, t0, REG_REGMASK
664          PTR_ADDU t0, t0, a1
665
666          REG_PROLOGUE
667          REG_S     v0, TF_REG_ZERO(t0)
668          REG_EPILOGUE
669
670          b         done
671
672mtoc1:
673          REG_PROLOGUE
674          REG_S     zero, TF_REG_ZERO(a1)                   # ensure zero has value 0
675          srl       t0, a0, 16-REG_SCALESHIFT
676          andi      t0, t0, REG_REGMASK
677          PTR_ADDU v0, a1, t0
678          REG_L     v0, TF_REG_ZERO(v0)
679          REG_EPILOGUE
680
681          srl       t1, a0, 11-FPX_SCALESHIFT
682          PTR_L     t0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
683          andi      t1, t1, FPX_REGMASK
684          PTR_ADDU t0, t0, t1
685
686          FPX_S     v0, PCB_FPREGS+FRAME_FP0(t0)
687
688          b         done
689
690#if defined(FPEMUL) && (defined(__mips_n32) || defined(__mips_n64))
691dmfromc1:
692          srl       t1, a0, 11-DFPX_SCALESHIFT    # fs is in bits 15:11
693          PTR_L     t0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
694          andi      t1, t1,  DFPX_REGMASK
695          PTR_ADDU t0, t0, t1
696
697          DFPX_L    v0, PCB_FPREGS+FRAME_FP0(t0)
698
699          srl       t0, a0, 16-REG_SCALESHIFT
700          andi      t0, t0, REG_REGMASK
701          PTR_ADDU t0, t0, a1
702
703          REG_PROLOGUE
704          REG_S     v0, TF_REG_ZERO(t0)
705          REG_EPILOGUE
706
707          b         done
708
709dmtoc1:
710          REG_PROLOGUE
711          REG_S     zero, TF_REG_ZERO(a1)                   # ensure zero has value 0
712          srl       t0, a0, 16-REG_SCALESHIFT
713          andi      t0, t0, REG_REGMASK
714          PTR_ADDU v0, a1, t0
715          REG_L     v0, TF_REG_ZERO(v0)
716          REG_EPILOGUE
717
718          srl       t1, a0, 11-DFPX_SCALESHIFT
719          PTR_L     t0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
720          andi      t1, t1, DFPX_REGMASK
721          PTR_ADDU t0, t0, t1
722
723          DFPX_S    v0, PCB_FPREGS+FRAME_FP0(t0)
724
725          b         done
726#endif /* FPEMUL && (__mips_n32 || __mips_n64) */
727
728cfromc1:
729          srl       t1, a0, 11
730          PTR_L     t0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
731          andi      t1, t1, 0x001F
732          li        t2, 0x1F
733          move      v0, zero
734          bne       t1, t2, cfinvalid
735
736          INT_L     v0, PCB_FPREGS+FRAME_FSR(t0)
737
738cfinvalid:
739
740          srl       t0, a0, 16-REG_SCALESHIFT
741          andi      t0, t0, REG_REGMASK
742          PTR_ADDU t0, t0, a1
743
744          REG_PROLOGUE
745          REG_S     v0, TF_REG_ZERO(t0)
746          REG_EPILOGUE
747
748          b         done
749
750ctoc1:
751          REG_PROLOGUE
752          REG_S     zero, TF_REG_ZERO(a1)                   # ensure zero has value 0
753          REG_EPILOGUE
754
755          srl       t0, a0, 11
756          andi      t0, t0, 0x001F
757          li        t1, 0x1F
758          bne       t0, t1, done
759
760          srl       t0, a0, 16-REG_SCALESHIFT
761          andi      t0, t0, REG_REGMASK
762          PTR_ADDU v0, a1, t0
763          REG_PROLOGUE
764          REG_L     v0, TF_REG_ZERO(v0)
765          REG_EPILOGUE
766          PTR_L     t0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
767          #nop
768          INT_S     v0, PCB_FPREGS+FRAME_FSR(t0)
769
770          b         done
771
772branchc1:
773          srl       v0, a0, 16 - PTR_SCALESHIFT
774          andi      v0, v0, 0x1f << PTR_SCALESHIFT
775          PTR_L     t9, branchc1_tbl(v0)
776          j         t9
777
778          .rdata
779branchc1_tbl:
780          PTR_WORD bcfalse    # br 0
781          PTR_WORD bctrue               # br 1
782          PTR_WORD bcfalse_l  # br 2
783          PTR_WORD bctrue_l   # br 3
784          PTR_WORD ill                  # br 4
785          PTR_WORD ill                  # br 5
786          PTR_WORD ill                  # br 6
787          PTR_WORD ill                  # br 7
788          PTR_WORD ill                  # br 8
789          PTR_WORD ill                  # br 9
790          PTR_WORD ill                  # br 10
791          PTR_WORD ill                  # br 11
792          PTR_WORD ill                  # br 12
793          PTR_WORD ill                  # br 13
794          PTR_WORD ill                  # br 14
795          PTR_WORD ill                  # br 15
796          PTR_WORD ill                  # br 16
797          PTR_WORD ill                  # br 17
798          PTR_WORD ill                  # br 18
799          PTR_WORD ill                  # br 19
800          PTR_WORD ill                  # br 20
801          PTR_WORD ill                  # br 21
802          PTR_WORD ill                  # br 22
803          PTR_WORD ill                  # br 23
804          PTR_WORD ill                  # br 24
805          PTR_WORD ill                  # br 25
806          PTR_WORD ill                  # br 26
807          PTR_WORD ill                  # br 27
808          PTR_WORD ill                  # br 28
809          PTR_WORD ill                  # br 29
810          PTR_WORD ill                  # br 30
811          PTR_WORD ill                  # br 31
812
813          .text
814
815bcfalse:
816          li        v0, MIPS_FCSR_FCC0
817          and       v0, v0, a2
818          beq       v0, zero, bcemul_branch
819          b         done
820bctrue:
821          li        v0, MIPS_FCSR_FCC0
822          and       v0, v0, a2
823          bne       v0, zero, bcemul_branch
824          b         done
825bcfalse_l:
826          li        v0, MIPS_FCSR_FCC0
827          and       v0, v0, a2
828          beq       v0, zero, bcemul_branch
829          REG_PROLOGUE
830          REG_L     v0, TF_REG_EPC(a1)
831          addiu     v0, v0, 4
832          REG_S     v0, TF_REG_EPC(a1)
833          REG_EPILOGUE
834          b         done
835bctrue_l:
836          li        v0, MIPS_FCSR_FCC0
837          and       v0, v0, a2
838          bne       v0, zero, bcemul_branch
839          REG_PROLOGUE
840          REG_L     v0, TF_REG_EPC(a1)
841          addiu     v0, v0, 4
842          REG_S     v0, TF_REG_EPC(a1)
843          REG_EPILOGUE
844          b         done
845
846bcemul_branch:
847          /* Fetch delay slot instruction */
848          REG_L     a1, CALLFRAME_FRAME(sp)
849          REG_PROLOGUE
850          REG_L     a0, TF_REG_EPC(a1)
851          REG_EPILOGUE
852          PTR_ADDU a0, 4
853          jal       _C_LABEL(mips_ufetch32)
854
855          move      a0, v0
856          REG_L     a1, CALLFRAME_FRAME(sp)
857          REG_L     a2, CALLFRAME_CAUSE(sp)
858
859          /* Update cause */
860          li        t0, MIPS_CR_BR_DELAY
861          or        a2, a2, t0
862
863          /* Free mips_emul_fp call frame */
864          REG_L     ra, CALLFRAME_RA(sp)
865          PTR_ADDU sp, CALLFRAME_SIZ
866
867          j         _C_LABEL(mips_emul_branchdelayslot)
868#endif
869
870/*
871 * Single precision subtract.
872 */
873sub_s:
874          jal       _C_LABEL(get_ft_fs_s)
875          xor       ta0, ta0, 1                             # negate FT sign bit
876          b         add_sub_s
877/*
878 * Single precision add.
879 */
880add_s:
881          jal       _C_LABEL(get_ft_fs_s)
882add_sub_s:
883          bne       t1, SEXP_INF, 1f              # is FS an infinity?
884          bne       ta1, SEXP_INF, result_fs_s    # if FT is not inf, result=FS
885          bne       t2, zero, result_fs_s                   # if FS is NAN, result is FS
886          bne       ta2, zero, result_ft_s                  # if FT is NAN, result is FT
887          bne       t0, ta0, invalid_s            # both infinities same sign?
888          b         result_fs_s                             # result is in FS
8891:
890          beq       ta1, SEXP_INF, result_ft_s    # if FT is inf, result=FT
891          bne       t1, zero, 4f                            # is FS a denormalized num?
892          beq       t2, zero, 3f                            # is FS zero?
893          bne       ta1, zero, 2f                           # is FT a denormalized num?
894          beq       ta2, zero, result_fs_s                  # FT is zero, result=FS
895          jal       _C_LABEL(renorm_fs_s)
896          jal       _C_LABEL(renorm_ft_s)
897          b         5f
8982:
899          jal       _C_LABEL(renorm_fs_s)
900          subu      ta1, ta1, SEXP_BIAS           # unbias FT exponent
901          or        ta2, ta2, SIMPL_ONE           # set implied one bit
902          b         5f
9033:
904          bne       ta1, zero, result_ft_s                  # if FT != 0, result=FT
905          bne       ta2, zero, result_ft_s
906          and       v0, a2, MIPS_FCSR_RM                    # get rounding mode
907          bne       v0, MIPS_FCSR_RM_RM, 1f                 # round to -infinity?
908          or        t0, t0, ta0                             # compute result sign
909          b         result_fs_s
9101:
911          and       t0, t0, ta0                             # compute result sign
912          b         result_fs_s
9134:
914          bne       ta1, zero, 2f                           # is FT a denormalized num?
915          beq       ta2, zero, result_fs_s                  # FT is zero, result=FS
916          subu      t1, t1, SEXP_BIAS             # unbias FS exponent
917          or        t2, t2, SIMPL_ONE             # set implied one bit
918          jal       _C_LABEL(renorm_ft_s)
919          b         5f
9202:
921          subu      t1, t1, SEXP_BIAS             # unbias FS exponent
922          or        t2, t2, SIMPL_ONE             # set implied one bit
923          subu      ta1, ta1, SEXP_BIAS           # unbias FT exponent
924          or        ta2, ta2, SIMPL_ONE           # set implied one bit
925/*
926 * Perform the addition.
927 */
9285:
929          move      t9, zero                      # no shifted bits (sticky reg)
930          beq       t1, ta1, 4f                             # no shift needed
931          subu      v0, t1, ta1                             # v0 = difference of exponents
932          move      v1, v0                                  # v1 = abs(difference)
933          bge       v0, zero, 1f
934          negu      v1
9351:
936          ble       v1, SFRAC_BITS+2, 2f                    # is difference too great?
937          li        t9, STICKYBIT                           # set the sticky bit
938          bge       v0, zero, 1f                            # check which exp is larger
939          move      t1, ta1                                 # result exp is FTs
940          move      t2, zero                      # FSs fraction shifted is zero
941          b         4f
9421:
943          move      ta2, zero                     # FTs fraction shifted is zero
944          b         4f
9452:
946          li        t9, 32                                  # compute 32 - abs(exp diff)
947          subu      t9, t9, v1
948          bgt       v0, zero, 3f                            # if FS > FT, shift FTs frac
949          move      t1, ta1                                 # FT > FS, result exp is FTs
950          sll       t9, t2, t9                              # save bits shifted out
951          srl       t2, t2, v1                              # shift FSs fraction
952          b         4f
9533:
954          sll       t9, ta2, t9                             # save bits shifted out
955          srl       ta2, ta2, v1                            # shift FTs fraction
9564:
957          bne       t0, ta0, 1f                             # if signs differ, subtract
958          addu      t2, t2, ta2                             # add fractions
959          b         norm_s
9601:
961          blt       t2, ta2, 3f                             # subtract larger from smaller
962          bne       t2, ta2, 2f                             # if same, result=0
963          move      t1, zero                      # result=0
964          move      t2, zero
965          and       v0, a2, MIPS_FCSR_RM                    # get rounding mode
966          bne       v0, MIPS_FCSR_RM_RM, 1f                 # round to -infinity?
967          or        t0, t0, ta0                             # compute result sign
968          b         result_fs_s
9691:
970          and       t0, t0, ta0                             # compute result sign
971          b         result_fs_s
9722:
973          sltu      v0, zero, t9                            # compute t2:zero - ta2:t9
974          subu      t9, zero, t9
975          subu      t2, t2, ta2                             # subtract fractions
976          subu      t2, t2, v0                              # subtract barrow
977          b         norm_s
9783:
979          move      t0, ta0                                 # sign of result = FTs
980          sltu      v0, zero, t9                            # compute ta2:zero - t2:t9
981          subu      t9, zero, t9
982          subu      t2, ta2, t2                             # subtract fractions
983          subu      t2, t2, v0                              # subtract barrow
984          b         norm_s
985
986/*
987 * Double precision subtract.
988 */
989sub_d:
990          jal       _C_LABEL(get_ft_fs_d)
991          xor       ta0, ta0, 1                             # negate sign bit
992          b         add_sub_d
993/*
994 * Double precision add.
995 */
996add_d:
997          jal       _C_LABEL(get_ft_fs_d)
998add_sub_d:
999          bne       t1, DEXP_INF, 1f              # is FS an infinity?
1000          bne       ta1, DEXP_INF, result_fs_d    # if FT is not inf, result=FS
1001          bne       t2, zero, result_fs_d                   # if FS is NAN, result is FS
1002          bne       t3, zero, result_fs_d
1003          bne       ta2, zero, result_ft_d                  # if FT is NAN, result is FT
1004          bne       ta3, zero, result_ft_d
1005          bne       t0, ta0, invalid_d            # both infinities same sign?
1006          b         result_fs_d                             # result is in FS
10071:
1008          beq       ta1, DEXP_INF, result_ft_d    # if FT is inf, result=FT
1009          bne       t1, zero, 4f                            # is FS a denormalized num?
1010          bne       t2, zero, 1f                            # is FS zero?
1011          beq       t3, zero, 3f
10121:
1013          bne       ta1, zero, 2f                           # is FT a denormalized num?
1014          bne       ta2, zero, 1f
1015          beq       ta3, zero, result_fs_d                  # FT is zero, result=FS
10161:
1017          jal       _C_LABEL(renorm_fs_d)
1018          jal       _C_LABEL(renorm_ft_d)
1019          b         5f
10202:
1021          jal       _C_LABEL(renorm_fs_d)
1022          subu      ta1, ta1, DEXP_BIAS           # unbias FT exponent
1023          or        ta2, ta2, DIMPL_ONE           # set implied one bit
1024          b         5f
10253:
1026          bne       ta1, zero, result_ft_d                  # if FT != 0, result=FT
1027          bne       ta2, zero, result_ft_d
1028          bne       ta3, zero, result_ft_d
1029          and       v0, a2, MIPS_FCSR_RM                    # get rounding mode
1030          bne       v0, MIPS_FCSR_RM_RM, 1f                 # round to -infinity?
1031          or        t0, t0, ta0                             # compute result sign
1032          b         result_fs_d
10331:
1034          and       t0, t0, ta0                             # compute result sign
1035          b         result_fs_d
10364:
1037          bne       ta1, zero, 2f                           # is FT a denormalized num?
1038          bne       ta2, zero, 1f
1039          beq       ta3, zero, result_fs_d                  # FT is zero, result=FS
10401:
1041          subu      t1, t1, DEXP_BIAS             # unbias FS exponent
1042          or        t2, t2, DIMPL_ONE             # set implied one bit
1043          jal       _C_LABEL(renorm_ft_d)
1044          b         5f
10452:
1046          subu      t1, t1, DEXP_BIAS             # unbias FS exponent
1047          or        t2, t2, DIMPL_ONE             # set implied one bit
1048          subu      ta1, ta1, DEXP_BIAS           # unbias FT exponent
1049          or        ta2, ta2, DIMPL_ONE           # set implied one bit
1050/*
1051 * Perform the addition.
1052 */
10535:
1054          move      t9, zero                      # no shifted bits (sticky reg)
1055          beq       t1, ta1, 4f                             # no shift needed
1056          subu      v0, t1, ta1                             # v0 = difference of exponents
1057          move      v1, v0                                  # v1 = abs(difference)
1058          bge       v0, zero, 1f
1059          negu      v1
10601:
1061          ble       v1, DFRAC_BITS+2, 2f                    # is difference too great?
1062          li        t9, STICKYBIT                           # set the sticky bit
1063          bge       v0, zero, 1f                            # check which exp is larger
1064          move      t1, ta1                                 # result exp is FTs
1065          move      t2, zero                      # FSs fraction shifted is zero
1066          move      t3, zero
1067          b         4f
10681:
1069          move      ta2, zero                     # FTs fraction shifted is zero
1070          move      ta3, zero
1071          b         4f
10722:
1073          li        t9, 32
1074          bge       v0, zero, 3f                            # if FS > FT, shift FTs frac
1075          move      t1, ta1                                 # FT > FS, result exp is FTs
1076          blt       v1, t9, 1f                              # shift right by < 32?
1077          subu      v1, v1, t9
1078          subu      t9, t9, v1
1079          sll       v0, t2, t9                              # save bits shifted out
1080          sltu      t9, zero, t3                            # dont lose any one bits
1081          or        t9, t9, v0                              # save sticky bit
1082          srl       t3, t2, v1                              # shift FSs fraction
1083          move      t2, zero
1084          b         4f
10851:
1086          subu      v0, t9, v1
1087          sll       t9, t3, v0                              # save bits shifted out
1088          srl       t3, t3, v1                              # shift FSs fraction
1089          sll       v0, t2, v0                              # save bits shifted out of t2
1090          or        t3, t3, v0                              # and put into t3
1091          srl       t2, t2, v1
1092          b         4f
10933:
1094          blt       v1, t9, 1f                              # shift right by < 32?
1095          subu      v1, v1, t9
1096          subu      v0, t9, v1
1097          sll       t9, ta2, v0                             # save bits shifted out
1098          srl       ta3, ta2, v1                            # shift FTs fraction
1099          move      ta2, zero
1100          b         4f
11011:
1102          subu      v0, t9, v1
1103          sll       t9, ta3, v0                             # save bits shifted out
1104          srl       ta3, ta3, v1                            # shift FTs fraction
1105          sll       v0, ta2, v0                             # save bits shifted out of t2
1106          or        ta3, ta3, v0                            # and put into t3
1107          srl       ta2, ta2, v1
11084:
1109          bne       t0, ta0, 1f                             # if signs differ, subtract
1110          addu      t3, t3, ta3                             # add fractions
1111          sltu      v0, t3, ta3                             # compute carry
1112          addu      t2, t2, ta2                             # add fractions
1113          addu      t2, t2, v0                              # add carry
1114          b         norm_d
11151:
1116          blt       t2, ta2, 3f                             # subtract larger from smaller
1117          bne       t2, ta2, 2f
1118          bltu      t3, ta3, 3f
1119          bne       t3, ta3, 2f                             # if same, result=0
1120          move      t1, zero                      # result=0
1121          move      t2, zero
1122          move      t3, zero
1123          and       v0, a2, MIPS_FCSR_RM                    # get rounding mode
1124          bne       v0, MIPS_FCSR_RM_RM, 1f                 # round to -infinity?
1125          or        t0, t0, ta0                             # compute result sign
1126          b         result_fs_d
11271:
1128          and       t0, t0, ta0                             # compute result sign
1129          b         result_fs_d
11302:
1131          beq       t9, zero, 1f                            # compute t2:t3:zero - ta2:ta3:t9
1132          subu      t9, zero, t9
1133          sltu      v0, t3, 1                     # compute barrow out
1134          subu      t3, t3, 1                     # subtract barrow
1135          subu      t2, t2, v0
11361:
1137          sltu      v0, t3, ta3
1138          subu      t3, t3, ta3                             # subtract fractions
1139          subu      t2, t2, ta2                             # subtract fractions
1140          subu      t2, t2, v0                              # subtract barrow
1141          b         norm_d
11423:
1143          move      t0, ta0                                 # sign of result = FTs
1144          beq       t9, zero, 1f                            # compute ta2:ta3:zero - t2:t3:t9
1145          subu      t9, zero, t9
1146          sltu      v0, ta3, 1                              # compute barrow out
1147          subu      ta3, ta3, 1                             # subtract barrow
1148          subu      ta2, ta2, v0
11491:
1150          sltu      v0, ta3, t3
1151          subu      t3, ta3, t3                             # subtract fractions
1152          subu      t2, ta2, t2                             # subtract fractions
1153          subu      t2, t2, v0                              # subtract barrow
1154          b         norm_d
1155
1156/*
1157 * Single precision multiply.
1158 */
1159mul_s:
1160          jal       _C_LABEL(get_ft_fs_s)
1161          xor       t0, t0, ta0                             # compute sign of result
1162          move      ta0, t0
1163          bne       t1, SEXP_INF, 2f              # is FS an infinity?
1164          bne       t2, zero, result_fs_s                   # if FS is a NAN, result=FS
1165          bne       ta1, SEXP_INF, 1f             # FS is inf, is FT an infinity?
1166          bne       ta2, zero, result_ft_s                  # if FT is a NAN, result=FT
1167          b         result_fs_s                             # result is infinity
11681:
1169          bne       ta1, zero, result_fs_s                  # inf * zero? if no, result=FS
1170          bne       ta2, zero, result_fs_s
1171          b         invalid_s                     # infinity * zero is invalid
11722:
1173          bne       ta1, SEXP_INF, 1f             # FS != inf, is FT an infinity?
1174          bne       t1, zero, result_ft_s                   # zero * inf? if no, result=FT
1175          bne       t2, zero, result_ft_s
1176          bne       ta2, zero, result_ft_s                  # if FT is a NAN, result=FT
1177          b         invalid_s                     # zero * infinity is invalid
11781:
1179          bne       t1, zero, 1f                            # is FS zero?
1180          beq       t2, zero, result_fs_s                   # result is zero
1181          jal       _C_LABEL(renorm_fs_s)
1182          b         2f
11831:
1184          subu      t1, t1, SEXP_BIAS             # unbias FS exponent
1185          or        t2, t2, SIMPL_ONE             # set implied one bit
11862:
1187          bne       ta1, zero, 1f                           # is FT zero?
1188          beq       ta2, zero, result_ft_s                  # result is zero
1189          jal       _C_LABEL(renorm_ft_s)
1190          b         2f
11911:
1192          subu      ta1, ta1, SEXP_BIAS           # unbias FT exponent
1193          or        ta2, ta2, SIMPL_ONE           # set implied one bit
11942:
1195          addu      t1, t1, ta1                             # compute result exponent
1196          addu      t1, t1, 9                     # account for binary point
1197          multu     t2, ta2                                 # multiply fractions
1198          mflo      t9
1199          mfhi      t2
1200          b         norm_s
1201
1202/*
1203 * Double precision multiply.
1204 */
1205mul_d:
1206          jal       _C_LABEL(get_ft_fs_d)
1207          xor       t0, t0, ta0                             # compute sign of result
1208          move      ta0, t0
1209          bne       t1, DEXP_INF, 2f              # is FS an infinity?
1210          bne       t2, zero, result_fs_d                   # if FS is a NAN, result=FS
1211          bne       t3, zero, result_fs_d
1212          bne       ta1, DEXP_INF, 1f             # FS is inf, is FT an infinity?
1213          bne       ta2, zero, result_ft_d                  # if FT is a NAN, result=FT
1214          bne       ta3, zero, result_ft_d
1215          b         result_fs_d                             # result is infinity
12161:
1217          bne       ta1, zero, result_fs_d                  # inf * zero? if no, result=FS
1218          bne       ta2, zero, result_fs_d
1219          bne       ta3, zero, result_fs_d
1220          b         invalid_d                     # infinity * zero is invalid
12212:
1222          bne       ta1, DEXP_INF, 1f             # FS != inf, is FT an infinity?
1223          bne       t1, zero, result_ft_d                   # zero * inf? if no, result=FT
1224          bne       t2, zero, result_ft_d                   # if FS is a NAN, result=FS
1225          bne       t3, zero, result_ft_d
1226          bne       ta2, zero, result_ft_d                  # if FT is a NAN, result=FT
1227          bne       ta3, zero, result_ft_d
1228          b         invalid_d                     # zero * infinity is invalid
12291:
1230          bne       t1, zero, 2f                            # is FS zero?
1231          bne       t2, zero, 1f
1232          beq       t3, zero, result_fs_d                   # result is zero
12331:
1234          jal       _C_LABEL(renorm_fs_d)
1235          b         3f
12362:
1237          subu      t1, t1, DEXP_BIAS             # unbias FS exponent
1238          or        t2, t2, DIMPL_ONE             # set implied one bit
12393:
1240          bne       ta1, zero, 2f                           # is FT zero?
1241          bne       ta2, zero, 1f
1242          beq       ta3, zero, result_ft_d                  # result is zero
12431:
1244          jal       _C_LABEL(renorm_ft_d)
1245          b         3f
12462:
1247          subu      ta1, ta1, DEXP_BIAS           # unbias FT exponent
1248          or        ta2, ta2, DIMPL_ONE           # set implied one bit
12493:
1250          addu      t1, t1, ta1                             # compute result exponent
1251          addu      t1, t1, 12                              # ???
1252          multu     t3, ta3                                 # multiply fractions (low * low)
1253          move      ta0, t2                                 # free up t2,t3 for result
1254          move      ta1, t3
1255          mflo      a3                                      # save low order bits
1256          mfhi      t9
1257          not       v0, t9
1258          multu     ta0, ta3                                # multiply FS(high) * FT(low)
1259          mflo      v1
1260          mfhi      t3                                      # init low result
1261          sltu      v0, v0, v1                              # compute carry
1262          addu      t9, v1
1263          multu     ta1, ta2                                # multiply FS(low) * FT(high)
1264          addu      t3, t3, v0                              # add carry
1265          not       v0, t9
1266          mflo      v1
1267          mfhi      t2
1268          sltu      v0, v0, v1
1269          addu      t9, v1
1270          multu     ta0, ta2                                # multiply FS(high) * FT(high)
1271          addu      t3, v0
1272          not       v1, t3
1273          sltu      v1, v1, t2
1274          addu      t3, t2
1275          not       v0, t3
1276          mfhi      t2
1277          addu      t2, v1
1278          mflo      v1
1279          sltu      v0, v0, v1
1280          addu      t2, v0
1281          addu      t3, v1
1282          sltu      a3, zero, a3                            # reduce t9,a3 to just t9
1283          or        t9, a3
1284          b         norm_d
1285
1286/*
1287 * Single precision divide.
1288 */
1289div_s:
1290          jal       _C_LABEL(get_ft_fs_s)
1291          xor       t0, t0, ta0                             # compute sign of result
1292          move      ta0, t0
1293          bne       t1, SEXP_INF, 1f              # is FS an infinity?
1294          bne       t2, zero, result_fs_s                   # if FS is NAN, result is FS
1295          bne       ta1, SEXP_INF, result_fs_s    # is FT an infinity?
1296          bne       ta2, zero, result_ft_s                  # if FT is NAN, result is FT
1297          b         invalid_s                     # infinity/infinity is invalid
12981:
1299          bne       ta1, SEXP_INF, 1f             # is FT an infinity?
1300          bne       ta2, zero, result_ft_s                  # if FT is NAN, result is FT
1301          move      t1, zero                      # x / infinity is zero
1302          move      t2, zero
1303          b         result_fs_s
13041:
1305          bne       t1, zero, 2f                            # is FS zero?
1306          bne       t2, zero, 1f
1307          bne       ta1, zero, result_fs_s                  # FS=zero, is FT zero?
1308          beq       ta2, zero, invalid_s                    # 0 / 0
1309          b         result_fs_s                             # result = zero
13101:
1311          jal       _C_LABEL(renorm_fs_s)
1312          b         3f
13132:
1314          subu      t1, t1, SEXP_BIAS             # unbias FS exponent
1315          or        t2, t2, SIMPL_ONE             # set implied one bit
13163:
1317          bne       ta1, zero, 2f                           # is FT zero?
1318          bne       ta2, zero, 1f
1319          or        a2, a2, MIPS_FCSR_CAUSE_Z | MIPS_FCSR_FLAGS_Z
1320          and       v0, a2, MIPS_FCSR_ENABLES_Z   # trap enabled?
1321          bne       v0, zero, fpe_trap
1322#ifdef FPEMUL
1323          PTR_L     t1, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
1324          #nop
1325          INT_S     a2, PCB_FPREGS+FRAME_FSR(t1)
1326#else
1327          ctc1      a2, MIPS_FCSR                           # save exceptions
1328#endif
1329          li        t1, SEXP_INF                            # result is infinity
1330          move      t2, zero
1331          b         result_fs_s
13321:
1333          jal       _C_LABEL(renorm_ft_s)
1334          b         3f
13352:
1336          subu      ta1, ta1, SEXP_BIAS           # unbias FT exponent
1337          or        ta2, ta2, SIMPL_ONE           # set implied one bit
13383:
1339          subu      t1, t1, ta1                             # compute exponent
1340          subu      t1, t1, 3                     # compensate for result position
1341          li        v0, SFRAC_BITS+3              # number of bits to divide
1342          move      t9, t2                                  # init dividend
1343          move      t2, zero                      # init result
13441:
1345          bltu      t9, ta2, 3f                             # is dividend >= divisor?
13462:
1347          subu      t9, t9, ta2                             # subtract divisor from dividend
1348          or        t2, t2, 1                     # remember that we did
1349          bne       t9, zero, 3f                            # if not done, continue
1350          sll       t2, t2, v0                              # shift result to final position
1351          b         norm_s
13523:
1353          sll       t9, t9, 1                     # shift dividend
1354          sll       t2, t2, 1                     # shift result
1355          subu      v0, v0, 1                     # are we done?
1356          bne       v0, zero, 1b                            # no, continue
1357          b         norm_s
1358
1359/*
1360 * Double precision divide.
1361 */
1362div_d:
1363          jal       _C_LABEL(get_ft_fs_d)
1364          xor       t0, t0, ta0                             # compute sign of result
1365          move      ta0, t0
1366          bne       t1, DEXP_INF, 1f              # is FS an infinity?
1367          bne       t2, zero, result_fs_d                   # if FS is NAN, result is FS
1368          bne       t3, zero, result_fs_d
1369          bne       ta1, DEXP_INF, result_fs_d    # is FT an infinity?
1370          bne       ta2, zero, result_ft_d                  # if FT is NAN, result is FT
1371          bne       ta3, zero, result_ft_d
1372          b         invalid_d                     # infinity/infinity is invalid
13731:
1374          bne       ta1, DEXP_INF, 1f             # is FT an infinity?
1375          bne       ta2, zero, result_ft_d                  # if FT is NAN, result is FT
1376          bne       ta3, zero, result_ft_d
1377          move      t1, zero                      # x / infinity is zero
1378          move      t2, zero
1379          move      t3, zero
1380          b         result_fs_d
13811:
1382          bne       t1, zero, 2f                            # is FS zero?
1383          bne       t2, zero, 1f
1384          bne       t3, zero, 1f
1385          bne       ta1, zero, result_fs_d                  # FS=zero, is FT zero?
1386          bne       ta2, zero, result_fs_d
1387          beq       ta3, zero, invalid_d                    # 0 / 0
1388          b         result_fs_d                             # result = zero
13891:
1390          jal       _C_LABEL(renorm_fs_d)
1391          b         3f
13922:
1393          subu      t1, t1, DEXP_BIAS             # unbias FS exponent
1394          or        t2, t2, DIMPL_ONE             # set implied one bit
13953:
1396          bne       ta1, zero, 2f                           # is FT zero?
1397          bne       ta2, zero, 1f
1398          bne       ta3, zero, 1f
1399          or        a2, a2, MIPS_FCSR_CAUSE_Z | MIPS_FCSR_FLAGS_Z
1400          and       v0, a2, MIPS_FCSR_ENABLES_Z   # trap enabled?
1401          bne       v0, zero, fpe_trap
1402#ifdef FPEMUL
1403          PTR_L     t1, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
1404          #nop
1405          INT_S     a2, PCB_FPREGS+FRAME_FSR(t1)
1406#else
1407          ctc1      a2, MIPS_FCSR                           # save exceptions
1408#endif
1409          li        t1, DEXP_INF                            # result is infinity
1410          move      t2, zero
1411          move      t3, zero
1412          b         result_fs_d
14131:
1414          jal       _C_LABEL(renorm_ft_d)
1415          b         3f
14162:
1417          subu      ta1, ta1, DEXP_BIAS           # unbias FT exponent
1418          or        ta2, ta2, DIMPL_ONE           # set implied one bit
14193:
1420          subu      t1, t1, ta1                             # compute exponent
1421          subu      t1, t1, 3                     # compensate for result position
1422          li        v0, DFRAC_BITS+3              # number of bits to divide
1423          move      t9, t2                                  # init dividend
1424          move      v1, t3
1425          move      t2, zero                      # init result
1426          move      t3, zero
14271:
1428          bltu      t9, ta2, 3f                             # is dividend >= divisor?
1429          bne       t9, ta2, 2f
1430          bltu      v1, ta3, 3f
14312:
1432          .set      noat
1433          sltu      AT, v1, ta3                             # subtract divisor from dividend
1434          subu      v1, v1, ta3
1435          subu      t9, t9, ta2
1436          subu      t9, t9, AT
1437          .set      at
1438          or        t3, t3, 1                     # remember that we did
1439          bne       t9, zero, 3f                            # if not done, continue
1440          bne       v1, zero, 3f
1441          li        v1, 32                                  # shift result to final position
1442          blt       v0, v1, 2f                              # shift < 32 bits?
1443          subu      v0, v0, v1                              # shift by > 32 bits
1444          sll       t2, t3, v0                              # shift upper part
1445          move      t3, zero
1446          b         norm_d
14472:
1448          .set      noat
1449          subu      v1, v1, v0                              # shift by < 32 bits
1450          sll       t2, t2, v0                              # shift upper part
1451          srl       AT, t3, v1                              # save bits shifted out
1452          or        t2, t2, AT                              # and put into upper part
1453          sll       t3, t3, v0
1454          b         norm_d
1455          .set      at
14563:
1457          .set      noat
1458          sll       t9, t9, 1                     # shift dividend
1459          srl       AT, v1, 31                              # save bit shifted out
1460          or        t9, t9, AT                              # and put into upper part
1461          sll       v1, v1, 1
1462          sll       t2, t2, 1                     # shift result
1463          srl       AT, t3, 31                              # save bit shifted out
1464          or        t2, t2, AT                              # and put into upper part
1465          sll       t3, t3, 1
1466          subu      v0, v0, 1                     # are we done?
1467          bne       v0, zero, 1b                            # no, continue
1468          sltu      v0, zero, v1                            # be sure to save any one bits
1469          or        t9, t9, v0                              # from the lower remainder
1470          b         norm_d
1471          .set      at
1472
1473#ifdef MIPS3_PLUS
1474sqrt_s:
1475          jal       _C_LABEL(get_fs_s)
1476
1477          /* Take care of zero, negative, inf, and NaN special cases */
1478          or        v0, t1, t2                              # sqrt(+-0) == +-0
1479          beq       v0, zero, result_fs_s                   # ...
1480          bne       t0, zero, 1f                            # sqrt(-val) == sNaN
1481          bne       t1, SEXP_INF, 2f              # skip forward if not infinity
1482          b         result_fs_s                             # sqrt(NaN,+inf) == itself
14831:        move      t0, zero                      # result is a quiet NAN
1484          li        t1, SEXP_INF                            # sqrt(-inf,-val) == sNaN
1485          li        t2, SQUIET_NAN
1486          b         result_fs_s
14872:
1488          /* normalize FS if needed */
1489          bne       t1, zero, 2f
1490          jal       _C_LABEL(renorm_fs_s)
14912:        and       t2, t2, (SIMPL_ONE-1)                   # ix &= 0x007fffff;
1492          or        t2, t2, SIMPL_ONE             # ix |= 0x00800000;
1493          and       v0, t1, 1                     # if (m & 1)
1494          beq       v0, zero, 1f                            # ...
1495          add       t2, t2, t2                              #         ix += ix;
14961:        sra       t1, t1, 1                     # m = m / 2;
1497
1498          /* generate sqrt(FS) bit by bit */
1499          add       t2, t2, t2                              # ix += ix;
1500          move      ta0, zero                     # q = 0; (result)
1501          li        t9, SIMPL_ONE<<1              # r = 0x01000000;
1502          move      ta2, zero                     # s = 0;
15031:        beq       t9, zero, 3f                            # while (r != 0) {
1504          add       v0, ta2, t9                             #         t = s + r;
1505          bgt       v0, t2, 2f                              #         if (t <= ix)
1506          add       ta2, v0, t9                             #                   s = t + r;
1507          sub       t2, t2, v0                              #                   ix -= t;
1508          add       ta0, ta0, t9                            #                   q += r;
15092:        add       t2, t2, t2                              #         ix += ix;
1510          srl       t9, t9, 1                     #         r >>= 1;
1511          b         1b                                      # }
15123:
1513          /* rounding -- all mips rounding modes use the same rounding here */
1514          beq       t2, zero, 1f                            # if (ix != 0)
1515          and       v0, ta0, 1                              # q += q&1;
1516          add       ta0, ta0, v0                            # ...
1517
1518          /* calculate result */
15191:        srl       t2, ta0, 1                              # ix = (q >> 1);
1520          add       t1, t1, SEXP_BIAS             # m += 127; (re-bias)
1521          li        v1, SIMPL_ONE
1522          and       v0, t2, v1                              # keep extra exponent bit
1523          bne       v0, zero, 1f                            # if it is there.
1524          sub       t1, t1, 1                     # ...
15251:
1526          nor       v1, v1, v1                              # ~SIMP_ONE
1527          and       t2, t2, v1                              # ix &= ~SIMPL_ONE
1528          b         result_fs_s                             # store result (already normal)
1529
1530sqrt_d:
1531          jal       _C_LABEL(get_fs_d)
1532
1533          /* Take care of zero, negative, inf, and NaN special cases */
1534          or        v0, t1, t2                              # sqrt(+-0) == +- 0
1535          or        v0, v0, t3                              # ...
1536          beq       v0, zero, result_fs_d                   # ...
1537          bne       t0, zero, 1f                            # sqrt(-val) == sNaN
1538          bne       t1, DEXP_INF, 2f              # skip forward if not infinity
1539          b         result_fs_d                             # sqrt(NaN,+inf) == itself
15401:        move      t0, zero                      # sqrt(-inf,-val) == sNaN
1541          li        t1, DEXP_INF
1542          li        t2, DQUIET_NAN0
1543          li        t3, DQUIET_NAN1
1544          b         result_fs_d
15452:
1546          /* normalize FS if needed */
1547          bne       t1, zero, 2f
1548          jal       _C_LABEL(renorm_fs_d)
15492:        and       t2, t2, (DIMPL_ONE-1)                   # ix0 &= 0x000fffff
1550          or        t2, t2, DIMPL_ONE             # ix0 |= 0x00100000
1551          and       v0, t1, 1                     # if (m & 1)
1552          beq       v0, zero, 1f                            # ...
1553          add       t2, t2, t2                              # ix0 += ix0
1554          srl       v0, t3, 31                              # ix0 += (ix1&sign)>>31)
1555          and       v0, v0, 1                     # ...
1556          add       t2, t2, v0                              # ...
1557          addu      t3, t3, t3                              # ix1 += ix1;
15581:        sra       t1, t1, 1                     # m = m / 2;
1559
1560          /* generate sqrt(FS) bit by bit -- first upper */
1561          addu      t2, t2, t2                              # ix0 += ix0;
1562          srl       v0, t3, 31                              # ix0 += (ix1&sign)>>31)
1563          and       v0, v0, 1                     # ...
1564          add       t2, t2, v0                              # ...
1565          addu      t3, t3, t3                              # ix1 += ix1;
1566
1567          move      ta0, zero                     # q = 0;  (result)
1568          move      ta1, zero                     # q1 = 0; (result)
1569          move      ta2, zero                     # s0 = 0;
1570          move      ta3, zero                     # s1 = 0;
1571          li        t9, DIMPL_ONE<<1              # t = 0x00200000;
15721:        beq       t9, zero, 3f                            # while (r != 0) {
1573          add       v0, ta2, t9                             #         t = s0+r;
1574          bgt       v0, t2, 2f                              #         if (t <= ix0)
1575          add       ta2, v0, t9                             #                   s0 = t + r;
1576          sub       t2, t2, v0                              #                   ix0 -= t;
1577          add       ta0, ta0, t9                            #                   q += r;
15782:        add       t2, t2, t2                              #         ix0 += ix0;
1579          srl       v0, t3, 31                              #         ix0 += (ix1&sign)>>31)
1580          and       v0, v0, 1                     #         ...
1581          add       t2, t2, v0                              #         ...
1582          addu      t3, t3, t3                              #         ix1 += ix1;
1583          srl       t9, t9, 1                     #         r >>= 1;
1584          b         1b                                      # }
15853:
1586          /* then lower bits */
1587          li        t9, 1<<31                     # r = sign;
15881:        beq       t9, zero, 4f                            # while (r != 0) {
1589          addu      v1, ta3, t9                             #    t1 = s1 + r;
1590          move      v0, ta2                                 #    t = s0;
1591          blt       v0, t2, 2f                              #    if ( (t<ix0) ||
1592          bne       v0, t2, 3f                              #         ((t == ix0) &&
1593          bgtu      v1, t3, 3f                              #          (t1 <= ix1)))
15942:        addu      ta3, v1, t9                             #         s1 = t1 + r;
1595          .set      noat
1596          srl       AT, v1, 31                              #         if (((t1&sign)==sign) &&
1597          and       AT, AT, 1                     #         ...
1598          beq       AT, zero, 2f                            #         ...
1599          srl       AT, ta3, 31                             #             (s1&sign) == 0)
1600          and       AT, AT, 1                     #             ...
1601          bne       AT, zero, 2f                            #             ...
1602          add       ta2, ta2, 1                             #             s0 += 1;
1603          .set      at
16042:        sub       t2, t2, v0                              #         ix0 -= t;
1605          bgeu      t3, v1, 2f                              #         if (ix1 < t1)
1606          sub       t2, t2, 1                     #             ix0 -= 1;
16072:        subu      t3, t3, v1                              #         ix1 -= t1;
1608          addu      ta1, ta1, t9                            #         q1 += r;
16093:        add       t2, t2, t2                              #    ix0 += ix0;
1610          srl       v0, t3, 31                              #    ix0 += (ix1&sign)>>31)
1611          and       v0, v0, 1                     #    ...
1612          add       t2, t2, v0                              #    ...
1613          addu      t3, t3, t3                              #    ix1 += ix1;
1614          srl       t9, t9, 1                     #    r >>= 1;
1615          b         1b                                      # }
16164:
1617
1618          /* rounding -- all mips rounding modes use the same rounding here */
1619          or        v0, t2, t3                              # if (ix0 | ix1)
1620          beq       v0, zero, 2f                            # ...
1621          li        v0, 0xffffffff                          #    if (q1 == 0xffffffff)
1622          and       v1, t2, v0                              #    ...
1623          bne       v1, v0, 1f                              #    ...
1624          move      ta1, zero                     #         q1 = 0;
1625          add       ta0, ta0, 1                             #         q += 1;
1626          b         2f                                      #    else
16271:        and       v0, ta1, 1                              #       q1 += q1 & 1;
1628          addu      ta1, ta1, v0                            #       ...
1629
1630          /* calculate result */
16312:        srl       t2, ta0, 1                              # ix0 = q >> 1;
1632          srl       t3, ta1, 1                              # ix1 = q1 >> 1;
1633          and       v0, ta0, 1                              # if ((q & 1) == 1)
1634          beq       v0, zero, 1f                            # ...
1635          or        t3, (1<<31)                             #         ix1 |= sign;
16361:        add       t1, t1, DEXP_BIAS             # m += 1023;
1637          li        v1, DIMPL_ONE
1638          and       v0, t2, v1                              # keep extra exponent bit
1639          bne       v0, zero, 1f                            # if it is there.
1640          sub       t1, t1, 1                     # ...
16411:
1642          nor       v1, v1, v1                              # ~DIMPL_ONE
1643          and       t2, t2, v1                              # ix0 &= ~DIMPL_ONE
1644          b         result_fs_d                             # store result (already normal)
1645#endif    /* MIPS3_PLUS */
1646
1647/*
1648 * Single precision absolute value.
1649 */
1650abs_s:
1651          jal       _C_LABEL(get_fs_s)
1652          move      t0, zero                      # set sign positive
1653          b         result_fs_s
1654
1655/*
1656 * Double precision absolute value.
1657 */
1658abs_d:
1659          jal       _C_LABEL(get_fs_d)
1660          move      t0, zero                      # set sign positive
1661          b         result_fs_d
1662
1663/*
1664 * Single precision move.
1665 */
1666mov_s:
1667          jal       _C_LABEL(get_fs_s)
1668          b         result_fs_s
1669
1670/*
1671 * Double precision move.
1672 */
1673mov_d:
1674          jal       _C_LABEL(get_fs_d)
1675          b         result_fs_d
1676
1677/*
1678 * Single precision negate.
1679 */
1680neg_s:
1681          jal       _C_LABEL(get_fs_s)
1682          xor       t0, t0, 1                     # reverse sign
1683          b         result_fs_s
1684
1685/*
1686 * Double precision negate.
1687 */
1688neg_d:
1689          jal       _C_LABEL(get_fs_d)
1690          xor       t0, t0, 1                     # reverse sign
1691          b         result_fs_d
1692
1693#ifdef MIPS3_PLUS
1694/*
1695 * Single precision mips2 rounding.  Explicit case of cvt_w_s.
1696 */
1697round_w_s:
1698          li        v1,0
1699          b         _cvt_w_s
1700trunc_w_s:
1701          li        v1,1
1702          b         _cvt_w_s
1703ceil_w_s:
1704          li        v1,2
1705          b         _cvt_w_s
1706floor_w_s:
1707          li        v1,3
1708          b         _cvt_w_s
1709
1710/*
1711 * Double precision mips2 rounding.  Explicit case of cvt_w_d.
1712 */
1713round_w_d:
1714          li        v1,0
1715          b         _cvt_w_d
1716trunc_w_d:
1717          li        v1,1
1718          b         _cvt_w_d
1719ceil_w_d:
1720          li        v1,2
1721          b         _cvt_w_d
1722floor_w_d:
1723          li        v1,3
1724          b         _cvt_w_d
1725#endif /* MIPS3_PLUS */
1726
1727/*
1728 * Convert double to single.
1729 */
1730cvt_s_d:
1731          jal       _C_LABEL(get_fs_d)
1732          bne       t1, DEXP_INF, 1f              # is FS an infinity?
1733          li        t1, SEXP_INF                            # convert to single
1734          sll       t2, t2, 3                     # convert D fraction to S
1735          srl       t9, t3, 32 - 3
1736          or        t2, t2, t9
1737          b         result_fs_s
17381:
1739          bne       t1, zero, 2f                            # is FS zero?
1740          bne       t2, zero, 1f
1741          beq       t3, zero, result_fs_s                   # result=0
17421:
1743          jal       _C_LABEL(renorm_fs_d)
1744          subu      t1, t1, 3                     # correct exp for shift below
1745          b         3f
17462:
1747          subu      t1, t1, DEXP_BIAS             # unbias exponent
1748          or        t2, t2, DIMPL_ONE             # add implied one bit
17493:
1750          sll       t2, t2, 3                     # convert D fraction to S
1751          srl       t9, t3, 32 - 3
1752          or        t2, t2, t9
1753          sll       t9, t3, 3
1754          b         norm_noshift_s
1755
1756/*
1757 * Convert integer to single.
1758 */
1759cvt_s_w:
1760          jal       _C_LABEL(get_fs_int)
1761          bne       t2, zero, .Lcvtswnot0                   # check for zero
1762          move      t1, zero
1763          b         result_fs_s
1764/*
1765 * Find out how many leading zero bits are in t2 and put in v1.
1766 */
1767.Lcvtswnot0:
1768#if __mips == 32 || __mips == 64
1769          clz       v1, t2
1770#else
1771          .set      noat
1772
1773          move      v0, t2
1774          move      v1, zero
1775          srl       AT, v0, 16
1776          bne       AT, zero, 1f
1777          addu      v1, 16
1778          sll       v0, 16
17791:
1780          srl       AT, v0, 24
1781          bne       AT, zero, 1f
1782          addu      v1, 8
1783          sll       v0, 8
17841:
1785          srl       AT, v0, 28
1786          bne       AT, zero, 1f
1787          addu      v1, 4
1788          sll       v0, 4
17891:
1790          srl       AT, v0, 30
1791          bne       AT, zero, 1f
1792          addu      v1, 2
1793          sll       v0, 2
17941:
1795          srl       AT, v0, 31
1796          bne       AT, zero, 1f
1797          addu      v1, 1
1798          .set      at
1799#endif /* __mips == 32 || __mips == 64 */
1800/*
1801 * Now shift t2 the correct number of bits.
1802 */
18031:
1804          subu      v1, v1, SLEAD_ZEROS           # dont count leading zeros
1805          li        t1, 23                                  # init exponent
1806          subu      t1, t1, v1                              # compute exponent
1807          beq       v1, zero, 1f
1808          li        v0, 32
1809          blt       v1, zero, 2f                            # if shift < 0, shift right
1810          subu      v0, v0, v1
1811          sll       t2, t2, v1                              # shift left
18121:
1813          add       t1, t1, SEXP_BIAS             # bias exponent
1814          and       t2, t2, ~SIMPL_ONE            # clear implied one bit
1815          b         result_fs_s
18162:
1817          negu      v1                                      # shift right by v1
1818          subu      v0, v0, v1
1819          sll       t9, t2, v0                              # save bits shifted out
1820          srl       t2, t2, v1
1821          b         norm_noshift_s
1822
1823/*
1824 * Convert single to double.
1825 */
1826cvt_d_s:
1827          jal       _C_LABEL(get_fs_s)
1828          move      t3, zero
1829          bne       t1, SEXP_INF, 1f              # is FS an infinity?
1830          li        t1, DEXP_INF                            # convert to double
1831          b         result_fs_d
18321:
1833          bne       t1, zero, 2f                            # is FS denormalized or zero?
1834          beq       t2, zero, result_fs_d                   # is FS zero?
1835          jal       _C_LABEL(renorm_fs_s)
1836          move      t9, zero
1837          sll       t3, t2, 32 - 3                          # convert S fraction to D
1838          srl       t2, t2, 3
1839          b         norm_d
18402:
1841          addu      t1, t1, DEXP_BIAS - SEXP_BIAS # bias exponent correctly
1842          sll       t3, t2, 32 - 3                          # convert S fraction to D
1843          srl       t2, t2, 3
1844          b         result_fs_d
1845
1846/*
1847 * Convert integer to double.
1848 */
1849cvt_d_w:
1850          jal       _C_LABEL(get_fs_int)
1851          bne       t2, zero, .Lcvtdwnot0                   # check for zero
1852          move      t1, zero                      # result=0
1853          move      t3, zero
1854          b         result_fs_d
1855/*
1856 * Find out how many leading zero bits are in t2 and put in v1.
1857 */
1858.Lcvtdwnot0:
1859#if __mips == 32 || __mips == 64
1860          clz       v1, t2
1861#else /* __mips == 32 || __mips == 64 */
1862          .set      noat
1863
1864          move      v0, t2
1865          move      v1, zero
1866          srl       AT, v0, 16
1867          bne       AT, zero, 1f
1868          addu      v1, 16
1869          sll       v0, 16
18701:
1871          srl       AT, v0, 24
1872          bne       AT, zero, 1f
1873          addu      v1, 8
1874          sll       v0, 8
18751:
1876          srl       AT, v0, 28
1877          bne       AT, zero, 1f
1878          addu      v1, 4
1879          sll       v0, 4
18801:
1881          srl       AT, v0, 30
1882          bne       AT, zero, 1f
1883          addu      v1, 2
1884          sll       v0, 2
18851:
1886          srl       AT, v0, 31
1887          bne       AT, zero, 1f
1888          addu      v1, 1
18891:
1890          .set      at
1891#endif /* __mips == 32 || __mips == 64 */
1892/*
1893 * Now shift t2 the correct number of bits.
1894 */
1895          subu      v1, v1, DLEAD_ZEROS           # dont count leading zeros
1896          li        t1, DEXP_BIAS + 20            # init exponent
1897          subu      t1, t1, v1                              # compute exponent
1898          beq       v1, zero, 1f
1899          li        v0, 32
1900          blt       v1, zero, 2f                            # if shift < 0, shift right
1901          subu      v0, v0, v1
1902          sll       t2, t2, v1                              # shift left
19031:
1904          and       t2, t2, ~DIMPL_ONE            # clear implied one bit
1905          move      t3, zero
1906          b         result_fs_d
19072:
1908          negu      v1                                      # shift right by v1
1909          subu      v0, v0, v1
1910          sll       t3, t2, v0
1911          srl       t2, t2, v1
1912          and       t2, t2, ~DIMPL_ONE            # clear implied one bit
1913          b         result_fs_d
1914
1915/*
1916 * Convert single to integer.
1917 */
1918cvt_w_s:
1919          and       v1, a2, MIPS_FCSR_RM                    # get rounding mode
1920_cvt_w_s:
1921          jal       _C_LABEL(get_fs_s)
1922          bne       t1, SEXP_INF, 1f              # is FS an infinity?
1923          bne       t2, zero, invalid_w           # invalid conversion
19241:
1925          bne       t1, zero, 1f                            # is FS zero?
1926          beq       t2, zero, result_fs_w                   # result is zero
1927          move      t2, zero                      # result is an inexact zero
1928          b         inexact_w
19291:
1930          subu      t1, t1, SEXP_BIAS             # unbias exponent
1931          or        t2, t2, SIMPL_ONE             # add implied one bit
1932          sll       t3, t2, 32 - 3                          # convert S fraction to D
1933          srl       t2, t2, 3
1934          b         cvt_w
1935
1936/*
1937 * Convert double to integer.
1938 */
1939cvt_w_d:
1940          and       v1, a2, MIPS_FCSR_RM                    # get rounding mode
1941_cvt_w_d:
1942          jal       _C_LABEL(get_fs_d)
1943          bne       t1, DEXP_INF, 1f              # is FS an infinity?
1944          bne       t2, zero, invalid_w           # invalid conversion
1945          bne       t3, zero, invalid_w           # invalid conversion
19461:
1947          bne       t1, zero, 2f                            # is FS zero?
1948          bne       t2, zero, 1f
1949          beq       t3, zero, result_fs_w                   # result is zero
19501:
1951          move      t2, zero                      # result is an inexact zero
1952          b         inexact_w
19532:
1954          subu      t1, t1, DEXP_BIAS             # unbias exponent
1955          or        t2, t2, DIMPL_ONE             # add implied one bit
1956cvt_w:
1957#if 0
1958          blt       t1, WEXP_MIN, underflow_w     # is exponent too small?
1959#else
1960          bge       t1, WEXP_MIN, 3f              # is exponent too small?
1961          beq       v1, MIPS_FCSR_RM_RP, 1f                 # round to +infinity
1962          beq       v1, MIPS_FCSR_RM_RM, 2f                 # round to -infinity
1963
1964          move      t2, zero
1965          b         result_fs_w
19661:
1967          xori      t2, t0, 1
1968          b         result_fs_w
19692:
1970          sll       t2, t0, 31
1971          sra       t2, t2, 31
1972          b         result_fs_w
1973
19743:
1975#endif
1976          li        v0, WEXP_MAX+1
1977          bgt       t1, v0, overflow_w            # is exponent too large?
1978          bne       t1, v0, 1f                              # special check for INT_MIN
1979          beq       t0, zero, overflow_w                    # if positive, overflow
1980          bne       t2, DIMPL_ONE, overflow_w
1981          bne       t3, zero, overflow_w
1982          li        t2, INT_MIN                             # result is INT_MIN
1983          b         result_fs_w
19841:
1985          subu      v0, t1, 20                              # compute amount to shift
1986          beq       v0, zero, 2f                            # is shift needed?
1987          li        v1, 32
1988          blt       v0, zero, 1f                            # if shift < 0, shift right
1989          subu      v1, v1, v0                              # shift left
1990          sll       t2, t2, v0
1991          srl       v1, t3, v1                              # save bits shifted out of t3
1992          or        t2, t2, v1                              # and put into t2
1993          sll       t3, t3, v0                              # shift FSs fraction
1994          b         2f
19951:
1996          negu      v0                                      # shift right by v0
1997          subu      v1, v1, v0
1998          sll       t9, t3, v1                              # save bits shifted out
1999          sltu      t9, zero, t9                            # dont lose any ones
2000          srl       t3, t3, v0                              # shift FSs fraction
2001          or        t3, t3, t9
2002          sll       v1, t2, v1                              # save bits shifted out of t2
2003          or        t3, t3, v1                              # and put into t3
2004          srl       t2, t2, v0
2005/*
2006 * round result (t0 is sign, t2 is integer part, t3 is fractional part).
2007 */
20082:
2009          and       v0, a2, MIPS_FCSR_RM                    # get rounding mode
2010          beq       v0, MIPS_FCSR_RM_RN, 3f                 # round to nearest
2011          beq       v0, MIPS_FCSR_RM_RZ, 5f                 # round to zero (truncate)
2012          beq       v0, MIPS_FCSR_RM_RP, 1f                 # round to +infinity
2013          beq       t0, zero, 5f                            # if sign is positive, truncate
2014          b         2f
20151:
2016          bne       t0, zero, 5f                            # if sign is negative, truncate
20172:
2018          beq       t3, zero, 5f                            # if no fraction bits, continue
2019          addu      t2, t2, 1                     # add rounding bit
2020          blt       t2, zero, overflow_w                    # overflow?
2021          b         5f
20223:
2023          li        v0, GUARDBIT                            # load guard bit for rounding
2024          addu      v0, v0, t3                              # add remainder
2025          sltu      v1, v0, t3                              # compute carry out
2026          beq       v1, zero, 4f                            # if no carry, continue
2027          addu      t2, t2, 1                     # add carry to result
2028          blt       t2, zero, overflow_w                    # overflow?
20294:
2030          bne       v0, zero, 5f                            # if rounded remainder is zero
2031          and       t2, t2, ~1                              #  clear LSB (round to nearest)
20325:
2033          beq       t0, zero, 1f                            # result positive?
2034          negu      t2                                      # convert to negative integer
20351:
2036          beq       t3, zero, result_fs_w                   # is result exact?
2037/*
2038 * Handle inexact exception.
2039 */
2040inexact_w:
2041          or        a2, a2, MIPS_FCSR_CAUSE_I | MIPS_FCSR_FLAGS_I
2042          and       v0, a2, MIPS_FCSR_ENABLES_I
2043          bne       v0, zero, fpe_trap
2044#ifdef FPEMUL
2045          PTR_L     v0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
2046          #nop
2047          INT_S     a2, PCB_FPREGS+FRAME_FSR(v0)
2048#else
2049          ctc1      a2, MIPS_FCSR                           # save exceptions
2050#endif
2051          b         result_fs_w
2052
2053/*
2054 * Conversions to integer which overflow will trap (if enabled),
2055 * or generate an inexact trap (if enabled),
2056 * or generate an invalid exception.
2057 */
2058overflow_w:
2059          or        a2, a2, MIPS_FCSR_CAUSE_O | MIPS_FCSR_FLAGS_O
2060          and       v0, a2, MIPS_FCSR_ENABLES_O
2061          bne       v0, zero, fpe_trap
2062          and       v0, a2, MIPS_FCSR_ENABLES_I
2063          bne       v0, zero, inexact_w           # inexact traps enabled?
2064          b         invalid_w
2065
2066/*
2067 * Conversions to integer which underflow will trap (if enabled),
2068 * or generate an inexact trap (if enabled),
2069 * or generate an invalid exception.
2070 */
2071underflow_w:
2072          or        a2, a2, MIPS_FCSR_CAUSE_U | MIPS_FCSR_FLAGS_U
2073          and       v0, a2, MIPS_FCSR_ENABLES_U
2074          bne       v0, zero, fpe_trap
2075          and       v0, a2, MIPS_FCSR_ENABLES_I
2076          bne       v0, zero, inexact_w           # inexact traps enabled?
2077          b         invalid_w
2078
2079/*
2080 * Compare single.
2081 */
2082cmp_s:
2083          jal       _C_LABEL(get_cmp_s)
2084          bne       t1, SEXP_INF, 1f              # is FS an infinity?
2085          bne       t2, zero, unordered           # FS is a NAN
20861:
2087          bne       ta1, SEXP_INF, 2f             # is FT an infinity?
2088          bne       ta2, zero, unordered                    # FT is a NAN
20892:
2090          sll       t1, t1, 23                              # reassemble exp & frac
2091          or        t1, t1, t2
2092          sll       ta1, ta1, 23                            # reassemble exp & frac
2093          or        ta1, ta1, ta2
2094          beq       t0, zero, 1f                            # is FS positive?
2095          negu      t1
20961:
2097          beq       ta0, zero, 1f                           # is FT positive?
2098          negu      ta1
20991:
2100          li        v0, COND_LESS
2101          blt       t1, ta1, test_cond            # is FS < FT?
2102          li        v0, COND_EQUAL
2103          beq       t1, ta1, test_cond            # is FS == FT?
2104          move      v0, zero                      # FS > FT
2105          b         test_cond
2106
2107/*
2108 * Compare double.
2109 */
2110cmp_d:
2111          jal       _C_LABEL(get_cmp_d)
2112          bne       t1, DEXP_INF, 1f              # is FS an infinity?
2113          bne       t2, zero, unordered
2114          bne       t3, zero, unordered           # FS is a NAN
21151:
2116          bne       ta1, DEXP_INF, 2f             # is FT an infinity?
2117          bne       ta2, zero, unordered
2118          bne       ta3, zero, unordered                    # FT is a NAN
21192:
2120          sll       t1, t1, 20                              # reassemble exp & frac
2121          or        t1, t1, t2
2122          sll       ta1, ta1, 20                            # reassemble exp & frac
2123          or        ta1, ta1, ta2
2124          beq       t0, zero, 1f                            # is FS positive?
2125          not       t3                                      # negate t1,t3
2126          not       t1
2127          addu      t3, t3, 1
2128          seq       v0, t3, zero                            # compute carry
2129          addu      t1, t1, v0
21301:
2131          beq       ta0, zero, 1f                           # is FT positive?
2132          not       ta3                                     # negate ta1,ta3
2133          not       ta1
2134          addu      ta3, ta3, 1
2135          seq       v0, ta3, zero                           # compute carry
2136          addu      ta1, ta1, v0
21371:
2138          li        v0, COND_LESS
2139          blt       t1, ta1, test_cond            # is FS(MSW) < FT(MSW)?
2140          move      v0, zero
2141          bne       t1, ta1, test_cond            # is FS(MSW) > FT(MSW)?
2142          li        v0, COND_LESS
2143          bltu      t3, ta3, test_cond            # is FS(LSW) < FT(LSW)?
2144          li        v0, COND_EQUAL
2145          beq       t3, ta3, test_cond            # is FS(LSW) == FT(LSW)?
2146          move      v0, zero                      # FS > FT
2147test_cond:
2148          and       v0, v0, a0                              # condition match instruction?
2149set_cond:
2150          bne       v0, zero, 1f
2151          and       a2, a2, ~MIPS_FCSR_FCC0                 # clear condition bit
2152          b         2f
21531:
2154          or        a2, a2, MIPS_FCSR_FCC0                  # set condition bit
21552:
2156#ifdef FPEMUL
2157          PTR_L     v0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
2158          #nop
2159          INT_S     a2, PCB_FPREGS+FRAME_FSR(v0)
2160#else
2161          ctc1      a2, MIPS_FCSR                           # save condition bit
2162#endif
2163          b         done
2164
2165unordered:
2166          and       v0, a0, COND_UNORDERED                  # this cmp match unordered?
2167          bne       v0, zero, 1f
2168          and       a2, a2, ~MIPS_FCSR_FCC0                 # clear condition bit
2169          b         2f
21701:
2171          or        a2, a2, MIPS_FCSR_FCC0                  # set condition bit
21722:
2173          and       v0, a0, COND_SIGNAL
2174          beq       v0, zero, 1f                            # is this a signaling cmp?
2175          or        a2, a2, MIPS_FCSR_CAUSE_V | MIPS_FCSR_FLAGS_V
2176          and       v0, a2, MIPS_FCSR_ENABLES_V
2177          bne       v0, zero, fpe_trap
21781:
2179#ifdef FPEMUL
2180          PTR_L     v0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
2181          #nop
2182          INT_S     a2, PCB_FPREGS+FRAME_FSR(v0)
2183#else
2184          ctc1      a2, MIPS_FCSR                           # save condition bit
2185#endif
2186          b         done
2187
2188/*
2189 * Determine the amount to shift the fraction in order to restore the
2190 * normalized position. After that, round and handle exceptions.
2191 */
2192norm_s:
2193#if __mips == 32 || __mips == 64
2194#ifdef __mips_o32
2195          bne       t2, zero, 1f
2196          clz       v1, t9
2197          addu      v1, 32
2198          b         2f
21991:
2200          clz       v1, t2
22012:
2202#elif __mips_isa_rev == 2
2203          move      v0, t9
2204          dins      v0, t2, 32, 32
2205          dclz      v1, v0
2206#else
2207          dsll      v0, t9, 32
2208          dsrl      v0, v0, 32
2209          dsll      v1, t2, 32
2210          or        v0, v1
2211          dclz      v1, v0
2212#endif
2213#else
2214          .set      noat
2215          move      v0, t2                                  # MSW
2216          move      v1, zero                      # v1 = num of leading zeros
2217          bne       t2, zero, 1f
2218          move      v0, t9                                  # LSW
2219          addu      v1, 32
22201:
2221          srl       AT, v0, 16
2222          bne       AT, zero, 1f
2223          addu      v1, 16
2224          sll       v0, 16
22251:
2226          srl       AT, v0, 24
2227          bne       AT, zero, 1f
2228          addu      v1, 8
2229          sll       v0, 8
22301:
2231          srl       AT, v0, 28
2232          bne       AT, zero, 1f
2233          addu      v1, 4
2234          sll       v0, 4
22351:
2236          srl       AT, v0, 30
2237          bne       AT, zero, 1f
2238          addu      v1, 2
2239          sll       v0, 2
22401:
2241          srl       AT, v0, 31
2242          bne       AT, zero, 1f
2243          addu      v1, 1
22442:
2245          .set      at
2246#endif    /* __mips == 32 || __mips == 64 */
2247/*
2248 * Now shift t2,t9 the correct number of bits.
2249 */
2250          subu      v1, v1, SLEAD_ZEROS           # dont count leading zeros
2251          subu      t1, t1, v1                              # adjust the exponent
2252          beq       v1, zero, norm_noshift_s
2253          li        ta1, 32
2254          blt       v1, zero, 1f                            # if shift < 0, shift right
2255          subu      ta1, ta1, v1
2256          sll       t2, t2, v1                              # shift t2,t9 left
2257          srl       v0, t9, ta1                             # save bits shifted out
2258          or        t2, t2, v0
2259          sll       t9, t9, v1
2260          b         norm_noshift_s
22611:
2262          negu      v1                                      # shift t2,t9 right by at
2263          subu      ta1, ta1, v1
2264          sll       v0, t9, ta1                             # save bits shifted out
2265          sltu      v0, zero, v0                            # be sure to save any one bits
2266          srl       t9, t9, v1
2267          or        t9, t9, v0
2268          sll       v0, t2, ta1                             # save bits shifted out
2269          or        t9, t9, v0
2270          srl       t2, t2, v1
2271norm_noshift_s:
2272          move      ta1, t1                                 # save unrounded exponent
2273          move      ta2, t2                                 # save unrounded fraction
2274          and       v0, a2, MIPS_FCSR_RM                    # get rounding mode
2275          beq       v0, MIPS_FCSR_RM_RN, 3f                 # round to nearest
2276          beq       v0, MIPS_FCSR_RM_RZ, 5f                 # round to zero (truncate)
2277          beq       v0, MIPS_FCSR_RM_RP, 1f                 # round to +infinity
2278          beq       t0, zero, 5f                            # if sign is positive, truncate
2279          b         2f
22801:
2281          bne       t0, zero, 5f                            # if sign is negative, truncate
22822:
2283          beq       t9, zero, 5f                            # if exact, continue
2284          addu      t2, t2, 1                     # add rounding bit
2285          bne       t2, SIMPL_ONE<<1, 5f                    # need to adjust exponent?
2286          addu      t1, t1, 1                     # adjust exponent
2287          srl       t2, t2, 1                     # renormalize fraction
2288          b         5f
22893:
2290          li        v0, GUARDBIT                            # load guard bit for rounding
2291          addu      v0, v0, t9                              # add remainder
2292          sltu      v1, v0, t9                              # compute carry out
2293          beq       v1, zero, 4f                            # if no carry, continue
2294          addu      t2, t2, 1                     # add carry to result
2295          bne       t2, SIMPL_ONE<<1, 4f                    # need to adjust exponent?
2296          addu      t1, t1, 1                     # adjust exponent
2297          srl       t2, t2, 1                     # renormalize fraction
22984:
2299          bne       v0, zero, 5f                            # if rounded remainder is zero
2300          and       t2, t2, ~1                              #  clear LSB (round to nearest)
23015:
2302          bgt       t1, SEXP_MAX, overflow_s      # overflow?
2303          blt       t1, SEXP_MIN, underflow_s     # underflow?
2304          bne       t9, zero, inexact_s           # is result inexact?
2305          addu      t1, t1, SEXP_BIAS             # bias exponent
2306          and       t2, t2, ~SIMPL_ONE            # clear implied one bit
2307          b         result_fs_s
2308
2309/*
2310 * Handle inexact exception.
2311 */
2312inexact_s:
2313          addu      t1, t1, SEXP_BIAS             # bias exponent
2314          and       t2, t2, ~SIMPL_ONE            # clear implied one bit
2315inexact_nobias_s:
2316          jal       _C_LABEL(set_fd_s)            # save result
2317          or        a2, a2, MIPS_FCSR_CAUSE_I | MIPS_FCSR_FLAGS_I
2318          and       v0, a2, MIPS_FCSR_ENABLES_I
2319          bne       v0, zero, fpe_trap
2320#ifdef FPEMUL
2321          PTR_L     v0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
2322          #nop
2323          INT_S     a2, PCB_FPREGS+FRAME_FSR(v0)
2324#else
2325          ctc1      a2, MIPS_FCSR                           # save exceptions
2326#endif
2327          b         done
2328
2329/*
2330 * Overflow will trap (if enabled),
2331 * or generate an inexact trap (if enabled),
2332 * or generate an infinity.
2333 */
2334overflow_s:
2335          or        a2, a2, MIPS_FCSR_CAUSE_O | MIPS_FCSR_FLAGS_O
2336          and       v0, a2, MIPS_FCSR_ENABLES_O
2337          beq       v0, zero, 1f
2338          subu      t1, t1, 192                             # bias exponent
2339          and       t2, t2, ~SIMPL_ONE            # clear implied one bit
2340          jal       _C_LABEL(set_fd_s)            # save result
2341          b         fpe_trap
23421:
2343          and       v0, a2, MIPS_FCSR_RM                    # get rounding mode
2344          beq       v0, MIPS_FCSR_RM_RN, 3f                 # round to nearest
2345          beq       v0, MIPS_FCSR_RM_RZ, 1f                 # round to zero (truncate)
2346          beq       v0, MIPS_FCSR_RM_RP, 2f                 # round to +infinity
2347          bne       t0, zero, 3f
23481:
2349          li        t1, SEXP_MAX                            # result is max finite
2350          li        t2, 0x007fffff
2351          b         inexact_s
23522:
2353          bne       t0, zero, 1b
23543:
2355          li        t1, SEXP_MAX + 1              # result is infinity
2356          move      t2, zero
2357          b         inexact_s
2358
2359/*
2360 * In this implementation, "tininess" is detected "after rounding" and
2361 * "loss of accuracy" is detected as "an inexact result".
2362 */
2363underflow_s:
2364          and       v0, a2, MIPS_FCSR_ENABLES_U
2365          beq       v0, zero, 1f
2366/*
2367 * Underflow is enabled so compute the result and trap.
2368 */
2369          addu      t1, t1, 192                             # bias exponent
2370          and       t2, t2, ~SIMPL_ONE            # clear implied one bit
2371          jal       _C_LABEL(set_fd_s)            # save result
2372          or        a2, a2, MIPS_FCSR_CAUSE_U | MIPS_FCSR_FLAGS_U
2373          b         fpe_trap
2374/*
2375 * Underflow is not enabled so compute the result,
2376 * signal inexact result (if it is) and trap (if enabled).
2377 */
23781:
2379          move      t1, ta1                                 # get unrounded exponent
2380          move      t2, ta2                                 # get unrounded fraction
2381          li        v0, SEXP_MIN                            # compute shift amount
2382          subu      v0, v0, t1                              # shift t2,t9 right by at
2383          blt       v0, SFRAC_BITS+2, 3f                    # shift all the bits out?
2384          move      t1, zero                      # result is inexact zero
2385          move      t2, zero
2386          or        a2, a2, MIPS_FCSR_CAUSE_U | MIPS_FCSR_FLAGS_U
2387/*
2388 * Now round the zero result.
2389 * Only need to worry about rounding to +- infinity when the sign matches.
2390 */
2391          and       v0, a2, MIPS_FCSR_RM                    # get rounding mode
2392          beq       v0, MIPS_FCSR_RM_RN, inexact_nobias_s   # round to nearest
2393          beq       v0, MIPS_FCSR_RM_RZ, inexact_nobias_s   # round to zero
2394          beq       v0, MIPS_FCSR_RM_RP, 1f                 # round to +infinity
2395          beq       t0, zero, inexact_nobias_s    # if sign is positive, truncate
2396          b         2f
23971:
2398          bne       t0, zero, inexact_nobias_s    # if sign is negative, truncate
23992:
2400          addu      t2, t2, 1                     # add rounding bit
2401          b         inexact_nobias_s
24023:
2403          .set      noat
2404          li        v1, 32
2405          subu      v1, v1, v0
2406          sltu      AT, zero, t9                            # be sure to save any one bits
2407          sll       t9, t2, v1                              # save bits shifted out
2408          or        t9, t9, AT                              # include sticky bits
2409          srl       t2, t2, v0
2410          .set      at
2411/*
2412 * Now round the denormalized result.
2413 */
2414          and       v0, a2, MIPS_FCSR_RM                    # get rounding mode
2415          beq       v0, MIPS_FCSR_RM_RN, 3f                 # round to nearest
2416          beq       v0, MIPS_FCSR_RM_RZ, 5f                 # round to zero (truncate)
2417          beq       v0, MIPS_FCSR_RM_RP, 1f                 # round to +infinity
2418          beq       t0, zero, 5f                            # if sign is positive, truncate
2419          b         2f
24201:
2421          bne       t0, zero, 5f                            # if sign is negative, truncate
24222:
2423          beq       t9, zero, 5f                            # if exact, continue
2424          addu      t2, t2, 1                     # add rounding bit
2425          b         5f
24263:
2427          li        v0, GUARDBIT                            # load guard bit for rounding
2428          addu      v0, v0, t9                              # add remainder
2429          sltu      v1, v0, t9                              # compute carry out
2430          beq       v1, zero, 4f                            # if no carry, continue
2431          addu      t2, t2, 1                     # add carry to result
24324:
2433          bne       v0, zero, 5f                            # if rounded remainder is zero
2434          and       t2, t2, ~1                              #  clear LSB (round to nearest)
24355:
2436          move      t1, zero                      # denorm or zero exponent
2437          jal       _C_LABEL(set_fd_s)            # save result
2438          beq       t9, zero, done                          # check for exact result
2439          or        a2, a2, MIPS_FCSR_CAUSE_U | MIPS_FCSR_FLAGS_U
2440          or        a2, a2, MIPS_FCSR_CAUSE_I | MIPS_FCSR_FLAGS_I
2441          and       v0, a2, MIPS_FCSR_ENABLES_I
2442          bne       v0, zero, fpe_trap
2443#ifdef FPEMUL
2444          PTR_L     v0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
2445          #nop
2446          INT_S     a2, PCB_FPREGS+FRAME_FSR(v0)
2447#else
2448          ctc1      a2, MIPS_FCSR                           # save exceptions
2449#endif
2450          b         done
2451
2452/*
2453 * Determine the amount to shift the fraction in order to restore the
2454 * normalized position. After that, round and handle exceptions.
2455 */
2456norm_d:
2457#if __mips == 32 || __mips == 64
2458          bne       t2, zero, 2f
2459          bne       t3, zero, 1f
2460          clz       v1, t9
2461          addu      v1, 64
2462          b         3f
24631:
2464          clz       v1, t3
2465          addu      v1, 32
2466          b         3f
24672:
2468          clz       v1, t2
24693:
2470#else
2471          .set      noat
2472          move      v0, t2
2473          move      v1, zero                      # v1 = num of leading zeros
2474          bne       t2, zero, 1f
2475          move      v0, t3
2476          addu      v1, 32
2477          bne       t3, zero, 1f
2478          move      v0, t9
2479          addu      v1, 32
24801:
2481          srl       AT, v0, 16
2482          bne       AT, zero, 1f
2483          addu      v1, 16
2484          sll       v0, 16
24851:
2486          srl       AT, v0, 24
2487          bne       AT, zero, 1f
2488          addu      v1, 8
2489          sll       v0, 8
24901:
2491          srl       AT, v0, 28
2492          bne       AT, zero, 1f
2493          addu      v1, 4
2494          sll       v0, 4
24951:
2496          srl       AT, v0, 30
2497          bne       AT, zero, 1f
2498          addu      v1, 2
2499          sll       v0, 2
25001:
2501          srl       AT, v0, 31
2502          bne       AT, zero, 1f
2503          addu      v1, 1
25041:
2505          .set      at
2506#endif /* __mips_isa == 32 || __mips_isa == 64 */
2507/*
2508 * Now shift t2,t3,t9 the correct number of bits.
2509 */
2510          subu      v1, v1, DLEAD_ZEROS           # dont count leading zeros
2511          subu      t1, t1, v1                              # adjust the exponent
2512          beq       v1, zero, norm_noshift_d
2513
2514          li        ta1, 32
2515          blt       v1, zero, 2f                            # if shift < 0, shift right
2516          blt       v1, ta1, 1f                             # shift by < 32?
2517          subu      v1, v1, ta1                             # shift by >= 32
2518          subu      ta1, ta1, v1
2519          sll       t2, t3, v1                              # shift left by v1
2520          srl       v0, t9, ta1                             # save bits shifted out
2521          or        t2, t2, v0
2522          sll       t3, t9, v1
2523          move      t9, zero
2524          b         norm_noshift_d
25251:
2526          subu      ta1, ta1, v1
2527          sll       t2, t2, v1                              # shift left by v1
2528          srl       v0, t3, ta1                             # save bits shifted out
2529          or        t2, t2, v0
2530          sll       t3, t3, v1
2531          srl       v0, t9, ta1                             # save bits shifted out
2532          or        t3, t3, v0
2533          sll       t9, t9, v1
2534          b         norm_noshift_d
25352:
2536          negu      v1                                      # shift right by at
2537          subu      ta1, ta1, v1                            #  (known to be < 32 bits)
2538          sll       v0, t9, ta1                             # save bits shifted out
2539          sltu      v0, zero, v0                            # be sure to save any one bits
2540          srl       t9, t9, v1
2541          or        t9, t9, v0
2542          sll       v0, t3, ta1                             # save bits shifted out
2543          or        t9, t9, v0
2544          srl       t3, t3, v1
2545          sll       v0, t2, ta1                             # save bits shifted out
2546          or        t3, t3, v0
2547          srl       t2, t2, v1
2548norm_noshift_d:
2549          move      ta1, t1                                 # save unrounded exponent
2550          move      ta2, t2                                 # save unrounded fraction (MS)
2551          move      ta3, t3                                 # save unrounded fraction (LS)
2552          and       v0, a2, MIPS_FCSR_RM                    # get rounding mode
2553          beq       v0, MIPS_FCSR_RM_RN, 3f                 # round to nearest
2554          beq       v0, MIPS_FCSR_RM_RZ, 5f                 # round to zero (truncate)
2555          beq       v0, MIPS_FCSR_RM_RP, 1f                 # round to +infinity
2556          beq       t0, zero, 5f                            # if sign is positive, truncate
2557          b         2f
25581:
2559          bne       t0, zero, 5f                            # if sign is negative, truncate
25602:
2561          beq       t9, zero, 5f                            # if exact, continue
2562          addu      t3, t3, 1                     # add rounding bit
2563          bne       t3, zero, 5f                            # branch if no carry
2564          addu      t2, t2, 1                     # add carry
2565          bne       t2, DIMPL_ONE<<1, 5f                    # need to adjust exponent?
2566          addu      t1, t1, 1                     # adjust exponent
2567          srl       t2, t2, 1                     # renormalize fraction
2568          b         5f
25693:
2570          li        v0, GUARDBIT                            # load guard bit for rounding
2571          addu      v0, v0, t9                              # add remainder
2572          sltu      v1, v0, t9                              # compute carry out
2573          beq       v1, zero, 4f                            # branch if no carry
2574          addu      t3, t3, 1                     # add carry
2575          bne       t3, zero, 4f                            # branch if no carry
2576          addu      t2, t2, 1                     # add carry to result
2577          bne       t2, DIMPL_ONE<<1, 4f                    # need to adjust exponent?
2578          addu      t1, t1, 1                     # adjust exponent
2579          srl       t2, t2, 1                     # renormalize fraction
25804:
2581          bne       v0, zero, 5f                            # if rounded remainder is zero
2582          and       t3, t3, ~1                              #  clear LSB (round to nearest)
25835:
2584          bgt       t1, DEXP_MAX, overflow_d      # overflow?
2585          blt       t1, DEXP_MIN, underflow_d     # underflow?
2586          bne       t9, zero, inexact_d           # is result inexact?
2587          addu      t1, t1, DEXP_BIAS             # bias exponent
2588          and       t2, t2, ~DIMPL_ONE            # clear implied one bit
2589          b         result_fs_d
2590
2591/*
2592 * Handle inexact exception.
2593 */
2594inexact_d:
2595          addu      t1, t1, DEXP_BIAS             # bias exponent
2596          and       t2, t2, ~DIMPL_ONE            # clear implied one bit
2597inexact_nobias_d:
2598          jal       _C_LABEL(set_fd_d)            # save result
2599          or        a2, a2, MIPS_FCSR_CAUSE_I | MIPS_FCSR_FLAGS_I
2600          and       v0, a2, MIPS_FCSR_ENABLES_I
2601          bne       v0, zero, fpe_trap
2602#ifdef FPEMUL
2603          PTR_L     v0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
2604          #nop
2605          INT_S     a2, PCB_FPREGS+FRAME_FSR(v0)
2606#else
2607          ctc1      a2, MIPS_FCSR                           # save exceptions
2608#endif
2609          b         done
2610
2611/*
2612 * Overflow will trap (if enabled),
2613 * or generate an inexact trap (if enabled),
2614 * or generate an infinity.
2615 */
2616overflow_d:
2617          or        a2, a2, MIPS_FCSR_CAUSE_O | MIPS_FCSR_FLAGS_O
2618          and       v0, a2, MIPS_FCSR_ENABLES_O
2619          beq       v0, zero, 1f
2620          subu      t1, t1, 1536                            # bias exponent
2621          and       t2, t2, ~DIMPL_ONE            # clear implied one bit
2622          jal       _C_LABEL(set_fd_d)            # save result
2623          b         fpe_trap
26241:
2625          and       v0, a2, MIPS_FCSR_RM                    # get rounding mode
2626          beq       v0, MIPS_FCSR_RM_RN, 3f                 # round to nearest
2627          beq       v0, MIPS_FCSR_RM_RZ, 1f                 # round to zero (truncate)
2628          beq       v0, MIPS_FCSR_RM_RP, 2f                 # round to +infinity
2629          bne       t0, zero, 3f
26301:
2631          li        t1, DEXP_MAX                            # result is max finite
2632          li        t2, 0x000fffff
2633          li        t3, 0xffffffff
2634          b         inexact_d
26352:
2636          bne       t0, zero, 1b
26373:
2638          li        t1, DEXP_MAX + 1              # result is infinity
2639          move      t2, zero
2640          move      t3, zero
2641          b         inexact_d
2642
2643/*
2644 * In this implementation, "tininess" is detected "after rounding" and
2645 * "loss of accuracy" is detected as "an inexact result".
2646 */
2647underflow_d:
2648          and       v0, a2, MIPS_FCSR_ENABLES_U
2649          beq       v0, zero, 1f
2650/*
2651 * Underflow is enabled so compute the result and trap.
2652 */
2653          addu      t1, t1, 1536                            # bias exponent
2654          and       t2, t2, ~DIMPL_ONE            # clear implied one bit
2655          jal       _C_LABEL(set_fd_d)            # save result
2656          or        a2, a2, MIPS_FCSR_CAUSE_U | MIPS_FCSR_FLAGS_U
2657          b         fpe_trap
2658/*
2659 * Underflow is not enabled so compute the result,
2660 * signal inexact result (if it is) and trap (if enabled).
2661 */
26621:
2663          move      t1, ta1                                 # get unrounded exponent
2664          move      t2, ta2                                 # get unrounded fraction (MS)
2665          move      t3, ta3                                 # get unrounded fraction (LS)
2666          li        v0, DEXP_MIN                            # compute shift amount
2667          subu      v0, v0, t1                              # shift t2,t9 right by at
2668          blt       v0, DFRAC_BITS+2, 3f                    # shift all the bits out?
2669          move      t1, zero                      # result is inexact zero
2670          move      t2, zero
2671          move      t3, zero
2672          or        a2, a2, MIPS_FCSR_CAUSE_U | MIPS_FCSR_FLAGS_U
2673/*
2674 * Now round the zero result.
2675 * Only need to worry about rounding to +- infinity when the sign matches.
2676 */
2677          and       v0, a2, MIPS_FCSR_RM                    # get rounding mode
2678          beq       v0, MIPS_FCSR_RM_RN, inexact_nobias_d   # round to nearest
2679          beq       v0, MIPS_FCSR_RM_RZ, inexact_nobias_d   # round to zero
2680          beq       v0, MIPS_FCSR_RM_RP, 1f                 # round to +infinity
2681          beq       t0, zero, inexact_nobias_d    # if sign is positive, truncate
2682          b         2f
26831:
2684          bne       t0, zero, inexact_nobias_d    # if sign is negative, truncate
26852:
2686          addu      t3, t3, 1                     # add rounding bit
2687          b         inexact_nobias_d
26883:
2689          li        v1, 32
2690          blt       v0, v1, 1f                              # shift by < 32?
2691          subu      v0, v0, v1                              # shift right by >= 32
2692          subu      v1, v1, v0
2693          .set      noat
2694          sltu      AT, zero, t9                            # be sure to save any one bits
2695          sll       t9, t2, v1                              # save bits shifted out
2696          or        t9, t9, AT                              # include sticky bits
2697          srl       t3, t2, v0
2698          move      t2, zero
2699          .set      at
2700          b         2f
27011:
2702          .set      noat
2703          subu      v1, v1, v0                              # shift right by at
2704          sltu      AT, zero, t9                            # be sure to save any one bits
2705          sll       t9, t3, v1                              # save bits shifted out
2706          or        t9, t9, AT                              # include sticky bits
2707          srl       t3, t3, v0
2708          sll       AT, t2, v1                              # save bits shifted out
2709          or        t3, t3, AT
2710          srl       t2, t2, v0
2711          .set      at
2712/*
2713 * Now round the denormalized result.
2714 */
27152:
2716          and       v0, a2, MIPS_FCSR_RM                    # get rounding mode
2717          beq       v0, MIPS_FCSR_RM_RN, 3f                 # round to nearest
2718          beq       v0, MIPS_FCSR_RM_RZ, 5f                 # round to zero (truncate)
2719          beq       v0, MIPS_FCSR_RM_RP, 1f                 # round to +infinity
2720          beq       t0, zero, 5f                            # if sign is positive, truncate
2721          b         2f
27221:
2723          bne       t0, zero, 5f                            # if sign is negative, truncate
27242:
2725          beq       t9, zero, 5f                            # if exact, continue
2726          addu      t3, t3, 1                     # add rounding bit
2727          bne       t3, zero, 5f                            # if no carry, continue
2728          addu      t2, t2, 1                     # add carry
2729          b         5f
27303:
2731          li        v0, GUARDBIT                            # load guard bit for rounding
2732          addu      v0, v0, t9                              # add remainder
2733          sltu      v1, v0, t9                              # compute carry out
2734          beq       v1, zero, 4f                            # if no carry, continue
2735          addu      t3, t3, 1                     # add rounding bit
2736          bne       t3, zero, 4f                            # if no carry, continue
2737          addu      t2, t2, 1                     # add carry
27384:
2739          bne       v0, zero, 5f                            # if rounded remainder is zero
2740          and       t3, t3, ~1                              #  clear LSB (round to nearest)
27415:
2742          move      t1, zero                      # denorm or zero exponent
2743          jal       _C_LABEL(set_fd_d)            # save result
2744          beq       t9, zero, done                          # check for exact result
2745          or        a2, a2, MIPS_FCSR_CAUSE_U | MIPS_FCSR_FLAGS_U
2746          or        a2, a2, MIPS_FCSR_CAUSE_I | MIPS_FCSR_FLAGS_I
2747          and       v0, a2, MIPS_FCSR_ENABLES_I
2748          bne       v0, zero, fpe_trap
2749#ifdef FPEMUL
2750          PTR_L     v0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
2751          #nop
2752          INT_S     a2, PCB_FPREGS+FRAME_FSR(v0)
2753#else
2754          ctc1      a2, MIPS_FCSR                           # save exceptions
2755#endif
2756          b         done
2757
2758/*
2759 * Signal an invalid operation if the trap is enabled; otherwise,
2760 * the result is a quiet NAN.
2761 */
2762invalid_s:                                                  # trap invalid operation
2763          or        a2, a2, MIPS_FCSR_CAUSE_V | MIPS_FCSR_FLAGS_V
2764          and       v0, a2, MIPS_FCSR_ENABLES_V
2765          bne       v0, zero, fpe_trap
2766#ifdef FPEMUL
2767          PTR_L     v0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
2768          #nop
2769          INT_S     a2, PCB_FPREGS+FRAME_FSR(v0)
2770#else
2771          ctc1      a2, MIPS_FCSR                           # save exceptions
2772#endif
2773          move      t0, zero                      # result is a quiet NAN
2774          li        t1, SEXP_INF
2775          li        t2, SQUIET_NAN
2776          jal       _C_LABEL(set_fd_s)            # save result (in t0,t1,t2)
2777          b         done
2778
2779/*
2780 * Signal an invalid operation if the trap is enabled; otherwise,
2781 * the result is a quiet NAN.
2782 */
2783invalid_d:                                                  # trap invalid operation
2784          or        a2, a2, MIPS_FCSR_CAUSE_V | MIPS_FCSR_FLAGS_V
2785          and       v0, a2, MIPS_FCSR_ENABLES_V
2786          bne       v0, zero, fpe_trap
2787#ifdef FPEMUL
2788          PTR_L     v0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
2789          #nop
2790          INT_S     a2, PCB_FPREGS+FRAME_FSR(v0)
2791#else
2792          ctc1      a2, MIPS_FCSR                           # save exceptions
2793#endif
2794          move      t0, zero                      # result is a quiet NAN
2795          li        t1, DEXP_INF
2796          li        t2, DQUIET_NAN0
2797          li        t3, DQUIET_NAN1
2798          jal       _C_LABEL(set_fd_d)            # save result (in t0,t1,t2,t3)
2799          b         done
2800
2801/*
2802 * Signal an invalid operation if the trap is enabled; otherwise,
2803 * the result is INT_MAX or INT_MIN.
2804 */
2805invalid_w:                                                  # trap invalid operation
2806          or        a2, a2, MIPS_FCSR_CAUSE_V | MIPS_FCSR_FLAGS_V
2807          and       v0, a2, MIPS_FCSR_ENABLES_V
2808          bne       v0, zero, fpe_trap
2809#ifdef FPEMUL
2810          PTR_L     v0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
2811          #nop
2812          INT_S     a2, PCB_FPREGS+FRAME_FSR(v0)
2813#else
2814          ctc1      a2, MIPS_FCSR                           # save exceptions
2815#endif
2816          bne       t0, zero, 1f
2817          li        t2, INT_MAX                             # result is INT_MAX
2818          b         result_fs_w
28191:
2820          li        t2, INT_MIN                             # result is INT_MIN
2821          b         result_fs_w
2822
2823/*
2824 * Trap if the hardware should have handled this case.
2825 */
2826fpe_trap:
2827#ifdef FPEMUL
2828          PTR_L     v0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
2829          #nop
2830          INT_S     a2, PCB_FPREGS+FRAME_FSR(v0)
2831#else
2832          /*
2833           * ctc1 with fpe bits set causes FPE in kernel mode panic on 5231.
2834           */
2835          REG_S     a2, CALLFRAME_SIZ + 3*SZREG(sp)
2836          move      a0, MIPS_CURLWP                         # get current lwp
2837          jal       _C_LABEL(fpu_save)            # on RM5231
2838
2839          REG_L     a2, CALLFRAME_SIZ + 3*SZREG(sp)
2840
2841          PTR_L     v0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
2842          #nop
2843          INT_S     a2, PCB_FPREGS+FRAME_FSR(v0)
2844#endif
2845          move      a3, a2                                  # fpustat
2846          REG_L     a1, CALLFRAME_FRAME(sp)                 # frame
2847          REG_L     a2, CALLFRAME_CAUSE(sp)                 # cause
2848          REG_L     ra, CALLFRAME_RA(sp)
2849          PTR_ADDU sp, CALLFRAME_SIZ
2850          j         _C_LABEL(fpemul_sigfpe)
2851
2852/*
2853 * Send an illegal instruction signal to the current lwp.
2854 */
2855ill:
2856#ifdef FPEMUL
2857          PTR_L     v0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
2858          #nop
2859          INT_S     a2, PCB_FPREGS+FRAME_FSR(v0)
2860#else
2861          ctc1      a2, MIPS_FCSR                           # save exceptions
2862#endif
2863          REG_L     a1, CALLFRAME_FRAME(sp)                 # frame
2864          REG_L     a2, CALLFRAME_CAUSE(sp)                 # cause
2865          REG_L     ra, CALLFRAME_RA(sp)
2866          PTR_ADDU sp, CALLFRAME_SIZ
2867          j         _C_LABEL(fpemul_sigill)
2868
2869result_ft_s:
2870          move      t0, ta0                                 # result is FT
2871          move      t1, ta1
2872          move      t2, ta2
2873result_fs_s:                                                # result is FS
2874          jal       _C_LABEL(set_fd_s)            # save result (in t0,t1,t2)
2875          b         done
2876
2877result_fs_w:
2878          jal       _C_LABEL(set_fd_word)                   # save result (in t2)
2879          b         done
2880
2881result_ft_d:
2882          move      t0, ta0                                 # result is FT
2883          move      t1, ta1
2884          move      t2, ta2
2885          move      t3, ta3
2886result_fs_d:                                                # result is FS
2887          jal       _C_LABEL(set_fd_d)            # save result (in t0,t1,t2,t3)
2888
2889done:
2890/*
2891 * Succeeded to emulate instruction with no error
2892 * so compute the next PC.
2893 */
2894          REG_L     t0, CALLFRAME_CAUSE(sp)
2895          REG_PROLOGUE
2896          REG_L     v0, TF_REG_EPC(a1)
2897          REG_EPILOGUE
2898          bgez      t0, 1f                                  # Check the branch delay bit.
2899/*
2900 * The instruction is in the branch delay slot so the branch will have to
2901 * be emulated to get the resulting PC.
2902 */
2903          REG_S     a1, CALLFRAME_FRAME(sp)
2904          move      a0, a1                                  # 1st arg is p. to trapframe
2905          move      a1, v0                                  # 2nd arg is instruction PC
2906                                                            # 3rd arg is FP CSR
2907          move      a3, zero                      # 4th arg is FALSE
2908          jal       _C_LABEL(mips_emul_branch)    # compute PC after branch
2909
2910          REG_L     a1, CALLFRAME_FRAME(sp)
2911          b         2f
2912/*
2913 * This is not in the branch delay slot so calculate the resulting
2914 * PC (epc + 4) into v0.
2915 */
29161:
2917          addiu     v0, v0, 4                     # v0 = next pc
29182:
2919          REG_PROLOGUE
2920          REG_S     v0, TF_REG_EPC(a1)            # save new pc
2921          REG_EPILOGUE
2922
2923          REG_L     ra, CALLFRAME_RA(sp)
2924          PTR_ADDU sp, CALLFRAME_SIZ
2925          j         ra
2926END(mips_emul_fp)
2927
2928/*----------------------------------------------------------------------------
2929 * get_fs_int --
2930 *
2931 *        Read (integer) the FS register (bits 15-11).
2932 *        This is an internal routine used by mips_emul_fp only.
2933 *
2934 * Results:
2935 *        t0        contains the sign
2936 *        t2        contains the fraction
2937 *
2938 *----------------------------------------------------------------------------
2939 */
2940STATIC_LEAF(get_fs_int)
2941#ifdef FPEMUL
2942          srl       t2, a0, 11 - FPX_SCALESHIFT
2943          PTR_L     t0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
2944          andi      t2, t2, FPX_REGEVENMASK                 # Even regs only
2945          PTR_ADDU t0, t0, t2
2946
2947          lw        t2, PCB_FPREGS+FRAME_FP0(t0)
2948
2949          srl       t0, t2, 31                    # init the sign bit
2950          bge       t2, zero, 1f
2951          negu      t2
29521:
2953          j         ra
2954#else
2955          srl       a3, a0, 11 - (PTR_SCALESHIFT-1)         # get FS field (even regs only)
2956          and       a3, a3, 0xf << PTR_SCALESHIFT # mask FS field
2957          PTR_L     a3, get_fs_int_tbl(a3)                  # switch on register number
2958          j         a3
2959
2960          .rdata
2961get_fs_int_tbl:
2962          PTR_WORD get_fs_int_f0
2963          PTR_WORD get_fs_int_f2
2964          PTR_WORD get_fs_int_f4
2965          PTR_WORD get_fs_int_f6
2966          PTR_WORD get_fs_int_f8
2967          PTR_WORD get_fs_int_f10
2968          PTR_WORD get_fs_int_f12
2969          PTR_WORD get_fs_int_f14
2970          PTR_WORD get_fs_int_f16
2971          PTR_WORD get_fs_int_f18
2972          PTR_WORD get_fs_int_f20
2973          PTR_WORD get_fs_int_f22
2974          PTR_WORD get_fs_int_f24
2975          PTR_WORD get_fs_int_f26
2976          PTR_WORD get_fs_int_f28
2977          PTR_WORD get_fs_int_f30
2978          .text
2979
2980get_fs_int_f0:
2981          mfc1      t2, $f0
2982          b         get_fs_int_done
2983get_fs_int_f2:
2984          mfc1      t2, $f2
2985          b         get_fs_int_done
2986get_fs_int_f4:
2987          mfc1      t2, $f4
2988          b         get_fs_int_done
2989get_fs_int_f6:
2990          mfc1      t2, $f6
2991          b         get_fs_int_done
2992get_fs_int_f8:
2993          mfc1      t2, $f8
2994          b         get_fs_int_done
2995get_fs_int_f10:
2996          mfc1      t2, $f10
2997          b         get_fs_int_done
2998get_fs_int_f12:
2999          mfc1      t2, $f12
3000          b         get_fs_int_done
3001get_fs_int_f14:
3002          mfc1      t2, $f14
3003          b         get_fs_int_done
3004get_fs_int_f16:
3005          mfc1      t2, $f16
3006          b         get_fs_int_done
3007get_fs_int_f18:
3008          mfc1      t2, $f18
3009          b         get_fs_int_done
3010get_fs_int_f20:
3011          mfc1      t2, $f20
3012          b         get_fs_int_done
3013get_fs_int_f22:
3014          mfc1      t2, $f22
3015          b         get_fs_int_done
3016get_fs_int_f24:
3017          mfc1      t2, $f24
3018          b         get_fs_int_done
3019get_fs_int_f26:
3020          mfc1      t2, $f26
3021          b         get_fs_int_done
3022get_fs_int_f28:
3023          mfc1      t2, $f28
3024          b         get_fs_int_done
3025get_fs_int_f30:
3026          mfc1      t2, $f30
3027get_fs_int_done:
3028          srl       t0, t2, 31                    # init the sign bit
3029          bge       t2, zero, 1f
3030          negu      t2
30311:
3032          j         ra
3033#endif
3034END(get_fs_int)
3035
3036/*----------------------------------------------------------------------------
3037 * get_ft_fs_s --
3038 *
3039 *        Read (single precision) the FT register (bits 20-16) and
3040 *        the FS register (bits 15-11) and break up into fields.
3041 *        This is an internal routine used by mips_emul_fp only.
3042 *
3043 * Results:
3044 *        t0        contains the FS sign
3045 *        t1        contains the FS (biased) exponent
3046 *        t2        contains the FS fraction
3047 *        ta0       contains the FT sign
3048 *        ta1       contains the FT (biased) exponent
3049 *        ta2       contains the FT fraction
3050 *
3051 *----------------------------------------------------------------------------
3052 */
3053STATIC_LEAF(get_ft_fs_s)
3054#ifdef FPEMUL
3055          srl       ta0, a0, 16 - FPX_SCALESHIFT
3056          PTR_L     ta1, L_PCB(MIPS_CURLWP)                 # get pcb of current lwp
3057          andi      ta0, ta0, FPX_REGEVENMASK     # Even regs only
3058          PTR_ADDU ta1, ta1, ta0
3059
3060          lw        ta0, PCB_FPREGS+FRAME_FP0(ta1)
3061
3062          srl       ta1, ta0, 23                            # get exponent
3063          and       ta1, ta1, 0xFF
3064          and       ta2, ta0, 0x7FFFFF            # get fraction
3065          srl       ta0, ta0, 31                            # get sign
3066          bne       ta1, SEXP_INF, 1f             # is it a signaling NAN?
3067          and       v0, ta2, SSIGNAL_NAN
3068          bne       v0, zero, invalid_s
30691:
3070          /* fall through to get FS */
3071#else
3072          srl       a3, a0, 16 - (PTR_SCALESHIFT - 1)# get FT field (even regs only)
3073          and       a3, a3, 0xF << PTR_SCALESHIFT # mask FT field
3074          PTR_L     a3, get_ft_s_tbl(a3)                    # switch on register number
3075          j         a3
3076
3077          .rdata
3078get_ft_s_tbl:
3079          PTR_WORD get_ft_s_f0
3080          PTR_WORD get_ft_s_f2
3081          PTR_WORD get_ft_s_f4
3082          PTR_WORD get_ft_s_f6
3083          PTR_WORD get_ft_s_f8
3084          PTR_WORD get_ft_s_f10
3085          PTR_WORD get_ft_s_f12
3086          PTR_WORD get_ft_s_f14
3087          PTR_WORD get_ft_s_f16
3088          PTR_WORD get_ft_s_f18
3089          PTR_WORD get_ft_s_f20
3090          PTR_WORD get_ft_s_f22
3091          PTR_WORD get_ft_s_f24
3092          PTR_WORD get_ft_s_f26
3093          PTR_WORD get_ft_s_f28
3094          PTR_WORD get_ft_s_f30
3095          .text
3096
3097get_ft_s_f0:
3098          mfc1      ta0, $f0
3099          b         get_ft_s_done
3100get_ft_s_f2:
3101          mfc1      ta0, $f2
3102          b         get_ft_s_done
3103get_ft_s_f4:
3104          mfc1      ta0, $f4
3105          b         get_ft_s_done
3106get_ft_s_f6:
3107          mfc1      ta0, $f6
3108          b         get_ft_s_done
3109get_ft_s_f8:
3110          mfc1      ta0, $f8
3111          b         get_ft_s_done
3112get_ft_s_f10:
3113          mfc1      ta0, $f10
3114          b         get_ft_s_done
3115get_ft_s_f12:
3116          mfc1      ta0, $f12
3117          b         get_ft_s_done
3118get_ft_s_f14:
3119          mfc1      ta0, $f14
3120          b         get_ft_s_done
3121get_ft_s_f16:
3122          mfc1      ta0, $f16
3123          b         get_ft_s_done
3124get_ft_s_f18:
3125          mfc1      ta0, $f18
3126          b         get_ft_s_done
3127get_ft_s_f20:
3128          mfc1      ta0, $f20
3129          b         get_ft_s_done
3130get_ft_s_f22:
3131          mfc1      ta0, $f22
3132          b         get_ft_s_done
3133get_ft_s_f24:
3134          mfc1      ta0, $f24
3135          b         get_ft_s_done
3136get_ft_s_f26:
3137          mfc1      ta0, $f26
3138          b         get_ft_s_done
3139get_ft_s_f28:
3140          mfc1      ta0, $f28
3141          b         get_ft_s_done
3142get_ft_s_f30:
3143          mfc1      ta0, $f30
3144get_ft_s_done:
3145          srl       ta1, ta0, 23                            # get exponent
3146          and       ta1, ta1, 0xFF
3147          and       ta2, ta0, 0x7FFFFF            # get fraction
3148          srl       ta0, ta0, 31                            # get sign
3149          bne       ta1, SEXP_INF, 1f             # is it a signaling NAN?
3150          and       v0, ta2, SSIGNAL_NAN
3151          bne       v0, zero, invalid_s
31521:
3153          /* fall through to get FS */
3154#endif
3155
3156/*----------------------------------------------------------------------------
3157 * get_fs_s --
3158 *
3159 *        Read (single precision) the FS register (bits 15-11) and
3160 *        break up into fields.
3161 *        This is an internal routine used by mips_emul_fp only.
3162 *
3163 * Results:
3164 *        t0        contains the sign
3165 *        t1        contains the (biased) exponent
3166 *        t2        contains the fraction
3167 *
3168 *----------------------------------------------------------------------------
3169 */
3170STATIC_XLEAF(get_fs_s)
3171#ifdef FPEMUL
3172          srl       t0, a0, 11 - FPX_SCALESHIFT
3173          PTR_L     t1, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
3174          andi      t0, t0, FPX_REGEVENMASK                 # Even regs only
3175          PTR_ADDU t1, t1, t0
3176
3177          lw        t0, PCB_FPREGS+FRAME_FP0(t1)
3178
3179          srl       t1, t0, 23                              # get exponent
3180          and       t1, t1, 0xFF
3181          and       t2, t0, 0x7FFFFF              # get fraction
3182          srl       t0, t0, 31                              # get sign
3183          bne       t1, SEXP_INF, 1f              # is it a signaling NAN?
3184          and       v0, t2, SSIGNAL_NAN
3185          bne       v0, zero, invalid_s
31861:
3187          j         ra
3188#else
3189          srl       a3, a0, 11 - (PTR_SCALESHIFT-1)         # get FS field (even regs only)
3190          and       a3, a3, 0xF << PTR_SCALESHIFT # mask FS field
3191          PTR_L     a3, get_fs_s_tbl(a3)                    # switch on register number
3192          j         a3
3193
3194          .rdata
3195get_fs_s_tbl:
3196          PTR_WORD get_fs_s_f0
3197          PTR_WORD get_fs_s_f2
3198          PTR_WORD get_fs_s_f4
3199          PTR_WORD get_fs_s_f6
3200          PTR_WORD get_fs_s_f8
3201          PTR_WORD get_fs_s_f10
3202          PTR_WORD get_fs_s_f12
3203          PTR_WORD get_fs_s_f14
3204          PTR_WORD get_fs_s_f16
3205          PTR_WORD get_fs_s_f18
3206          PTR_WORD get_fs_s_f20
3207          PTR_WORD get_fs_s_f22
3208          PTR_WORD get_fs_s_f24
3209          PTR_WORD get_fs_s_f26
3210          PTR_WORD get_fs_s_f28
3211          PTR_WORD get_fs_s_f30
3212          .text
3213
3214get_fs_s_f0:
3215          mfc1      t0, $f0
3216          b         get_fs_s_done
3217get_fs_s_f2:
3218          mfc1      t0, $f2
3219          b         get_fs_s_done
3220get_fs_s_f4:
3221          mfc1      t0, $f4
3222          b         get_fs_s_done
3223get_fs_s_f6:
3224          mfc1      t0, $f6
3225          b         get_fs_s_done
3226get_fs_s_f8:
3227          mfc1      t0, $f8
3228          b         get_fs_s_done
3229get_fs_s_f10:
3230          mfc1      t0, $f10
3231          b         get_fs_s_done
3232get_fs_s_f12:
3233          mfc1      t0, $f12
3234          b         get_fs_s_done
3235get_fs_s_f14:
3236          mfc1      t0, $f14
3237          b         get_fs_s_done
3238get_fs_s_f16:
3239          mfc1      t0, $f16
3240          b         get_fs_s_done
3241get_fs_s_f18:
3242          mfc1      t0, $f18
3243          b         get_fs_s_done
3244get_fs_s_f20:
3245          mfc1      t0, $f20
3246          b         get_fs_s_done
3247get_fs_s_f22:
3248          mfc1      t0, $f22
3249          b         get_fs_s_done
3250get_fs_s_f24:
3251          mfc1      t0, $f24
3252          b         get_fs_s_done
3253get_fs_s_f26:
3254          mfc1      t0, $f26
3255          b         get_fs_s_done
3256get_fs_s_f28:
3257          mfc1      t0, $f28
3258          b         get_fs_s_done
3259get_fs_s_f30:
3260          mfc1      t0, $f30
3261get_fs_s_done:
3262          srl       t1, t0, 23                              # get exponent
3263          and       t1, t1, 0xFF
3264          and       t2, t0, 0x7FFFFF              # get fraction
3265          srl       t0, t0, 31                              # get sign
3266          bne       t1, SEXP_INF, 1f              # is it a signaling NAN?
3267          and       v0, t2, SSIGNAL_NAN
3268          bne       v0, zero, invalid_s
32691:
3270          j         ra
3271#endif
3272END(get_ft_fs_s)
3273
3274/*----------------------------------------------------------------------------
3275 * get_ft_fs_d --
3276 *
3277 *        Read (double precision) the FT register (bits 20-16) and
3278 *        the FS register (bits 15-11) and break up into fields.
3279 *        This is an internal routine used by mips_emul_fp only.
3280 *
3281 * Results:
3282 *        t0        contains the FS sign
3283 *        t1        contains the FS (biased) exponent
3284 *        t2        contains the FS fraction
3285 *        t3        contains the FS remaining fraction
3286 *        ta0       contains the FT sign
3287 *        ta1       contains the FT (biased) exponent
3288 *        ta2       contains the FT fraction
3289 *        ta3       contains the FT remaining fraction
3290 *
3291 *----------------------------------------------------------------------------
3292 */
3293STATIC_LEAF(get_ft_fs_d)
3294#ifdef FPEMUL
3295          srl       ta3, a0, 16 - FPX_SCALESHIFT
3296          PTR_L     ta0, L_PCB(MIPS_CURLWP)                 # get pcb of current lwp
3297          andi      ta3, ta3, FPX_REGEVENMASK     # Even regs only
3298          PTR_ADDU ta0, ta3
3299
3300#if defined(__mips_n32) || defined(__mips_n64)
3301          FPX_L     ta3, PCB_FPREGS+FRAME_FP0(ta0)
3302          dsrl      ta0, ta3, 32
3303          srl       ta3, ta3, 0
3304#else
3305          lw        ta3, PCB_FPREGS+FRAME_FP0(ta0)
3306          lw        ta0, PCB_FPREGS+FRAME_FP0+SZFPREG(ta0)
3307#endif
3308
3309          srl       ta1, ta0, 20                            # get exponent
3310          and       ta1, ta1, 0x7FF
3311          and       ta2, ta0, 0xFFFFF             # get fraction
3312          srl       ta0, ta0, 31                            # get sign
3313          bne       ta1, DEXP_INF, 1f             # is it a signaling NAN?
3314          and       v0, ta2, DSIGNAL_NAN
3315          bne       v0, zero, invalid_d
33161:
3317          /* fall through to get FS */
3318#else
3319          srl       a3, a0, 16 - (PTR_SCALESHIFT-1)         # get FT field (even regs only)
3320          and       a3, a3, 0xF << PTR_SCALESHIFT # mask FT field
3321          PTR_L     a3, get_ft_d_tbl(a3)                    # switch on register number
3322          j         a3
3323
3324          .rdata
3325get_ft_d_tbl:
3326          PTR_WORD get_ft_d_f0
3327          PTR_WORD get_ft_d_f2
3328          PTR_WORD get_ft_d_f4
3329          PTR_WORD get_ft_d_f6
3330          PTR_WORD get_ft_d_f8
3331          PTR_WORD get_ft_d_f10
3332          PTR_WORD get_ft_d_f12
3333          PTR_WORD get_ft_d_f14
3334          PTR_WORD get_ft_d_f16
3335          PTR_WORD get_ft_d_f18
3336          PTR_WORD get_ft_d_f20
3337          PTR_WORD get_ft_d_f22
3338          PTR_WORD get_ft_d_f24
3339          PTR_WORD get_ft_d_f26
3340          PTR_WORD get_ft_d_f28
3341          PTR_WORD get_ft_d_f30
3342          .text
3343
3344get_ft_d_f0:
3345          mfc1      ta3, $f0
3346          mfc1      ta0, $f1
3347          b         get_ft_d_done
3348get_ft_d_f2:
3349          mfc1      ta3, $f2
3350          mfc1      ta0, $f3
3351          b         get_ft_d_done
3352get_ft_d_f4:
3353          mfc1      ta3, $f4
3354          mfc1      ta0, $f5
3355          b         get_ft_d_done
3356get_ft_d_f6:
3357          mfc1      ta3, $f6
3358          mfc1      ta0, $f7
3359          b         get_ft_d_done
3360get_ft_d_f8:
3361          mfc1      ta3, $f8
3362          mfc1      ta0, $f9
3363          b         get_ft_d_done
3364get_ft_d_f10:
3365          mfc1      ta3, $f10
3366          mfc1      ta0, $f11
3367          b         get_ft_d_done
3368get_ft_d_f12:
3369          mfc1      ta3, $f12
3370          mfc1      ta0, $f13
3371          b         get_ft_d_done
3372get_ft_d_f14:
3373          mfc1      ta3, $f14
3374          mfc1      ta0, $f15
3375          b         get_ft_d_done
3376get_ft_d_f16:
3377          mfc1      ta3, $f16
3378          mfc1      ta0, $f17
3379          b         get_ft_d_done
3380get_ft_d_f18:
3381          mfc1      ta3, $f18
3382          mfc1      ta0, $f19
3383          b         get_ft_d_done
3384get_ft_d_f20:
3385          mfc1      ta3, $f20
3386          mfc1      ta0, $f21
3387          b         get_ft_d_done
3388get_ft_d_f22:
3389          mfc1      ta3, $f22
3390          mfc1      ta0, $f23
3391          b         get_ft_d_done
3392get_ft_d_f24:
3393          mfc1      ta3, $f24
3394          mfc1      ta0, $f25
3395          b         get_ft_d_done
3396get_ft_d_f26:
3397          mfc1      ta3, $f26
3398          mfc1      ta0, $f27
3399          b         get_ft_d_done
3400get_ft_d_f28:
3401          mfc1      ta3, $f28
3402          mfc1      ta0, $f29
3403          b         get_ft_d_done
3404get_ft_d_f30:
3405          mfc1      ta3, $f30
3406          mfc1      ta0, $f31
3407get_ft_d_done:
3408          srl       ta1, ta0, 20                            # get exponent
3409          and       ta1, ta1, 0x7FF
3410          and       ta2, ta0, 0xFFFFF                       # get fraction
3411          srl       ta0, ta0, 31                            # get sign
3412          bne       ta1, DEXP_INF, 1f             # is it a signaling NAN?
3413          and       v0, ta2, DSIGNAL_NAN
3414          bne       v0, zero, invalid_d
34151:
3416          /* fall through to get FS */
3417#endif
3418
3419/*----------------------------------------------------------------------------
3420 * get_fs_d --
3421 *
3422 *        Read (double precision) the FS register (bits 15-11) and
3423 *        break up into fields.
3424 *        This is an internal routine used by mips_emul_fp only.
3425 *
3426 * Results:
3427 *        t0        contains the sign
3428 *        t1        contains the (biased) exponent
3429 *        t2        contains the fraction
3430 *        t3        contains the remaining fraction
3431 *
3432 *----------------------------------------------------------------------------
3433 */
3434STATIC_XLEAF(get_fs_d)
3435#ifdef FPEMUL
3436          srl       t3, a0, 11 - FPX_SCALESHIFT
3437          PTR_L     t0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
3438          andi      t3, t3, FPX_REGEVENMASK                 # Even regs only
3439          PTR_ADDU t0, t3
3440
3441#if defined(__mips_n32) || defined(__mips_n64)
3442          FPX_L     t3, PCB_FPREGS+FRAME_FP0(t0)
3443          dsrl      t0, t3, 32
3444          srl       t3, t3, 0
3445#else
3446          lw        t3, PCB_FPREGS+FRAME_FP0(t0)
3447          lw        t0, PCB_FPREGS+FRAME_FP0+SZFPREG(t0)
3448#endif
3449
3450          srl       t1, t0, 20                              # get exponent
3451          and       t1, t1, 0x7FF
3452          and       t2, t0, 0xFFFFF                         # get fraction
3453          srl       t0, t0, 31                              # get sign
3454          bne       t1, DEXP_INF, 1f              # is it a signaling NAN?
3455          and       v0, t2, DSIGNAL_NAN
3456          bne       v0, zero, invalid_d
34571:
3458          j         ra
3459#else
3460          srl       a3, a0, 11 - (PTR_SCALESHIFT-1)         # get FS field (even regs only)
3461          and       a3, a3, 0xF << PTR_SCALESHIFT # mask FS field
3462          PTR_L     a3, get_fs_d_tbl(a3)                    # switch on register number
3463          j         a3
3464
3465          .rdata
3466get_fs_d_tbl:
3467          PTR_WORD get_fs_d_f0
3468          PTR_WORD get_fs_d_f2
3469          PTR_WORD get_fs_d_f4
3470          PTR_WORD get_fs_d_f6
3471          PTR_WORD get_fs_d_f8
3472          PTR_WORD get_fs_d_f10
3473          PTR_WORD get_fs_d_f12
3474          PTR_WORD get_fs_d_f14
3475          PTR_WORD get_fs_d_f16
3476          PTR_WORD get_fs_d_f18
3477          PTR_WORD get_fs_d_f20
3478          PTR_WORD get_fs_d_f22
3479          PTR_WORD get_fs_d_f24
3480          PTR_WORD get_fs_d_f26
3481          PTR_WORD get_fs_d_f28
3482          PTR_WORD get_fs_d_f30
3483          .text
3484
3485get_fs_d_f0:
3486          mfc1      t3, $f0
3487          mfc1      t0, $f1
3488          b         get_fs_d_done
3489get_fs_d_f2:
3490          mfc1      t3, $f2
3491          mfc1      t0, $f3
3492          b         get_fs_d_done
3493get_fs_d_f4:
3494          mfc1      t3, $f4
3495          mfc1      t0, $f5
3496          b         get_fs_d_done
3497get_fs_d_f6:
3498          mfc1      t3, $f6
3499          mfc1      t0, $f7
3500          b         get_fs_d_done
3501get_fs_d_f8:
3502          mfc1      t3, $f8
3503          mfc1      t0, $f9
3504          b         get_fs_d_done
3505get_fs_d_f10:
3506          mfc1      t3, $f10
3507          mfc1      t0, $f11
3508          b         get_fs_d_done
3509get_fs_d_f12:
3510          mfc1      t3, $f12
3511          mfc1      t0, $f13
3512          b         get_fs_d_done
3513get_fs_d_f14:
3514          mfc1      t3, $f14
3515          mfc1      t0, $f15
3516          b         get_fs_d_done
3517get_fs_d_f16:
3518          mfc1      t3, $f16
3519          mfc1      t0, $f17
3520          b         get_fs_d_done
3521get_fs_d_f18:
3522          mfc1      t3, $f18
3523          mfc1      t0, $f19
3524          b         get_fs_d_done
3525get_fs_d_f20:
3526          mfc1      t3, $f20
3527          mfc1      t0, $f21
3528          b         get_fs_d_done
3529get_fs_d_f22:
3530          mfc1      t3, $f22
3531          mfc1      t0, $f23
3532          b         get_fs_d_done
3533get_fs_d_f24:
3534          mfc1      t3, $f24
3535          mfc1      t0, $f25
3536          b         get_fs_d_done
3537get_fs_d_f26:
3538          mfc1      t3, $f26
3539          mfc1      t0, $f27
3540          b         get_fs_d_done
3541get_fs_d_f28:
3542          mfc1      t3, $f28
3543          mfc1      t0, $f29
3544          b         get_fs_d_done
3545get_fs_d_f30:
3546          mfc1      t3, $f30
3547          mfc1      t0, $f31
3548get_fs_d_done:
3549          srl       t1, t0, 20                              # get exponent
3550          and       t1, t1, 0x7FF
3551          and       t2, t0, 0xFFFFF                         # get fraction
3552          srl       t0, t0, 31                              # get sign
3553          bne       t1, DEXP_INF, 1f              # is it a signaling NAN?
3554          and       v0, t2, DSIGNAL_NAN
3555          bne       v0, zero, invalid_d
35561:
3557          j         ra
3558#endif
3559END(get_ft_fs_d)
3560
3561/*----------------------------------------------------------------------------
3562 * get_cmp_s --
3563 *
3564 *        Read (single precision) the FS register (bits 15-11) and
3565 *        the FT register (bits 20-16) and break up into fields.
3566 *        This is an internal routine used by mips_emul_fp only.
3567 *
3568 * Results:
3569 *        t0        contains the sign
3570 *        t1        contains the (biased) exponent
3571 *        t2        contains the fraction
3572 *        ta0       contains the sign
3573 *        ta1       contains the (biased) exponent
3574 *        ta2       contains the fraction
3575 *
3576 *----------------------------------------------------------------------------
3577 */
3578STATIC_LEAF(get_cmp_s)
3579#ifdef FPEMUL
3580          srl       t1, a0, 11 - FPX_SCALESHIFT
3581          PTR_L     ta2, L_PCB(MIPS_CURLWP)                 # get pcb of current lwp
3582          andi      t1, t1, FPX_REGEVENMASK                           # Even regs only
3583          PTR_ADDU t0, ta2, t1
3584
3585          lw        t0, PCB_FPREGS+FRAME_FP0(t0)
3586
3587          srl       t1, t0, 23                              # get exponent
3588          and       t1, t1, 0xFF
3589          and       t2, t0, 0x7FFFFF              # get fraction
3590          srl       t0, t0, 31                              # get sign
3591
3592          srl       ta0, a0, 16 - FPX_SCALESHIFT
3593          andi      ta0, ta0, FPX_REGEVENMASK                         # Even regs only
3594          PTR_ADDU ta2, ta0
3595
3596          lw        ta0, PCB_FPREGS+FRAME_FP0(ta2)
3597
3598          srl       ta1, ta0, 23                            # get exponent
3599          and       ta1, ta1, 0xFF
3600          and       ta2, ta0, 0x7FFFFF            # get fraction
3601          srl       ta0, ta0, 31                            # get sign
3602          j         ra
3603#else
3604          srl       a3, a0, 11 - (PTR_SCALESHIFT-1)         # get FS field (even regs only)
3605          and       a3, a3, 0xF << PTR_SCALESHIFT # mask FS field
3606          PTR_L     a3, cmp_fs_s_tbl(a3)                    # switch on register number
3607          j         a3
3608
3609          .rdata
3610cmp_fs_s_tbl:
3611          PTR_WORD cmp_fs_s_f0
3612          PTR_WORD cmp_fs_s_f2
3613          PTR_WORD cmp_fs_s_f4
3614          PTR_WORD cmp_fs_s_f6
3615          PTR_WORD cmp_fs_s_f8
3616          PTR_WORD cmp_fs_s_f10
3617          PTR_WORD cmp_fs_s_f12
3618          PTR_WORD cmp_fs_s_f14
3619          PTR_WORD cmp_fs_s_f16
3620          PTR_WORD cmp_fs_s_f18
3621          PTR_WORD cmp_fs_s_f20
3622          PTR_WORD cmp_fs_s_f22
3623          PTR_WORD cmp_fs_s_f24
3624          PTR_WORD cmp_fs_s_f26
3625          PTR_WORD cmp_fs_s_f28
3626          PTR_WORD cmp_fs_s_f30
3627          .text
3628
3629cmp_fs_s_f0:
3630          mfc1      t0, $f0
3631          b         cmp_fs_s_done
3632cmp_fs_s_f2:
3633          mfc1      t0, $f2
3634          b         cmp_fs_s_done
3635cmp_fs_s_f4:
3636          mfc1      t0, $f4
3637          b         cmp_fs_s_done
3638cmp_fs_s_f6:
3639          mfc1      t0, $f6
3640          b         cmp_fs_s_done
3641cmp_fs_s_f8:
3642          mfc1      t0, $f8
3643          b         cmp_fs_s_done
3644cmp_fs_s_f10:
3645          mfc1      t0, $f10
3646          b         cmp_fs_s_done
3647cmp_fs_s_f12:
3648          mfc1      t0, $f12
3649          b         cmp_fs_s_done
3650cmp_fs_s_f14:
3651          mfc1      t0, $f14
3652          b         cmp_fs_s_done
3653cmp_fs_s_f16:
3654          mfc1      t0, $f16
3655          b         cmp_fs_s_done
3656cmp_fs_s_f18:
3657          mfc1      t0, $f18
3658          b         cmp_fs_s_done
3659cmp_fs_s_f20:
3660          mfc1      t0, $f20
3661          b         cmp_fs_s_done
3662cmp_fs_s_f22:
3663          mfc1      t0, $f22
3664          b         cmp_fs_s_done
3665cmp_fs_s_f24:
3666          mfc1      t0, $f24
3667          b         cmp_fs_s_done
3668cmp_fs_s_f26:
3669          mfc1      t0, $f26
3670          b         cmp_fs_s_done
3671cmp_fs_s_f28:
3672          mfc1      t0, $f28
3673          b         cmp_fs_s_done
3674cmp_fs_s_f30:
3675          mfc1      t0, $f30
3676cmp_fs_s_done:
3677          srl       t1, t0, 23                              # get exponent
3678          and       t1, t1, 0xFF
3679          and       t2, t0, 0x7FFFFF              # get fraction
3680          srl       t0, t0, 31                              # get sign
3681
3682          srl       a3, a0, 17 - PTR_SCALESHIFT                       # get FT field (even regs only)
3683          and       a3, a3, 0xF << PTR_SCALESHIFT           # mask FT field
3684          PTR_L     a3, cmp_ft_s_tbl(a3)                    # switch on register number
3685          j         a3
3686
3687          .rdata
3688cmp_ft_s_tbl:
3689          PTR_WORD cmp_ft_s_f0
3690          PTR_WORD cmp_ft_s_f2
3691          PTR_WORD cmp_ft_s_f4
3692          PTR_WORD cmp_ft_s_f6
3693          PTR_WORD cmp_ft_s_f8
3694          PTR_WORD cmp_ft_s_f10
3695          PTR_WORD cmp_ft_s_f12
3696          PTR_WORD cmp_ft_s_f14
3697          PTR_WORD cmp_ft_s_f16
3698          PTR_WORD cmp_ft_s_f18
3699          PTR_WORD cmp_ft_s_f20
3700          PTR_WORD cmp_ft_s_f22
3701          PTR_WORD cmp_ft_s_f24
3702          PTR_WORD cmp_ft_s_f26
3703          PTR_WORD cmp_ft_s_f28
3704          PTR_WORD cmp_ft_s_f30
3705          .text
3706
3707cmp_ft_s_f0:
3708          mfc1      ta0, $f0
3709          b         cmp_ft_s_done
3710cmp_ft_s_f2:
3711          mfc1      ta0, $f2
3712          b         cmp_ft_s_done
3713cmp_ft_s_f4:
3714          mfc1      ta0, $f4
3715          b         cmp_ft_s_done
3716cmp_ft_s_f6:
3717          mfc1      ta0, $f6
3718          b         cmp_ft_s_done
3719cmp_ft_s_f8:
3720          mfc1      ta0, $f8
3721          b         cmp_ft_s_done
3722cmp_ft_s_f10:
3723          mfc1      ta0, $f10
3724          b         cmp_ft_s_done
3725cmp_ft_s_f12:
3726          mfc1      ta0, $f12
3727          b         cmp_ft_s_done
3728cmp_ft_s_f14:
3729          mfc1      ta0, $f14
3730          b         cmp_ft_s_done
3731cmp_ft_s_f16:
3732          mfc1      ta0, $f16
3733          b         cmp_ft_s_done
3734cmp_ft_s_f18:
3735          mfc1      ta0, $f18
3736          b         cmp_ft_s_done
3737cmp_ft_s_f20:
3738          mfc1      ta0, $f20
3739          b         cmp_ft_s_done
3740cmp_ft_s_f22:
3741          mfc1      ta0, $f22
3742          b         cmp_ft_s_done
3743cmp_ft_s_f24:
3744          mfc1      ta0, $f24
3745          b         cmp_ft_s_done
3746cmp_ft_s_f26:
3747          mfc1      ta0, $f26
3748          b         cmp_ft_s_done
3749cmp_ft_s_f28:
3750          mfc1      ta0, $f28
3751          b         cmp_ft_s_done
3752cmp_ft_s_f30:
3753          mfc1      ta0, $f30
3754cmp_ft_s_done:
3755          srl       ta1, ta0, 23                            # get exponent
3756          and       ta1, ta1, 0xFF
3757          and       ta2, ta0, 0x7FFFFF            # get fraction
3758          srl       ta0, ta0, 31                            # get sign
3759          j         ra
3760#endif
3761END(get_cmp_s)
3762
3763/*----------------------------------------------------------------------------
3764 * get_cmp_d --
3765 *
3766 *        Read (double precision) the FS register (bits 15-11) and
3767 *        the FT register (bits 20-16) and break up into fields.
3768 *        This is an internal routine used by mips_emul_fp only.
3769 *
3770 * Results:
3771 *        t0        contains the sign
3772 *        t1        contains the (biased) exponent
3773 *        t2        contains the fraction
3774 *        t3        contains the remaining fraction
3775 *        ta0       contains the sign
3776 *        ta1       contains the (biased) exponent
3777 *        ta2       contains the fraction
3778 *        ta3       contains the remaining fraction
3779 *
3780 *----------------------------------------------------------------------------
3781 */
3782STATIC_LEAF(get_cmp_d)
3783#ifdef FPEMUL
3784          srl       t1, a0, 11-FPX_SCALESHIFT
3785          PTR_L     ta2, L_PCB(MIPS_CURLWP)                 # get pcb of current lwp
3786          andi      t1, t1, FPX_REGEVENMASK                           # Even regs only
3787          PTR_ADDU t0, ta2, t1
3788
3789#if defined(__mips_n32) || defined(__mips_n64)
3790          FPX_L     t3, PCB_FPREGS+FRAME_FP0(t0)
3791          dsrl      t0, t3, 32
3792          srl       t3, t3, 0
3793#else
3794          FPX_L     t3, PCB_FPREGS+FRAME_FP0(t0)
3795          FPX_L     t0, PCB_FPREGS+FRAME_FP0+SZFPREG(t0)
3796#endif
3797
3798          srl       t1, t0, 20                              # get exponent
3799          and       t1, t1, 0x7FF
3800          and       t2, t0, 0xFFFFF                         # get fraction
3801          srl       t0, t0, 31                              # get sign
3802
3803          srl       ta0, a0, 16 - FPX_SCALESHIFT
3804          andi      ta0, ta0, FPX_REGEVENMASK               # Even regs only
3805          PTR_ADDU ta2, ta2, ta0
3806
3807#if defined(__mips_n32) || defined(__mips_n64)
3808          FPX_L     ta3, PCB_FPREGS+FRAME_FP0(ta2)
3809          dsrl      ta0, ta3, 32
3810          srl       ta3, ta3, 0
3811#else
3812          lw        ta3, PCB_FPREGS+FRAME_FP0(ta2)
3813          lw        ta0, PCB_FPREGS+FRAME_FP0+SZFPREG(ta2)
3814#endif
3815
3816          srl       ta1, ta0, 20                            # get exponent
3817          and       ta1, ta1, 0x7FF
3818          and       ta2, ta0, 0xFFFFF                       # get fraction
3819          srl       ta0, ta0, 31                            # get sign
3820          j         ra
3821#else
3822          srl       a3, a0, 12 - PTR_SCALESHIFT   # get FS field
3823          and       a3, a3, 0xF << PTR_SCALESHIFT # mask FS field (even regs only)
3824          PTR_L     a3, cmp_fs_d_tbl(a3)                    # switch on register number
3825          j         a3
3826
3827          .rdata
3828cmp_fs_d_tbl:
3829          PTR_WORD cmp_fs_d_f0
3830          PTR_WORD cmp_fs_d_f2
3831          PTR_WORD cmp_fs_d_f4
3832          PTR_WORD cmp_fs_d_f6
3833          PTR_WORD cmp_fs_d_f8
3834          PTR_WORD cmp_fs_d_f10
3835          PTR_WORD cmp_fs_d_f12
3836          PTR_WORD cmp_fs_d_f14
3837          PTR_WORD cmp_fs_d_f16
3838          PTR_WORD cmp_fs_d_f18
3839          PTR_WORD cmp_fs_d_f20
3840          PTR_WORD cmp_fs_d_f22
3841          PTR_WORD cmp_fs_d_f24
3842          PTR_WORD cmp_fs_d_f26
3843          PTR_WORD cmp_fs_d_f28
3844          PTR_WORD cmp_fs_d_f30
3845          .text
3846
3847cmp_fs_d_f0:
3848          mfc1      t3, $f0
3849          mfc1      t0, $f1
3850          b         cmp_fs_d_done
3851cmp_fs_d_f2:
3852          mfc1      t3, $f2
3853          mfc1      t0, $f3
3854          b         cmp_fs_d_done
3855cmp_fs_d_f4:
3856          mfc1      t3, $f4
3857          mfc1      t0, $f5
3858          b         cmp_fs_d_done
3859cmp_fs_d_f6:
3860          mfc1      t3, $f6
3861          mfc1      t0, $f7
3862          b         cmp_fs_d_done
3863cmp_fs_d_f8:
3864          mfc1      t3, $f8
3865          mfc1      t0, $f9
3866          b         cmp_fs_d_done
3867cmp_fs_d_f10:
3868          mfc1      t3, $f10
3869          mfc1      t0, $f11
3870          b         cmp_fs_d_done
3871cmp_fs_d_f12:
3872          mfc1      t3, $f12
3873          mfc1      t0, $f13
3874          b         cmp_fs_d_done
3875cmp_fs_d_f14:
3876          mfc1      t3, $f14
3877          mfc1      t0, $f15
3878          b         cmp_fs_d_done
3879cmp_fs_d_f16:
3880          mfc1      t3, $f16
3881          mfc1      t0, $f17
3882          b         cmp_fs_d_done
3883cmp_fs_d_f18:
3884          mfc1      t3, $f18
3885          mfc1      t0, $f19
3886          b         cmp_fs_d_done
3887cmp_fs_d_f20:
3888          mfc1      t3, $f20
3889          mfc1      t0, $f21
3890          b         cmp_fs_d_done
3891cmp_fs_d_f22:
3892          mfc1      t3, $f22
3893          mfc1      t0, $f23
3894          b         cmp_fs_d_done
3895cmp_fs_d_f24:
3896          mfc1      t3, $f24
3897          mfc1      t0, $f25
3898          b         cmp_fs_d_done
3899cmp_fs_d_f26:
3900          mfc1      t3, $f26
3901          mfc1      t0, $f27
3902          b         cmp_fs_d_done
3903cmp_fs_d_f28:
3904          mfc1      t3, $f28
3905          mfc1      t0, $f29
3906          b         cmp_fs_d_done
3907cmp_fs_d_f30:
3908          mfc1      t3, $f30
3909          mfc1      t0, $f31
3910cmp_fs_d_done:
3911          srl       t1, t0, 20                              # get exponent
3912          and       t1, t1, 0x7FF
3913          and       t2, t0, 0xFFFFF                         # get fraction
3914          srl       t0, t0, 31                              # get sign
3915
3916          srl       a3, a0, 17 - PTR_SCALESHIFT   # get FT field (even regs only)
3917          and       a3, a3, 0xF << PTR_SCALESHIFT # mask FT field
3918          PTR_L     a3, cmp_ft_d_tbl(a3)                    # switch on register number
3919          j         a3
3920
3921          .rdata
3922cmp_ft_d_tbl:
3923          PTR_WORD cmp_ft_d_f0
3924          PTR_WORD cmp_ft_d_f2
3925          PTR_WORD cmp_ft_d_f4
3926          PTR_WORD cmp_ft_d_f6
3927          PTR_WORD cmp_ft_d_f8
3928          PTR_WORD cmp_ft_d_f10
3929          PTR_WORD cmp_ft_d_f12
3930          PTR_WORD cmp_ft_d_f14
3931          PTR_WORD cmp_ft_d_f16
3932          PTR_WORD cmp_ft_d_f18
3933          PTR_WORD cmp_ft_d_f20
3934          PTR_WORD cmp_ft_d_f22
3935          PTR_WORD cmp_ft_d_f24
3936          PTR_WORD cmp_ft_d_f26
3937          PTR_WORD cmp_ft_d_f28
3938          PTR_WORD cmp_ft_d_f30
3939          .text
3940
3941cmp_ft_d_f0:
3942          mfc1      ta3, $f0
3943          mfc1      ta0, $f1
3944          b         cmp_ft_d_done
3945cmp_ft_d_f2:
3946          mfc1      ta3, $f2
3947          mfc1      ta0, $f3
3948          b         cmp_ft_d_done
3949cmp_ft_d_f4:
3950          mfc1      ta3, $f4
3951          mfc1      ta0, $f5
3952          b         cmp_ft_d_done
3953cmp_ft_d_f6:
3954          mfc1      ta3, $f6
3955          mfc1      ta0, $f7
3956          b         cmp_ft_d_done
3957cmp_ft_d_f8:
3958          mfc1      ta3, $f8
3959          mfc1      ta0, $f9
3960          b         cmp_ft_d_done
3961cmp_ft_d_f10:
3962          mfc1      ta3, $f10
3963          mfc1      ta0, $f11
3964          b         cmp_ft_d_done
3965cmp_ft_d_f12:
3966          mfc1      ta3, $f12
3967          mfc1      ta0, $f13
3968          b         cmp_ft_d_done
3969cmp_ft_d_f14:
3970          mfc1      ta3, $f14
3971          mfc1      ta0, $f15
3972          b         cmp_ft_d_done
3973cmp_ft_d_f16:
3974          mfc1      ta3, $f16
3975          mfc1      ta0, $f17
3976          b         cmp_ft_d_done
3977cmp_ft_d_f18:
3978          mfc1      ta3, $f18
3979          mfc1      ta0, $f19
3980          b         cmp_ft_d_done
3981cmp_ft_d_f20:
3982          mfc1      ta3, $f20
3983          mfc1      ta0, $f21
3984          b         cmp_ft_d_done
3985cmp_ft_d_f22:
3986          mfc1      ta3, $f22
3987          mfc1      ta0, $f23
3988          b         cmp_ft_d_done
3989cmp_ft_d_f24:
3990          mfc1      ta3, $f24
3991          mfc1      ta0, $f25
3992          b         cmp_ft_d_done
3993cmp_ft_d_f26:
3994          mfc1      ta3, $f26
3995          mfc1      ta0, $f27
3996          b         cmp_ft_d_done
3997cmp_ft_d_f28:
3998          mfc1      ta3, $f28
3999          mfc1      ta0, $f29
4000          b         cmp_ft_d_done
4001cmp_ft_d_f30:
4002          mfc1      ta3, $f30
4003          mfc1      ta0, $f31
4004cmp_ft_d_done:
4005          srl       ta1, ta0, 20                            # get exponent
4006          and       ta1, ta1, 0x7FF
4007          and       ta2, ta0, 0xFFFFF                       # get fraction
4008          srl       ta0, ta0, 31                            # get sign
4009          j         ra
4010#endif
4011END(get_cmp_d)
4012
4013/*----------------------------------------------------------------------------
4014 * set_fd_s --
4015 *
4016 *        Write (single precision) the FD register (bits 10-6).
4017 *        This is an internal routine used by mips_emul_fp only.
4018 *
4019 * Arguments:
4020 *        a0        contains the FP instruction
4021 *        t0        contains the sign
4022 *        t1        contains the (biased) exponent
4023 *        t2        contains the fraction
4024 *
4025 * set_fd_word --
4026 *
4027 *        Write (integer) the FD register (bits 10-6).
4028 *        This is an internal routine used by mips_emul_fp only.
4029 *
4030 * Arguments:
4031 *        a0        contains the FP instruction
4032 *        t2        contains the integer
4033 *
4034 *----------------------------------------------------------------------------
4035 */
4036STATIC_LEAF(set_fd_s)
4037          sll       t0, t0, 31                              # position sign
4038          sll       t1, t1, 23                              # position exponent
4039          or        t2, t2, t0
4040          or        t2, t2, t1
4041STATIC_XLEAF(set_fd_word)
4042#ifdef FPEMUL
4043          srl       t1, a0, 6 - FPX_SCALESHIFT
4044          PTR_L     t0, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
4045          andi      t1, t1, FPX_REGEVENMASK                 # Even regs only
4046          PTR_ADDU t0, t0, t1
4047
4048          FPX_S     t2, PCB_FPREGS+FRAME_FP0(t0)
4049          j         ra
4050#else
4051          srl       a3, a0, 6 + 1 - PTR_SCALESHIFT          # get FD field (even regs only)
4052          and       a3, a3, 0xF << PTR_SCALESHIFT # mask FT field
4053          PTR_L     a3, set_fd_s_tbl(a3)                    # switch on register number
4054          j         a3
4055
4056          .rdata
4057set_fd_s_tbl:
4058          PTR_WORD set_fd_s_f0
4059          PTR_WORD set_fd_s_f2
4060          PTR_WORD set_fd_s_f4
4061          PTR_WORD set_fd_s_f6
4062          PTR_WORD set_fd_s_f8
4063          PTR_WORD set_fd_s_f10
4064          PTR_WORD set_fd_s_f12
4065          PTR_WORD set_fd_s_f14
4066          PTR_WORD set_fd_s_f16
4067          PTR_WORD set_fd_s_f18
4068          PTR_WORD set_fd_s_f20
4069          PTR_WORD set_fd_s_f22
4070          PTR_WORD set_fd_s_f24
4071          PTR_WORD set_fd_s_f26
4072          PTR_WORD set_fd_s_f28
4073          PTR_WORD set_fd_s_f30
4074          .text
4075
4076set_fd_s_f0:
4077          mtc1      t2, $f0
4078          j         ra
4079set_fd_s_f2:
4080          mtc1      t2, $f2
4081          j         ra
4082set_fd_s_f4:
4083          mtc1      t2, $f4
4084          j         ra
4085set_fd_s_f6:
4086          mtc1      t2, $f6
4087          j         ra
4088set_fd_s_f8:
4089          mtc1      t2, $f8
4090          j         ra
4091set_fd_s_f10:
4092          mtc1      t2, $f10
4093          j         ra
4094set_fd_s_f12:
4095          mtc1      t2, $f12
4096          j         ra
4097set_fd_s_f14:
4098          mtc1      t2, $f14
4099          j         ra
4100set_fd_s_f16:
4101          mtc1      t2, $f16
4102          j         ra
4103set_fd_s_f18:
4104          mtc1      t2, $f18
4105          j         ra
4106set_fd_s_f20:
4107          mtc1      t2, $f20
4108          j         ra
4109set_fd_s_f22:
4110          mtc1      t2, $f22
4111          j         ra
4112set_fd_s_f24:
4113          mtc1      t2, $f24
4114          j         ra
4115set_fd_s_f26:
4116          mtc1      t2, $f26
4117          j         ra
4118set_fd_s_f28:
4119          mtc1      t2, $f28
4120          j         ra
4121set_fd_s_f30:
4122          mtc1      t2, $f30
4123          j         ra
4124#endif
4125END(set_fd_s)
4126
4127/*----------------------------------------------------------------------------
4128 * set_fd_d --
4129 *
4130 *        Write (double precision) the FT register (bits 10-6).
4131 *        This is an internal routine used by mips_emul_fp only.
4132 *
4133 * Arguments:
4134 *        a0        contains the FP instruction
4135 *        t0        contains the sign
4136 *        t1        contains the (biased) exponent
4137 *        t2        contains the fraction
4138 *        t3        contains the remaining fraction
4139 *
4140 *----------------------------------------------------------------------------
4141 */
4142STATIC_LEAF(set_fd_d)
4143#ifdef FPEMUL
4144          sll       t0, t0, 31                              # set sign
4145          sll       t1, t1, 20                              # set exponent
4146          or        t0, t0, t1
4147          or        t0, t0, t2                              # set fraction
4148
4149          srl       t1, a0, 6-FPX_SCALESHIFT
4150          PTR_L     t2, L_PCB(MIPS_CURLWP)                  # get pcb of current lwp
4151          andi      t1, t1, FPX_REGEVENMASK
4152          PTR_ADDU t2, t2, t1
4153
4154#if defined(__mips_n32) || defined(__mips_n64)
4155          dsll      t0, t0, 32
4156          or        t0, t0, t3
4157          FPX_S     t0, PCB_FPREGS+FRAME_FP0(t2)
4158#else
4159          FPX_S     t3, PCB_FPREGS+FRAME_FP0(t2)
4160          FPX_S     t0, PCB_FPREGS+FRAME_FP0+4(t2)
4161#endif
4162          j         ra
4163#else
4164          sll       t0, t0, 31                              # set sign
4165          sll       t1, t1, 20                              # set exponent
4166          or        t0, t0, t1
4167          or        t0, t0, t2                              # set fraction
4168          srl       a3, a0, 7 - PTR_SCALESHIFT    # get FD field (even regs only)
4169          and       a3, a3, 0xF << PTR_SCALESHIFT # mask FD field
4170          PTR_L     a3, set_fd_d_tbl(a3)                    # switch on register number
4171          j         a3
4172
4173          .rdata
4174set_fd_d_tbl:
4175          PTR_WORD set_fd_d_f0
4176          PTR_WORD set_fd_d_f2
4177          PTR_WORD set_fd_d_f4
4178          PTR_WORD set_fd_d_f6
4179          PTR_WORD set_fd_d_f8
4180          PTR_WORD set_fd_d_f10
4181          PTR_WORD set_fd_d_f12
4182          PTR_WORD set_fd_d_f14
4183          PTR_WORD set_fd_d_f16
4184          PTR_WORD set_fd_d_f18
4185          PTR_WORD set_fd_d_f20
4186          PTR_WORD set_fd_d_f22
4187          PTR_WORD set_fd_d_f24
4188          PTR_WORD set_fd_d_f26
4189          PTR_WORD set_fd_d_f28
4190          PTR_WORD set_fd_d_f30
4191          .text
4192
4193set_fd_d_f0:
4194          mtc1      t3, $f0
4195          mtc1      t0, $f1
4196          j         ra
4197set_fd_d_f2:
4198          mtc1      t3, $f2
4199          mtc1      t0, $f3
4200          j         ra
4201set_fd_d_f4:
4202          mtc1      t3, $f4
4203          mtc1      t0, $f5
4204          j         ra
4205set_fd_d_f6:
4206          mtc1      t3, $f6
4207          mtc1      t0, $f7
4208          j         ra
4209set_fd_d_f8:
4210          mtc1      t3, $f8
4211          mtc1      t0, $f9
4212          j         ra
4213set_fd_d_f10:
4214          mtc1      t3, $f10
4215          mtc1      t0, $f11
4216          j         ra
4217set_fd_d_f12:
4218          mtc1      t3, $f12
4219          mtc1      t0, $f13
4220          j         ra
4221set_fd_d_f14:
4222          mtc1      t3, $f14
4223          mtc1      t0, $f15
4224          j         ra
4225set_fd_d_f16:
4226          mtc1      t3, $f16
4227          mtc1      t0, $f17
4228          j         ra
4229set_fd_d_f18:
4230          mtc1      t3, $f18
4231          mtc1      t0, $f19
4232          j         ra
4233set_fd_d_f20:
4234          mtc1      t3, $f20
4235          mtc1      t0, $f21
4236          j         ra
4237set_fd_d_f22:
4238          mtc1      t3, $f22
4239          mtc1      t0, $f23
4240          j         ra
4241set_fd_d_f24:
4242          mtc1      t3, $f24
4243          mtc1      t0, $f25
4244          j         ra
4245set_fd_d_f26:
4246          mtc1      t3, $f26
4247          mtc1      t0, $f27
4248          j         ra
4249set_fd_d_f28:
4250          mtc1      t3, $f28
4251          mtc1      t0, $f29
4252          j         ra
4253set_fd_d_f30:
4254          mtc1      t3, $f30
4255          mtc1      t0, $f31
4256          j         ra
4257#endif
4258END(set_fd_d)
4259
4260/*----------------------------------------------------------------------------
4261 * renorm_fs_s --
4262 *
4263 * Results:
4264 *        t1        unbiased exponent
4265 *        t2        normalized fraction
4266 *
4267 *----------------------------------------------------------------------------
4268 */
4269STATIC_LEAF(renorm_fs_s)
4270/*
4271 * Find out how many leading zero bits are in t2 and put in at.
4272 */
4273#if __mips == 32 || __mips == 64
4274          clz       v1, t2
4275#else
4276          .set      noat
4277          move      v0, t2
4278          move      v1, zero
4279          srl       AT, v0, 16
4280          bne       AT, zero, 1f
4281          addu      v1, 16
4282          sll       v0, 16
42831:
4284          srl       AT, v0, 24
4285          bne       AT, zero, 1f
4286          addu      v1, 8
4287          sll       v0, 8
42881:
4289          srl       AT, v0, 28
4290          bne       AT, zero, 1f
4291          addu      v1, 4
4292          sll       v0, 4
42931:
4294          srl       AT, v0, 30
4295          bne       AT, zero, 1f
4296          addu      v1, 2
4297          sll       v0, 2
42981:
4299          srl       AT, v0, 31
4300          bne       AT, zero, 1f
4301          addu      v1, 1
43021:
4303          .set      at
4304#endif /* __mips == 32 || __mips == 64 */
4305/*
4306 * Now shift t2 the correct number of bits.
4307 */
4308          subu      v1, v1, SLEAD_ZEROS # dont count normal leading zeros
4309          li        t1, SEXP_MIN
4310          subu      t1, t1, v1                    # adjust exponent
4311          sll       t2, t2, v1
4312          j         ra
4313END(renorm_fs_s)
4314
4315/*----------------------------------------------------------------------------
4316 * renorm_fs_d --
4317 *
4318 * Results:
4319 *        t1        unbiased exponent
4320 *        t2,t3     normalized fraction
4321 *
4322 *----------------------------------------------------------------------------
4323 */
4324STATIC_LEAF(renorm_fs_d)
4325/*
4326 * Find out how many leading zero bits are in t2,t3 and put in v1.
4327 */
4328#if __mips == 32 || __mips == 64
4329#ifdef __mips_o32
4330          bne       ta2, zero, 1f
4331          clz       v1, ta3
4332          addu      v1, 32
4333          b         2f
43341:
4335          clz       v1, ta2
43362:
4337#elif __mips_isa_rev == 2
4338          move      v0, ta3
4339          dins      v0, ta2, 32, 32
4340          dclz      v1, v0
4341#else
4342          dsll      v0, ta3, 32
4343          dsrl      v0, v0, 32
4344          dsll      v1, ta2, 32
4345          or        v0, v1
4346          dclz      v1, v0
4347#endif /* __mips_o32 */
4348#else
4349          .set      noat
4350          move      v0, t2
4351          move      v1, zero
4352          bne       t2, zero, 1f
4353          move      v0, t3
4354          addu      v1, 32
43551:
4356          srl       AT, v0, 16
4357          bne       AT, zero, 1f
4358          addu      v1, 16
4359          sll       v0, 16
43601:
4361          srl       AT, v0, 24
4362          bne       AT, zero, 1f
4363          addu      v1, 8
4364          sll       v0, 8
43651:
4366          srl       AT, v0, 28
4367          bne       AT, zero, 1f
4368          addu      v1, 4
4369          sll       v0, 4
43701:
4371          srl       AT, v0, 30
4372          bne       AT, zero, 1f
4373          addu      v1, 2
4374          sll       v0, 2
43751:
4376          srl       AT, v0, 31
4377          bne       AT, zero, 1f
4378          addu      v1, 1
43791:
4380          .set      at
4381#endif /* __mips == 32 || __mips == 64 */
4382/*
4383 * Now shift t2,t3 the correct number of bits.
4384 */
4385          subu      v1, v1, DLEAD_ZEROS # dont count normal leading zeros
4386          li        t1, DEXP_MIN
4387          subu      t1, t1, v1                    # adjust exponent
4388#ifdef __mips_o32
4389          li        v0, 32
4390          blt       v1, v0, 1f
4391          subu      v1, v1, v0                    # shift fraction left >= 32 bits
4392          sll       t2, t3, v1
4393          move      t3, zero
4394          j         ra
43951:
4396          subu      v0, v0, v1                    # shift fraction left < 32 bits
4397          sll       t2, t2, v1
4398          srl       v0, t3, v0
4399          or        t2, t2, v0
4400          sll       t3, t3, v1
4401          j         ra
4402#else
4403          dsll      v0, v0, t1
4404          dsrl      t2, v0, 32                    # MSW
4405          sll       t3, v0, 0           # LSW
4406          j         ra
4407#endif
4408END(renorm_fs_d)
4409
4410/*----------------------------------------------------------------------------
4411 * renorm_ft_s --
4412 *
4413 * Results:
4414 *        ta1       unbiased exponent
4415 *        ta2       normalized fraction
4416 *
4417 *----------------------------------------------------------------------------
4418 */
4419STATIC_LEAF(renorm_ft_s)
4420/*
4421 * Find out how many leading zero bits are in ta2 and put in v1.
4422 */
4423#if __mips == 32 || __mips == 64
4424          clz       v1, ta2
4425#else
4426          .set      noat
4427
4428          move      v0, ta2
4429          move      v1, zero
4430          srl       AT, v0, 16
4431          bne       AT, zero, 1f
4432          addu      v1, 16
4433          sll       v0, 16
44341:
4435          srl       AT, v0, 24
4436          bne       AT, zero, 1f
4437          addu      v1, 8
4438          sll       v0, 8
44391:
4440          srl       AT, v0, 28
4441          bne       AT, zero, 1f
4442          addu      v1, 4
4443          sll       v0, 4
44441:
4445          srl       AT, v0, 30
4446          bne       AT, zero, 1f
4447          addu      v1, 2
4448          sll       v0, 2
44491:
4450          srl       AT, v0, 31
4451          bne       AT, zero, 1f
4452          addu      v1, 1
44531:
4454          .set      at
4455#endif /* __mips == 32 || __mips == 64 */
4456/*
4457 * Now shift ta2 the correct number of bits.
4458 */
4459          subu      v1, v1, SLEAD_ZEROS # dont count normal leading zeros
4460          li        ta1, SEXP_MIN
4461          subu      ta1, ta1, v1                  # adjust exponent
4462          sll       ta2, ta2, v1
4463          j         ra
4464END(renorm_ft_s)
4465
4466/*----------------------------------------------------------------------------
4467 * renorm_ft_d --
4468 *
4469 * Results:
4470 *        ta1       unbiased exponent
4471 *        ta2,ta3   normalized fraction
4472 *
4473 *----------------------------------------------------------------------------
4474 */
4475STATIC_LEAF(renorm_ft_d)
4476/*
4477 * Find out how many leading zero bits are in ta2,ta3 and put in at.
4478 */
4479#if __mips == 32 || __mips == 64
4480#ifdef __mips_o32
4481          bne       ta2, zero, 1f
4482          clz       v1, ta3
4483          addu      v1, 32
4484          b         2f
44851:
4486          clz       v1, ta2
44872:
4488#elif __mips_isa_rev == 2
4489          move      v0, ta3
4490          dins      v0, ta2, 32, 32
4491          dclz      v1, v0
4492#else
4493          dsll      v0, ta3, 32
4494          dsrl      v0, v0, 32
4495          dsll      v1, ta2, 32
4496          or        v0, v1
4497          dclz      v1, v0
4498#endif /* __mips_o32 */
4499#else
4500          .set      noat
4501          move      v0, ta2
4502          move      v1, zero
4503          bne       ta2, zero, 1f
4504          move      v0, ta3
4505          addu      v1, 32
45061:
4507          srl       AT, v0, 16
4508          bne       AT, zero, 1f
4509          addu      v1, 16
4510          sll       v0, 16
45111:
4512          srl       AT, v0, 24
4513          bne       AT, zero, 1f
4514          addu      v1, 8
4515          sll       v0, 8
45161:
4517          srl       AT, v0, 28
4518          bne       AT, zero, 1f
4519          addu      v1, 4
4520          sll       v0, 4
45211:
4522          srl       AT, v0, 30
4523          bne       AT, zero, 1f
4524          addu      v1, 2
4525          sll       v0, 2
45261:
4527          srl       AT, v0, 31
4528          bne       AT, zero, 1f
4529          addu      v1, 1
45301:
4531          .set      at
4532#endif /* __mips == 32 || __mips == 64 */
4533/*
4534 * Now shift ta2,ta3 the correct number of bits.
4535 */
4536          subu      v1, v1, DLEAD_ZEROS # dont count normal leading zeros
4537          li        ta1, DEXP_MIN
4538          subu      ta1, ta1, v1                  # adjust exponent
4539#ifdef __mips_o32
4540          li        v0, 32
4541          blt       v1, v0, 1f
4542          subu      v1, v1, v0                    # shift fraction left >= 32 bits
4543          sll       ta2, ta3, v1
4544          move      ta3, zero
4545          j         ra
45461:
4547          subu      v0, v0, v1                    # shift fraction left < 32 bits
4548          sll       ta2, ta2, v1
4549          srl       v0, ta3, v0
4550          or        ta2, ta2, v0
4551          sll       ta3, ta3, v1
4552          j         ra
4553#else
4554          dsll      v0, v0, t1
4555          dsrl      ta2, v0, 32
4556          sll       ta3, v0, 0
4557          j         ra
4558#endif    /* __mips_o32 */
4559END(renorm_ft_d)
4560
4561/*
4562 * Send SIGILL, SIGFPE.
4563 * Args are same as mips_emul_fp.
4564 */
4565STATIC_LEAF(fpemul_sigill)
4566          li        t0, 0xFFFFFF00
4567          and       a2, a2, t0
4568          ori       a2, a2, T_RES_INST << MIPS_CR_EXC_CODE_SHIFT
4569          REG_PROLOGUE
4570          REG_S     a2, TF_REG_CAUSE(a1)
4571          REG_EPILOGUE
4572
4573          move      a1, a0                                  # code = instruction
4574          move      a0, MIPS_CURLWP                         # get current lwp
4575          j         _C_LABEL(mips_fpuillinst)
4576END(fpemul_sigill)
4577
4578STATIC_LEAF(fpemul_sigfpe)
4579          li        t0, 0xFFFFFF00
4580          and       a2, a2, t0
4581          ori       a2, a2, T_FPE << MIPS_CR_EXC_CODE_SHIFT
4582          REG_PROLOGUE
4583          REG_S     a2, TF_REG_CAUSE(a1)
4584          REG_EPILOGUE
4585
4586          move      a1, a3                                  # fpustat
4587          move      a0, MIPS_CURLWP                         # get current lwp
4588          j         _C_LABEL(mips_fpuexcept)
4589END(fpemul_sigfpe)
4590
4591#ifdef FPEMUL
4592STATIC_LEAF(mips_emul_sigfpe)
4593          li        t0, 0xFFFFFF00
4594          and       a2, a2, t0
4595          ori       a2, a2, T_OVFLOW << MIPS_CR_EXC_CODE_SHIFT
4596          REG_PROLOGUE
4597          REG_S     a2, TF_REG_CAUSE(a1)
4598          REG_EPILOGUE
4599
4600          move      a1, a3                                  # fpustat
4601          move      a0, MIPS_CURLWP                         # get current lwp
4602          j         _C_LABEL(mips_fpuexcept)
4603END(mips_emul_sigfpe)
4604#endif
4605