Module Name:    src
Committed By:   tsutsui
Date:           Sat Oct 15 15:14:30 UTC 2011

Modified Files:
        src/sys/arch/m68k/fpe: fpu_emulate.c fpu_emulate.h fpu_hyperb.c
            fpu_trig.c

Log Message:
Add hyperboric and trigonometric functions to m68k FPE, written by isaki@.
With these emulations (~4KB text) xeyes on XM6i works better.
Discussed with isaki@ at OSC 2011 Hiroshima.


To generate a diff of this commit:
cvs rdiff -u -r1.35 -r1.36 src/sys/arch/m68k/fpe/fpu_emulate.c
cvs rdiff -u -r1.17 -r1.18 src/sys/arch/m68k/fpe/fpu_emulate.h
cvs rdiff -u -r1.5 -r1.6 src/sys/arch/m68k/fpe/fpu_hyperb.c \
    src/sys/arch/m68k/fpe/fpu_trig.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/m68k/fpe/fpu_emulate.c
diff -u src/sys/arch/m68k/fpe/fpu_emulate.c:1.35 src/sys/arch/m68k/fpe/fpu_emulate.c:1.36
--- src/sys/arch/m68k/fpe/fpu_emulate.c:1.35	Mon Jul 18 14:11:27 2011
+++ src/sys/arch/m68k/fpe/fpu_emulate.c	Sat Oct 15 15:14:29 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu_emulate.c,v 1.35 2011/07/18 14:11:27 isaki Exp $	*/
+/*	$NetBSD: fpu_emulate.c,v 1.36 2011/10/15 15:14:29 tsutsui Exp $	*/
 
 /*
  * Copyright (c) 1995 Gordon W. Ross
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu_emulate.c,v 1.35 2011/07/18 14:11:27 isaki Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu_emulate.c,v 1.36 2011/10/15 15:14:29 tsutsui Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -65,7 +65,6 @@ static int fpu_emul_arith(struct fpemu *
 static int fpu_emul_type1(struct fpemu *, struct instruction *);
 static int fpu_emul_brcc(struct fpemu *, struct instruction *);
 static int test_cc(struct fpemu *, int);
-static struct fpn *fpu_cmp(struct fpemu *);
 
 #ifdef DEBUG_FPE
 #define DUMP_INSN(insn)							\
@@ -494,7 +493,7 @@ fpu_emul_fmovm(struct fpemu *fe, struct 
 	return sig;
 }
 
-static struct fpn *
+struct fpn *
 fpu_cmp(struct fpemu *fe)
 {
 	struct fpn *x = &fe->fe_f1, *y = &fe->fe_f2;

Index: src/sys/arch/m68k/fpe/fpu_emulate.h
diff -u src/sys/arch/m68k/fpe/fpu_emulate.h:1.17 src/sys/arch/m68k/fpe/fpu_emulate.h:1.18
--- src/sys/arch/m68k/fpe/fpu_emulate.h:1.17	Sun Oct  9 01:34:19 2011
+++ src/sys/arch/m68k/fpe/fpu_emulate.h	Sat Oct 15 15:14:30 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu_emulate.h,v 1.17 2011/10/09 01:34:19 tsutsui Exp $	*/
+/*	$NetBSD: fpu_emulate.h,v 1.18 2011/10/15 15:14:30 tsutsui Exp $	*/
 
 /*
  * Copyright (c) 1995 Gordon Ross
@@ -244,6 +244,9 @@ int fpu_emul_fscale(struct fpemu *fe, st
 #include "fpu_arith_proto.h"
 
 int fpu_emulate(struct frame *frame, struct fpframe *fpf, ksiginfo_t *ksi);
+struct fpn *fpu_cmp(struct fpemu *);
+
+struct fpn *fpu_sincos_taylor(struct fpemu *, struct fpn *, u_int, int);
 
 /*
  * "helper" functions

Index: src/sys/arch/m68k/fpe/fpu_hyperb.c
diff -u src/sys/arch/m68k/fpe/fpu_hyperb.c:1.5 src/sys/arch/m68k/fpe/fpu_hyperb.c:1.6
--- src/sys/arch/m68k/fpe/fpu_hyperb.c:1.5	Mon Jul 18 07:44:30 2011
+++ src/sys/arch/m68k/fpe/fpu_hyperb.c	Sat Oct 15 15:14:30 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu_hyperb.c,v 1.5 2011/07/18 07:44:30 isaki Exp $	*/
+/*	$NetBSD: fpu_hyperb.c,v 1.6 2011/10/15 15:14:30 tsutsui Exp $	*/
 
 /*
  * Copyright (c) 1995  Ken Nakata
@@ -31,8 +31,33 @@
  *	@(#)fpu_hyperb.c	10/24/95
  */
 
+/*
+ * Copyright (c) 2011 Tetsuya Isaki. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu_hyperb.c,v 1.5 2011/07/18 07:44:30 isaki Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu_hyperb.c,v 1.6 2011/10/15 15:14:30 tsutsui Exp $");
 
 #include "fpu_emulate.h"
 
@@ -52,20 +77,87 @@ fpu_atanh(struct fpemu *fe)
 struct fpn *
 fpu_cosh(struct fpemu *fe)
 {
-	/* stub */
+	struct fpn s0;
+	struct fpn *r;
+	int hyperb = 1;
+
+	fe->fe_fpsr &= ~FPSR_EXCP; /* clear all exceptions */
+
+	if (ISNAN(&fe->fe_f2))
+		return &fe->fe_f2;
+
+	if (ISINF(&fe->fe_f2)) {
+		fe->fe_f2.fp_sign = 0;
+		return &fe->fe_f2;
+	}
+
+	fpu_const(&s0, 0x32);	/* 1.0 */
+	r = fpu_sincos_taylor(fe, &s0, 1, hyperb);
+	CPYFPN(&fe->fe_f2, r);
+
+	fpu_upd_fpsr(fe, &fe->fe_f2);
 	return &fe->fe_f2;
 }
 
 struct fpn *
 fpu_sinh(struct fpemu *fe)
 {
-	/* stub */
+	struct fpn s0;
+	struct fpn *r;
+	int hyperb = 1;
+
+	fe->fe_fpsr &= ~FPSR_EXCP; /* clear all exceptions */
+
+	if (ISNAN(&fe->fe_f2))
+		return &fe->fe_f2;
+	if (ISINF(&fe->fe_f2))
+		return &fe->fe_f2;
+
+	CPYFPN(&s0, &fe->fe_f2);
+	r = fpu_sincos_taylor(fe, &s0, 2, hyperb);
+	CPYFPN(&fe->fe_f2, r);
+
+	fpu_upd_fpsr(fe, &fe->fe_f2);
 	return &fe->fe_f2;
 }
 
 struct fpn *
 fpu_tanh(struct fpemu *fe)
 {
-	/* stub */
+	struct fpn x;
+	struct fpn s;
+	struct fpn *r;
+	int sign;
+
+	fe->fe_fpsr &= ~FPSR_EXCP; /* clear all exceptions */
+
+	if (ISNAN(&fe->fe_f2))
+		return &fe->fe_f2;
+
+	if (ISINF(&fe->fe_f2)) {
+		sign = fe->fe_f2.fp_sign;
+		fpu_const(&fe->fe_f2, 0x32);
+		fe->fe_f2.fp_sign = sign;
+		return &fe->fe_f2;
+	}
+
+	CPYFPN(&x, &fe->fe_f2);
+
+	/* sinh(x) */
+	CPYFPN(&fe->fe_f2, &x);
+	r = fpu_sinh(fe);
+	CPYFPN(&s, r);
+
+	/* cosh(x) */
+	CPYFPN(&fe->fe_f2, &x);
+	r = fpu_cosh(fe);
+	CPYFPN(&fe->fe_f2, r);
+
+	CPYFPN(&fe->fe_f1, &s);
+	r = fpu_div(fe);
+
+	CPYFPN(&fe->fe_f2, r);
+
+	fpu_upd_fpsr(fe, &fe->fe_f2);
 	return &fe->fe_f2;
 }
Index: src/sys/arch/m68k/fpe/fpu_trig.c
diff -u src/sys/arch/m68k/fpe/fpu_trig.c:1.5 src/sys/arch/m68k/fpe/fpu_trig.c:1.6
--- src/sys/arch/m68k/fpe/fpu_trig.c:1.5	Mon Jul 18 07:44:30 2011
+++ src/sys/arch/m68k/fpe/fpu_trig.c	Sat Oct 15 15:14:30 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu_trig.c,v 1.5 2011/07/18 07:44:30 isaki Exp $	*/
+/*	$NetBSD: fpu_trig.c,v 1.6 2011/10/15 15:14:30 tsutsui Exp $	*/
 
 /*
  * Copyright (c) 1995  Ken Nakata
@@ -31,11 +31,39 @@
  *	@(#)fpu_trig.c	10/24/95
  */
 
+/*
+ * Copyright (c) 2011 Tetsuya Isaki. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu_trig.c,v 1.5 2011/07/18 07:44:30 isaki Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu_trig.c,v 1.6 2011/10/15 15:14:30 tsutsui Exp $");
 
 #include "fpu_emulate.h"
 
+static inline struct fpn *fpu_cos_halfpi(struct fpemu *);
+static inline struct fpn *fpu_sin_halfpi(struct fpemu *);
+
 struct fpn *
 fpu_acos(struct fpemu *fe)
 {
@@ -57,30 +85,411 @@ fpu_atan(struct fpemu *fe)
 	return &fe->fe_f2;
 }
 
+/*
+ * taylor expansion used by sin(), cos(), sinh(), cosh().
+ * hyperb is for sinh(), cosh().
+ */
+struct fpn *
+fpu_sincos_taylor(struct fpemu *fe, struct fpn *s0, u_int f, int hyperb)
+{
+	struct fpn res;
+	struct fpn x2;
+	struct fpn *s1;
+	struct fpn *r;
+	int sign;
+	u_int k;
+
+	/* x2 := x * x */
+	CPYFPN(&fe->fe_f1, &fe->fe_f2);
+	r = fpu_mul(fe);
+	CPYFPN(&x2, r);
+
+	/* res := s0 */
+	CPYFPN(&res, s0);
+
+	sign = 1;	/* sign := (-1)^n */
+
+	for (;;) {
+		/* (f1 :=) s0 * x^2 */
+		CPYFPN(&fe->fe_f1, s0);
+		CPYFPN(&fe->fe_f2, &x2);
+		r = fpu_mul(fe);
+		CPYFPN(&fe->fe_f1, r);
+
+		/*
+		 * for sin(),  s1 := s0 * x^2 / (2n+1)2n
+		 * for cos(),  s1 := s0 * x^2 / 2n(2n-1)
+		 */
+		k = f * (f + 1);
+		fpu_explode(fe, &fe->fe_f2, FTYPE_LNG, &k);
+		s1 = fpu_div(fe);
+
+		/* break if s1 is enough small */
+		if (ISZERO(s1))
+			break;
+		if (res.fp_exp - s1->fp_exp >= FP_NMANT)
+			break;
+
+		/* s0 := s1 for next loop */
+		CPYFPN(s0, s1);
+
+		CPYFPN(&fe->fe_f2, s1);
+		if (!hyperb) {
+			/* (-1)^n */
+			fe->fe_f2.fp_sign = sign;
+		}
+
+		/* res += s1 */
+		CPYFPN(&fe->fe_f1, &res);
+		r = fpu_add(fe);
+		CPYFPN(&res, r);
+
+		f += 2;
+		sign ^= 1;
+	}
+
+	CPYFPN(&fe->fe_f2, &res);
+	return &fe->fe_f2;
+}
+
+/*
+ *           inf   (-1)^n    2n
+ * cos(x) = \sum { ------ * x   }
+ *           n=0     2n!
+ *
+ *              x^2   x^4   x^6
+ *        = 1 - --- + --- - --- + ...
+ *               2!    4!    6!
+ *
+ *        = s0 - s1 + s2  - s3  + ...
+ *
+ *               x*x           x*x           x*x
+ * s0 = 1,  s1 = ---*s0,  s2 = ---*s1,  s3 = ---*s2, ...
+ *               1*2           3*4           5*6
+ *
+ * here 0 <= x < pi/2
+ */
+static inline struct fpn *
+fpu_cos_halfpi(struct fpemu *fe)
+{
+	struct fpn s0;
+
+	/* s0 := 1 */
+	fpu_const(&s0, 0x32);
+
+	return fpu_sincos_taylor(fe, &s0, 1, 0);
+}
+
+/*
+ *          inf    (-1)^n     2n+1
+ * sin(x) = \sum { ------- * x     }
+ *          n=0    (2n+1)!
+ *
+ *              x^3   x^5   x^7
+ *        = x - --- + --- - --- + ...
+ *               3!    5!    7!
+ *
+ *        = s0 - s1 + s2  - s3  + ...
+ *
+ *               x*x           x*x           x*x
+ * s0 = x,  s1 = ---*s0,  s2 = ---*s1,  s3 = ---*s2, ...
+ *               2*3           4*5           6*7
+ *
+ * here 0 <= x < pi/2
+ */
+static inline struct fpn *
+fpu_sin_halfpi(struct fpemu *fe)
+{
+	struct fpn s0;
+
+	/* s0 := x */
+	CPYFPN(&s0, &fe->fe_f2);
+
+	return fpu_sincos_taylor(fe, &s0, 2, 0);
+}
+
+/*
+ * cos(x):
+ *
+ *	if (x < 0) {
+ *		x = abs(x);
+ *	}
+ *	if (x > 2*pi) {
+ *		x %= 2*pi;
+ *	}
+ *	if (x > pi) {
+ *		x -= pi;
+ *		sign inverse;
+ *	}
+ *	if (x > pi/2) {
+ *		y = sin(x - pi/2);
+ *		sign inverse;
+ *	} else {
+ *		y = cos(x);
+ *	}
+ *	if (sign) {
+ *		y = -y;
+ *	}
+ */
 struct fpn *
 fpu_cos(struct fpemu *fe)
 {
-	/* stub */
+	struct fpn x;
+	struct fpn p;
+	struct fpn *r;
+	int sign;
+
+	fe->fe_fpsr &= ~FPSR_EXCP; /* clear all exceptions */
+
+	if (ISNAN(&fe->fe_f2))
+		return &fe->fe_f2;
+	if (ISINF(&fe->fe_f2))
+		return fpu_newnan(fe);
+
+	CPYFPN(&x, &fe->fe_f2);
+
+	/* x = abs(input) */
+	x.fp_sign = 0;
+	sign = 0;
+
+	/* p <- 2*pi */
+	fpu_const(&p, 0);
+	p.fp_exp++;
+
+	/*
+	 * if (x > 2*pi*N)
+	 *  cos(x) is cos(x - 2*pi*N)
+	 */
+	CPYFPN(&fe->fe_f1, &x);
+	CPYFPN(&fe->fe_f2, &p);
+	r = fpu_cmp(fe);
+	if (r->fp_sign == 0) {
+		CPYFPN(&fe->fe_f1, &x);
+		CPYFPN(&fe->fe_f2, &p);
+		r = fpu_mod(fe);
+		CPYFPN(&x, r);
+	}
+
+	/* p <- pi */
+	p.fp_exp--;
+
+	/*
+	 * if (x > pi)
+	 *  cos(x) is -cos(x - pi)
+	 */
+	CPYFPN(&fe->fe_f1, &x);
+	CPYFPN(&fe->fe_f2, &p);
+	r = fpu_cmp(fe);
+	if (r->fp_sign == 0) {
+		CPYFPN(&fe->fe_f1, &x);
+		CPYFPN(&fe->fe_f2, &p);
+		fe->fe_f2.fp_sign = 1;
+		r = fpu_add(fe);
+		CPYFPN(&x, r);
+
+		sign ^= 1;
+	}
+
+	/* p <- pi/2 */
+	p.fp_exp--;
+
+	/*
+	 * if (x > pi/2)
+	 *  cos(x) is -sin(x - pi/2)
+	 * else
+	 *  cos(x)
+	 */
+	CPYFPN(&fe->fe_f1, &x);
+	CPYFPN(&fe->fe_f2, &p);
+	r = fpu_cmp(fe);
+	if (r->fp_sign == 0) {
+		CPYFPN(&fe->fe_f1, &x);
+		CPYFPN(&fe->fe_f2, &p);
+		fe->fe_f2.fp_sign = 1;
+		r = fpu_add(fe);
+
+		CPYFPN(&fe->fe_f2, r);
+		r = fpu_sin_halfpi(fe);
+		sign ^= 1;
+	} else {
+		CPYFPN(&fe->fe_f2, &x);
+		r = fpu_cos_halfpi(fe);
+	}
+
+	CPYFPN(&fe->fe_f2, r);
+	fe->fe_f2.fp_sign = sign;
+
+	fpu_upd_fpsr(fe, &fe->fe_f2);
 	return &fe->fe_f2;
 }
 
+/*
+ * sin(x):
+ *
+ *	if (x < 0) {
+ *		x = abs(x);
+ *		sign = 1;
+ *	}
+ *	if (x > 2*pi) {
+ *		x %= 2*pi;
+ *	}
+ *	if (x > pi) {
+ *		x -= pi;
+ *		sign inverse;
+ *	}
+ *	if (x > pi/2) {
+ *		y = cos(x - pi/2);
+ *	} else {
+ *		y = sin(x);
+ *	}
+ *	if (sign) {
+ *		y = -y;
+ *	}
+ */
 struct fpn *
 fpu_sin(struct fpemu *fe)
 {
-	/* stub */
+	struct fpn x;
+	struct fpn p;
+	struct fpn *r;
+	int sign;
+
+	fe->fe_fpsr &= ~FPSR_EXCP; /* clear all exceptions */
+
+	if (ISNAN(&fe->fe_f2))
+		return &fe->fe_f2;
+	if (ISINF(&fe->fe_f2))
+		return fpu_newnan(fe);
+
+	CPYFPN(&x, &fe->fe_f2);
+
+	/* x = abs(input) */
+	sign = x.fp_sign;
+	x.fp_sign = 0;
+
+	/* p <- 2*pi */
+	fpu_const(&p, 0);
+	p.fp_exp++;
+
+	/*
+	 * if (x > 2*pi*N)
+	 *  sin(x) is sin(x - 2*pi*N)
+	 */
+	CPYFPN(&fe->fe_f1, &x);
+	CPYFPN(&fe->fe_f2, &p);
+	r = fpu_cmp(fe);
+	if (r->fp_sign == 0) {
+		CPYFPN(&fe->fe_f1, &x);
+		CPYFPN(&fe->fe_f2, &p);
+		r = fpu_mod(fe);
+		CPYFPN(&x, r);
+	}
+
+	/* p <- pi */
+	p.fp_exp--;
+
+	/*
+	 * if (x > pi)
+	 *  sin(x) is -sin(x - pi)
+	 */
+	CPYFPN(&fe->fe_f1, &x);
+	CPYFPN(&fe->fe_f2, &p);
+	r = fpu_cmp(fe);
+	if (r->fp_sign == 0) {
+		CPYFPN(&fe->fe_f1, &x);
+		CPYFPN(&fe->fe_f2, &p);
+		fe->fe_f2.fp_sign = 1;
+		r = fpu_add(fe);
+		CPYFPN(&x, r);
+
+		sign ^= 1;
+	}
+
+	/* p <- pi/2 */
+	p.fp_exp--;
+
+	/*
+	 * if (x > pi/2)
+	 *  sin(x) is cos(x - pi/2)
+	 * else
+	 *  sin(x)
+	 */
+	CPYFPN(&fe->fe_f1, &x);
+	CPYFPN(&fe->fe_f2, &p);
+	r = fpu_cmp(fe);
+	if (r->fp_sign == 0) {
+		CPYFPN(&fe->fe_f1, &x);
+		CPYFPN(&fe->fe_f2, &p);
+		fe->fe_f2.fp_sign = 1;
+		r = fpu_add(fe);
+
+		CPYFPN(&fe->fe_f2, r);
+		r = fpu_cos_halfpi(fe);
+	} else {
+		CPYFPN(&fe->fe_f2, &x);
+		r = fpu_sin_halfpi(fe);
+	}
+
+	CPYFPN(&fe->fe_f2, r);
+	fe->fe_f2.fp_sign = sign;
+
+	fpu_upd_fpsr(fe, &fe->fe_f2);
 	return &fe->fe_f2;
 }
 
+/*
+ * tan(x) = sin(x) / cos(x)
+ */
 struct fpn *
 fpu_tan(struct fpemu *fe)
 {
-	/* stub */
+	struct fpn x;
+	struct fpn s;
+	struct fpn *r;
+
+	fe->fe_fpsr &= ~FPSR_EXCP; /* clear all exceptions */
+
+	if (ISNAN(&fe->fe_f2))
+		return &fe->fe_f2;
+	if (ISINF(&fe->fe_f2))
+		return fpu_newnan(fe);
+
+	CPYFPN(&x, &fe->fe_f2);
+
+	/* sin(x) */
+	CPYFPN(&fe->fe_f2, &x);
+	r = fpu_sin(fe);
+	CPYFPN(&s, r);
+
+	/* cos(x) */
+	CPYFPN(&fe->fe_f2, &x);
+	r = fpu_cos(fe);
+	CPYFPN(&fe->fe_f2, r);
+
+	CPYFPN(&fe->fe_f1, &s);
+	r = fpu_div(fe);
+
+	CPYFPN(&fe->fe_f2, r);
+
+	fpu_upd_fpsr(fe, &fe->fe_f2);
 	return &fe->fe_f2;
 }
 
 struct fpn *
 fpu_sincos(struct fpemu *fe, int regc)
 {
-	/* stub */
-	return &fe->fe_f2;
+	struct fpn x;
+	struct fpn *r;
+
+	CPYFPN(&x, &fe->fe_f2);
+
+	/* cos(x) */
+	r = fpu_cos(fe);
+	fpu_implode(fe, r, FTYPE_EXT, &fe->fe_fpframe->fpf_regs[regc]);
+
+	/* sin(x) */
+	CPYFPN(&fe->fe_f2, &x);
+	r = fpu_sin(fe);
+	fpu_upd_fpsr(fe, r);
+	return r;
 }

Reply via email to