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