195604Sjake/*-
295604Sjake * Copyright (c) 2002 Jake Burkholder.
395604Sjake * All rights reserved.
495604Sjake *
595604Sjake * Redistribution and use in source and binary forms, with or without
695604Sjake * modification, are permitted provided that the following conditions
795604Sjake * are met:
895604Sjake * 1. Redistributions of source code must retain the above copyright
995604Sjake *    notice, this list of conditions and the following disclaimer.
1095604Sjake * 2. Redistributions in binary form must reproduce the above copyright
1195604Sjake *    notice, this list of conditions and the following disclaimer in the
1295604Sjake *    documentation and/or other materials provided with the distribution.
1395604Sjake *
1495604Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1595604Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1695604Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1795604Sjake * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1895604Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1995604Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2095604Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2195604Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2295604Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2395604Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2495604Sjake * SUCH DAMAGE.
2595604Sjake */
2695604Sjake
2795604Sjake#include <sys/cdefs.h>
2895604Sjake__FBSDID("$FreeBSD$");
2995604Sjake
3095604Sjake#include <sys/types.h>
3195604Sjake#include <machine/fsr.h>
3295604Sjake
3395604Sjake#include "fpu_emu.h"
3495604Sjake#include "fpu_extern.h"
3595604Sjake
3695604Sjake#define	_QP_OP(op) \
3795604Sjakevoid _Qp_ ## op(u_int *c, u_int *a, u_int *b); \
3895604Sjakevoid \
3995604Sjake_Qp_ ## op(u_int *c, u_int *a, u_int *b) \
4095604Sjake{ \
4195604Sjake	struct fpemu fe; \
4295604Sjake	struct fpn *r; \
4395604Sjake	__asm __volatile("stx %%fsr, %0" : "=m" (fe.fe_fsr) :); \
44178138Sdas	fe.fe_cx = 0; \
4595604Sjake	fe.fe_f1.fp_sign = a[0] >> 31; \
4695604Sjake	fe.fe_f1.fp_sticky = 0; \
4795604Sjake	fe.fe_f1.fp_class = __fpu_qtof(&fe.fe_f1, a[0], a[1], a[2], a[3]); \
4895604Sjake	fe.fe_f2.fp_sign = b[0] >> 31; \
4995604Sjake	fe.fe_f2.fp_sticky = 0; \
5095604Sjake	fe.fe_f2.fp_class = __fpu_qtof(&fe.fe_f2, b[0], b[1], b[2], b[3]); \
5195604Sjake	r = __fpu_ ## op(&fe); \
5295604Sjake	c[0] = __fpu_ftoq(&fe, r, c); \
53178138Sdas	fe.fe_fsr |= fe.fe_cx << FSR_AEXC_SHIFT; \
54178138Sdas	__asm __volatile("ldx %0, %%fsr" : : "m" (fe.fe_fsr)); \
5595604Sjake}
5695604Sjake
57146673Sstefanf#define	_QP_TTOQ(qname, fname, ntype, signpos, atype, ...) \
5895604Sjakevoid _Qp_ ## qname ## toq(u_int *c, ntype n); \
5995604Sjakevoid \
6095604Sjake_Qp_ ## qname ## toq(u_int *c, ntype n) \
6195604Sjake{ \
6295604Sjake	struct fpemu fe; \
63127091Sdes	union { atype a[2]; ntype n; } u = { .n = n }; \
6495604Sjake	__asm __volatile("stx %%fsr, %0" : "=m" (fe.fe_fsr) :); \
65178138Sdas	fe.fe_cx = 0; \
66146673Sstefanf	fe.fe_f1.fp_sign = (signpos >= 0) ? u.a[0] >> signpos : 0; \
6795604Sjake	fe.fe_f1.fp_sticky = 0; \
6895604Sjake	fe.fe_f1.fp_class = __fpu_ ## fname ## tof(&fe.fe_f1, __VA_ARGS__); \
6995604Sjake	c[0] = __fpu_ftoq(&fe, &fe.fe_f1, c); \
70178138Sdas	fe.fe_fsr |= fe.fe_cx << FSR_AEXC_SHIFT; \
71178138Sdas	__asm __volatile("ldx %0, %%fsr" : : "m" (fe.fe_fsr)); \
7295604Sjake}
7395604Sjake
7495604Sjake#define	_QP_QTOT(qname, fname, type, ...) \
7595604Sjaketype _Qp_qto ## qname(u_int *c); \
7695604Sjaketype \
7795604Sjake_Qp_qto ## qname(u_int *c) \
7895604Sjake{ \
7995604Sjake	struct fpemu fe; \
80127091Sdes	union { u_int a; type n; } u; \
8195604Sjake	__asm __volatile("stx %%fsr, %0" : "=m" (fe.fe_fsr) :); \
82178138Sdas	fe.fe_cx = 0; \
8395604Sjake	fe.fe_f1.fp_sign = c[0] >> 31; \
8495604Sjake	fe.fe_f1.fp_sticky = 0; \
8595604Sjake	fe.fe_f1.fp_class = __fpu_qtof(&fe.fe_f1, c[0], c[1], c[2], c[3]); \
86127091Sdes	u.a = __fpu_fto ## fname(&fe, &fe.fe_f1, ## __VA_ARGS__); \
87178138Sdas	fe.fe_fsr |= fe.fe_cx << FSR_AEXC_SHIFT; \
88178138Sdas	__asm __volatile("ldx %0, %%fsr" : : "m" (fe.fe_fsr)); \
89127091Sdes	return (u.n); \
9095604Sjake}
9195604Sjake
9295604Sjake#define	FCC_EQ(fcc)	((fcc) == FSR_CC_EQ)
9395604Sjake#define	FCC_GE(fcc)	((fcc) == FSR_CC_EQ || (fcc) == FSR_CC_GT)
9495604Sjake#define	FCC_GT(fcc)	((fcc) == FSR_CC_GT)
9595604Sjake#define	FCC_LE(fcc)	((fcc) == FSR_CC_EQ || (fcc) == FSR_CC_LT)
9695604Sjake#define	FCC_LT(fcc)	((fcc) == FSR_CC_LT)
9795604Sjake#define	FCC_NE(fcc)	((fcc) != FSR_CC_EQ)
98147519Sstefanf#define	FCC_ID(fcc)	(fcc)
9995604Sjake
10095604Sjake#define	_QP_CMP(name, cmpe, test) \
101147519Sstefanfint _Qp_ ## name(u_int *a, u_int *b) ; \
10295604Sjakeint \
103147519Sstefanf_Qp_ ## name(u_int *a, u_int *b) \
10495604Sjake{ \
10595604Sjake	struct fpemu fe; \
10695604Sjake	__asm __volatile("stx %%fsr, %0" : "=m" (fe.fe_fsr) :); \
107178138Sdas	fe.fe_cx = 0; \
10895604Sjake	fe.fe_f1.fp_sign = a[0] >> 31; \
10995604Sjake	fe.fe_f1.fp_sticky = 0; \
11095604Sjake	fe.fe_f1.fp_class = __fpu_qtof(&fe.fe_f1, a[0], a[1], a[2], a[3]); \
11195604Sjake	fe.fe_f2.fp_sign = b[0] >> 31; \
11295604Sjake	fe.fe_f2.fp_sticky = 0; \
11395604Sjake	fe.fe_f2.fp_class = __fpu_qtof(&fe.fe_f2, b[0], b[1], b[2], b[3]); \
11495604Sjake	__fpu_compare(&fe, cmpe, 0); \
115178138Sdas	fe.fe_fsr |= fe.fe_cx << FSR_AEXC_SHIFT; \
116178138Sdas	__asm __volatile("ldx %0, %%fsr" : : "m" (fe.fe_fsr)); \
11795604Sjake	return (test(FSR_GET_FCC0(fe.fe_fsr))); \
11895604Sjake}
11995604Sjake
12097823Sjakevoid _Qp_sqrt(u_int *c, u_int *a);
12197823Sjakevoid
12297823Sjake_Qp_sqrt(u_int *c, u_int *a)
12397823Sjake{
12497823Sjake	struct fpemu fe;
12597823Sjake	struct fpn *r;
12697823Sjake	__asm __volatile("stx %%fsr, %0" : "=m" (fe.fe_fsr) :);
127178138Sdas	fe.fe_cx = 0;
12897823Sjake	fe.fe_f1.fp_sign = a[0] >> 31;
12997823Sjake	fe.fe_f1.fp_sticky = 0;
13097823Sjake	fe.fe_f1.fp_class = __fpu_qtof(&fe.fe_f1, a[0], a[1], a[2], a[3]);
13197823Sjake	r = __fpu_sqrt(&fe);
13297823Sjake	c[0] = __fpu_ftoq(&fe, r, c);
133178138Sdas	fe.fe_fsr |= fe.fe_cx << FSR_AEXC_SHIFT;
134178138Sdas	__asm __volatile("ldx %0, %%fsr" : : "m" (fe.fe_fsr));
13597823Sjake}
13697823Sjake
13795604Sjake_QP_OP(add)
13895604Sjake_QP_OP(div)
13995604Sjake_QP_OP(mul)
14095604Sjake_QP_OP(sub)
14195604Sjake
142146673Sstefanf_QP_TTOQ(d,	d,	double,	31, u_int,  u.a[0], u.a[1])
143146673Sstefanf_QP_TTOQ(i,	i,	int,	31, u_int,  u.a[0])
144146673Sstefanf_QP_TTOQ(s,	s,	float,	31, u_int,  u.a[0])
145146673Sstefanf_QP_TTOQ(x,	x,	long,	63, u_long, u.a[0])
146146673Sstefanf_QP_TTOQ(ui,	i,	u_int,	-1, u_int,  u.a[0])
147146673Sstefanf_QP_TTOQ(ux,	x,	u_long,	-1, u_long, u.a[0])
14895604Sjake
149127091Sdes_QP_QTOT(d,	d,	double,	&u.a)
150102831Sjake_QP_QTOT(i,	i,	int)
151102831Sjake_QP_QTOT(s,	s,	float)
152127091Sdes_QP_QTOT(x,	x,	long,	&u.a)
153102831Sjake_QP_QTOT(ui,	i,	u_int)
154127091Sdes_QP_QTOT(ux,	x,	u_long,	&u.a)
15595604Sjake
156147519Sstefanf_QP_CMP(feq,	0,	FCC_EQ)
157157791Smarius_QP_CMP(fge,	1,	FCC_GE)
158157791Smarius_QP_CMP(fgt,	1,	FCC_GT)
159157791Smarius_QP_CMP(fle,	1,	FCC_LE)
160157791Smarius_QP_CMP(flt,	1,	FCC_LT)
161147519Sstefanf_QP_CMP(fne,	0, 	FCC_NE)
162147519Sstefanf_QP_CMP(cmp,	0, 	FCC_ID)
163147519Sstefanf_QP_CMP(cmpe,	1, 	FCC_ID)
164