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; }