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