Home | History | Annotate | Line # | Download | only in fpe
fpu_cordic.c revision 1.2.16.1
      1 /*	$NetBSD: fpu_cordic.c,v 1.2.16.1 2016/10/05 20:55:31 skrll Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2013 Tetsuya Isaki. All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 __KERNEL_RCSID(0, "$NetBSD: fpu_cordic.c,v 1.2.16.1 2016/10/05 20:55:31 skrll Exp $");
     30 
     31 #include <machine/ieee.h>
     32 
     33 #include "fpu_emulate.h"
     34 
     35 /*
     36  * sfpn = shoftened fp number; the idea is from fpu_log.c but not the same.
     37  * The most significant byte of sp_m0 is EXP (signed byte) and the rest
     38  * of sp_m0 is fp_mant[0].
     39  */
     40 struct sfpn {
     41 	uint32_t sp_m0;
     42 	uint32_t sp_m1;
     43 	uint32_t sp_m2;
     44 };
     45 
     46 #if defined(CORDIC_BOOTSTRAP)
     47 /*
     48  * This is a bootstrap code to generate a pre-calculated tables such as
     49  * atan_table[] and atanh_table[].  However, it's just for reference.
     50  * If you want to run the bootstrap, you will define CORDIC_BOOTSTRAP
     51  * and modify these files as a userland application.
     52  */
     53 
     54 #include <stdio.h>
     55 #include <stdlib.h>
     56 #include <string.h>
     57 #include <float.h>
     58 
     59 static void prepare_cordic_const(struct fpemu *);
     60 static struct fpn *fpu_gain1_cordic(struct fpemu *);
     61 static struct fpn *fpu_gain2_cordic(struct fpemu *);
     62 static struct fpn *fpu_atan_taylor(struct fpemu *);
     63 static void printf_fpn(const struct fpn *);
     64 static void printf_sfpn(const struct sfpn *);
     65 static void fpn_to_sfpn(struct sfpn *, const struct fpn *);
     66 
     67 static struct sfpn atan_table[EXT_FRACBITS];
     68 static struct sfpn atanh_table[EXT_FRACBITS];
     69 static struct fpn inv_gain1;
     70 static struct fpn inv_gain2;
     71 
     72 static void fpu_cordit2(struct fpemu *,
     73 	struct fpn *, struct fpn *, struct fpn *, const struct fpn *);
     74 
     75 int
     76 main(int argc, char *argv[])
     77 {
     78 	struct fpemu dummyfe;
     79 	int i;
     80 	struct fpn fp;
     81 
     82 	memset(&dummyfe, 0, sizeof(dummyfe));
     83 	prepare_cordic_const(&dummyfe);
     84 
     85 	/* output as source code */
     86 	printf("static const struct sfpn atan_table[] = {\n");
     87 	for (i = 0; i < EXT_FRACBITS; i++) {
     88 		printf("\t");
     89 		printf_sfpn(&atan_table[i]);
     90 		printf(",\n");
     91 	}
     92 	printf("};\n\n");
     93 
     94 	printf("static const struct sfpn atanh_table[] = {\n");
     95 	for (i = 0; i < EXT_FRACBITS; i++) {
     96 		printf("\t");
     97 		printf_sfpn(&atanh_table[i]);
     98 		printf(",\n");
     99 	}
    100 	printf("};\n\n");
    101 
    102 	printf("const struct fpn fpu_cordic_inv_gain1 =\n\t");
    103 	printf_fpn(&inv_gain1);
    104 	printf(";\n\n");
    105 
    106 	printf("const struct fpn fpu_cordic_inv_gain2 =\n\t");
    107 	printf_fpn(&inv_gain2);
    108 	printf(";\n\n");
    109 }
    110 
    111 /*
    112  * This routine uses fpu_const(), fpu_add(), fpu_div(), fpu_logn()
    113  * and fpu_atan_taylor() as bootstrap.
    114  */
    115 static void
    116 prepare_cordic_const(struct fpemu *fe)
    117 {
    118 	struct fpn t;
    119 	struct fpn x;
    120 	struct fpn *r;
    121 	int i;
    122 
    123 	/* atan_table and atanh_table */
    124 	fpu_const(&t, FPU_CONST_1);
    125 	for (i = 0; i < EXT_FRACBITS; i++) {
    126 		/* atan(t) */
    127 		CPYFPN(&fe->fe_f2, &t);
    128 		r = fpu_atan_taylor(fe);
    129 		fpn_to_sfpn(&atan_table[i], r);
    130 
    131 		/* t /= 2 */
    132 		t.fp_exp--;
    133 
    134 		/* (1-t) */
    135 		fpu_const(&fe->fe_f1, FPU_CONST_1);
    136 		CPYFPN(&fe->fe_f2, &t);
    137 		fe->fe_f2.fp_sign = 1;
    138 		r = fpu_add(fe);
    139 		CPYFPN(&x, r);
    140 
    141 		/* (1+t) */
    142 		fpu_const(&fe->fe_f1, FPU_CONST_1);
    143 		CPYFPN(&fe->fe_f2, &t);
    144 		r = fpu_add(fe);
    145 
    146 		/* r = (1+t)/(1-t) */
    147 		CPYFPN(&fe->fe_f1, r);
    148 		CPYFPN(&fe->fe_f2, &x);
    149 		r = fpu_div(fe);
    150 
    151 		/* r = log(r) */
    152 		CPYFPN(&fe->fe_f2, r);
    153 		r = fpu_logn(fe);
    154 
    155 		/* r /= 2 */
    156 		r->fp_exp--;
    157 
    158 		fpn_to_sfpn(&atanh_table[i], r);
    159 	}
    160 
    161 	/* inv_gain1 = 1 / gain1cordic() */
    162 	r = fpu_gain1_cordic(fe);
    163 	CPYFPN(&fe->fe_f2, r);
    164 	fpu_const(&fe->fe_f1, FPU_CONST_1);
    165 	r = fpu_div(fe);
    166 	CPYFPN(&inv_gain1, r);
    167 
    168 	/* inv_gain2 = 1 / gain2cordic() */
    169 	r = fpu_gain2_cordic(fe);
    170 	CPYFPN(&fe->fe_f2, r);
    171 	fpu_const(&fe->fe_f1, FPU_CONST_1);
    172 	r = fpu_div(fe);
    173 	CPYFPN(&inv_gain2, r);
    174 }
    175 
    176 static struct fpn *
    177 fpu_gain1_cordic(struct fpemu *fe)
    178 {
    179 	struct fpn x;
    180 	struct fpn y;
    181 	struct fpn z;
    182 	struct fpn v;
    183 
    184 	fpu_const(&x, FPU_CONST_1);
    185 	fpu_const(&y, FPU_CONST_0);
    186 	fpu_const(&z, FPU_CONST_0);
    187 	CPYFPN(&v, &x);
    188 	v.fp_sign = !v.fp_sign;
    189 
    190 	fpu_cordit1(fe, &x, &y, &z, &v);
    191 	CPYFPN(&fe->fe_f2, &x);
    192 	return &fe->fe_f2;
    193 }
    194 
    195 static struct fpn *
    196 fpu_gain2_cordic(struct fpemu *fe)
    197 {
    198 	struct fpn x;
    199 	struct fpn y;
    200 	struct fpn z;
    201 	struct fpn v;
    202 
    203 	fpu_const(&x, FPU_CONST_1);
    204 	fpu_const(&y, FPU_CONST_0);
    205 	fpu_const(&z, FPU_CONST_0);
    206 	CPYFPN(&v, &x);
    207 	v.fp_sign = !v.fp_sign;
    208 
    209 	fpu_cordit2(fe, &x, &y, &z, &v);
    210 	CPYFPN(&fe->fe_f2, &x);
    211 	return &fe->fe_f2;
    212 }
    213 
    214 /*
    215  * arctan(x) = pi/4 (for |x| = 1)
    216  *
    217  *                 x^3   x^5   x^7
    218  * arctan(x) = x - --- + --- - --- + ...   (for |x| < 1)
    219  *                  3     5     7
    220  */
    221 static struct fpn *
    222 fpu_atan_taylor(struct fpemu *fe)
    223 {
    224 	struct fpn res;
    225 	struct fpn x2;
    226 	struct fpn s0;
    227 	struct fpn *s1;
    228 	struct fpn *r;
    229 	uint32_t k;
    230 
    231 	/* arctan(1) is pi/4 */
    232 	if (fe->fe_f2.fp_exp == 0) {
    233 		fpu_const(&fe->fe_f2, FPU_CONST_PI);
    234 		fe->fe_f2.fp_exp -= 2;
    235 		return &fe->fe_f2;
    236 	}
    237 
    238 	/* s0 := x */
    239 	CPYFPN(&s0, &fe->fe_f2);
    240 
    241 	/* res := x */
    242 	CPYFPN(&res, &fe->fe_f2);
    243 
    244 	/* x2 := x * x */
    245 	CPYFPN(&fe->fe_f1, &fe->fe_f2);
    246 	r = fpu_mul(fe);
    247 	CPYFPN(&x2, r);
    248 
    249 	k = 3;
    250 	for (;;) {
    251 		/* s1 := -s0 * x2 */
    252 		CPYFPN(&fe->fe_f1, &s0);
    253 		CPYFPN(&fe->fe_f2, &x2);
    254 		s1 = fpu_mul(fe);
    255 		s1->fp_sign ^= 1;
    256 		CPYFPN(&fe->fe_f1, s1);
    257 
    258 		/* s0 := s1 for next loop */
    259 		CPYFPN(&s0, s1);
    260 
    261 		/* s1 := s1 / k */
    262 		fpu_explode(fe, &fe->fe_f2, FTYPE_LNG, &k);
    263 		s1 = fpu_div(fe);
    264 
    265 		/* break if s1 is enough small */
    266 		if (ISZERO(s1))
    267 			break;
    268 		if (res.fp_exp - s1->fp_exp >= FP_NMANT)
    269 			break;
    270 
    271 		/* res += s1 */
    272 		CPYFPN(&fe->fe_f2, s1);
    273 		CPYFPN(&fe->fe_f1, &res);
    274 		r = fpu_add(fe);
    275 		CPYFPN(&res, r);
    276 
    277 		k += 2;
    278 	}
    279 
    280 	CPYFPN(&fe->fe_f2, &res);
    281 	return &fe->fe_f2;
    282 }
    283 
    284 static void
    285 printf_fpn(const struct fpn *fp)
    286 {
    287 	printf("{ %d, %d, %3d, %d, { 0x%08x, 0x%08x, 0x%08x, }, }",
    288 		fp->fp_class, fp->fp_sign, fp->fp_exp, fp->fp_sticky ? 1 : 0,
    289 		fp->fp_mant[0], fp->fp_mant[1], fp->fp_mant[2]);
    290 }
    291 
    292 static void
    293 printf_sfpn(const struct sfpn *sp)
    294 {
    295 	printf("{ 0x%08x, 0x%08x, 0x%08x, }",
    296 		sp->sp_m0, sp->sp_m1, sp->sp_m2);
    297 }
    298 
    299 static void
    300 fpn_to_sfpn(struct sfpn *sp, const struct fpn *fp)
    301 {
    302 	sp->sp_m0 = (fp->fp_exp << 24) | fp->fp_mant[0];
    303 	sp->sp_m1 = fp->fp_mant[1];
    304 	sp->sp_m2 = fp->fp_mant[2];
    305 }
    306 
    307 #else /* CORDIC_BOOTSTRAP */
    308 
    309 static const struct sfpn atan_table[] = {
    310 	{ 0xff06487e, 0xd5110b46, 0x11a80000, },
    311 	{ 0xfe076b19, 0xc1586ed3, 0xda2b7f0d, },
    312 	{ 0xfd07d6dd, 0x7e4b2037, 0x58ab6e33, },
    313 	{ 0xfc07f56e, 0xa6ab0bdb, 0x719644b5, },
    314 	{ 0xfb07fd56, 0xedcb3f7a, 0x71b65937, },
    315 	{ 0xfa07ff55, 0x6eea5d89, 0x2a13bce7, },
    316 	{ 0xf907ffd5, 0x56eedca6, 0xaddf3c5f, },
    317 	{ 0xf807fff5, 0x556eeea5, 0xcb403117, },
    318 	{ 0xf707fffd, 0x5556eeed, 0xca5d8956, },
    319 	{ 0xf607ffff, 0x55556eee, 0xea5ca6ab, },
    320 	{ 0xf507ffff, 0xd55556ee, 0xeedca5c8, },
    321 	{ 0xf407ffff, 0xf555556e, 0xeeeea5c8, },
    322 	{ 0xf307ffff, 0xfd555556, 0xeeeeedc8, },
    323 	{ 0xf207ffff, 0xff555555, 0x6eeeeee8, },
    324 	{ 0xf107ffff, 0xffd55555, 0x56eeeeed, },
    325 	{ 0xf007ffff, 0xfff55555, 0x556eeeed, },
    326 	{ 0xef07ffff, 0xfffd5555, 0x5556eeed, },
    327 	{ 0xee07ffff, 0xffff5555, 0x55556eed, },
    328 	{ 0xed07ffff, 0xffffd555, 0x555556ed, },
    329 	{ 0xec07ffff, 0xfffff555, 0x5555556d, },
    330 	{ 0xeb07ffff, 0xfffffd55, 0x55555555, },
    331 	{ 0xea07ffff, 0xffffff55, 0x55555554, },
    332 	{ 0xe907ffff, 0xffffffd5, 0x55555554, },
    333 	{ 0xe807ffff, 0xfffffff5, 0x55555554, },
    334 	{ 0xe707ffff, 0xfffffffd, 0x55555554, },
    335 	{ 0xe607ffff, 0xffffffff, 0x55555554, },
    336 	{ 0xe507ffff, 0xffffffff, 0xd5555554, },
    337 	{ 0xe407ffff, 0xffffffff, 0xf5555554, },
    338 	{ 0xe307ffff, 0xffffffff, 0xfd555554, },
    339 	{ 0xe207ffff, 0xffffffff, 0xff555554, },
    340 	{ 0xe107ffff, 0xffffffff, 0xffd55554, },
    341 	{ 0xe007ffff, 0xffffffff, 0xfff55554, },
    342 	{ 0xdf07ffff, 0xffffffff, 0xfffd5554, },
    343 	{ 0xde07ffff, 0xffffffff, 0xffff5554, },
    344 	{ 0xdd07ffff, 0xffffffff, 0xffffd554, },
    345 	{ 0xdc07ffff, 0xffffffff, 0xfffff554, },
    346 	{ 0xdb07ffff, 0xffffffff, 0xfffffd54, },
    347 	{ 0xda07ffff, 0xffffffff, 0xffffff54, },
    348 	{ 0xd907ffff, 0xffffffff, 0xffffffd4, },
    349 	{ 0xd807ffff, 0xffffffff, 0xfffffff4, },
    350 	{ 0xd707ffff, 0xffffffff, 0xfffffffc, },
    351 	{ 0xd7040000, 0x00000000, 0x00000000, },
    352 	{ 0xd6040000, 0x00000000, 0x00000000, },
    353 	{ 0xd5040000, 0x00000000, 0x00000000, },
    354 	{ 0xd4040000, 0x00000000, 0x00000000, },
    355 	{ 0xd3040000, 0x00000000, 0x00000000, },
    356 	{ 0xd2040000, 0x00000000, 0x00000000, },
    357 	{ 0xd1040000, 0x00000000, 0x00000000, },
    358 	{ 0xd0040000, 0x00000000, 0x00000000, },
    359 	{ 0xcf040000, 0x00000000, 0x00000000, },
    360 	{ 0xce040000, 0x00000000, 0x00000000, },
    361 	{ 0xcd040000, 0x00000000, 0x00000000, },
    362 	{ 0xcc040000, 0x00000000, 0x00000000, },
    363 	{ 0xcb040000, 0x00000000, 0x00000000, },
    364 	{ 0xca040000, 0x00000000, 0x00000000, },
    365 	{ 0xc9040000, 0x00000000, 0x00000000, },
    366 	{ 0xc8040000, 0x00000000, 0x00000000, },
    367 	{ 0xc7040000, 0x00000000, 0x00000000, },
    368 	{ 0xc6040000, 0x00000000, 0x00000000, },
    369 	{ 0xc5040000, 0x00000000, 0x00000000, },
    370 	{ 0xc4040000, 0x00000000, 0x00000000, },
    371 	{ 0xc3040000, 0x00000000, 0x00000000, },
    372 	{ 0xc2040000, 0x00000000, 0x00000000, },
    373 	{ 0xc1040000, 0x00000000, 0x00000000, },
    374 };
    375 
    376 static const struct sfpn atanh_table[] = {
    377 	{ 0xff0464fa, 0x9eab40c2, 0xa5dc43f6, },
    378 	{ 0xfe04162b, 0xbea04514, 0x69ca8e4a, },
    379 	{ 0xfd040562, 0x4727abbd, 0xda654b67, },
    380 	{ 0xfc040156, 0x22b4dd6b, 0x372a679c, },
    381 	{ 0xfb040055, 0x62246bb8, 0x92d60b35, },
    382 	{ 0xfa040015, 0x56222b47, 0x2637d656, },
    383 	{ 0xf9040005, 0x55622246, 0xb4dcf86e, },
    384 	{ 0xf8040001, 0x55562222, 0xb46bb307, },
    385 	{ 0xf7040000, 0x55556222, 0x246b45cd, },
    386 	{ 0xf6040000, 0x15555622, 0x222b465b, },
    387 	{ 0xf5040000, 0x05555562, 0x2222467f, },
    388 	{ 0xf4040000, 0x01555556, 0x22221eaf, },
    389 	{ 0xf3040000, 0x00555555, 0x62222213, },
    390 	{ 0xf2040000, 0x00155555, 0x56221221, },
    391 	{ 0xf1040000, 0x00055555, 0x556221a2, },
    392 	{ 0xf0040000, 0x00015555, 0x5556221e, },
    393 	{ 0xef040000, 0x00005555, 0x55552222, },
    394 	{ 0xee040000, 0x00001555, 0x55555222, },
    395 	{ 0xed040000, 0x00000555, 0x55555522, },
    396 	{ 0xec040000, 0x00000155, 0x55555552, },
    397 	{ 0xeb040000, 0x00000055, 0x554d5555, },
    398 	{ 0xea040000, 0x00000015, 0x55545555, },
    399 	{ 0xe9040000, 0x00000005, 0x55553555, },
    400 	{ 0xe8040000, 0x00000001, 0x55555155, },
    401 	{ 0xe7040000, 0x00000000, 0x555554d5, },
    402 	{ 0xe6040000, 0x00000000, 0x15555545, },
    403 	{ 0xe5040000, 0x00000000, 0x05555553, },
    404 	{ 0xe307ffff, 0xffffffff, 0xfaaaaaaa, },
    405 	{ 0xe207ffff, 0xffffffff, 0xfeaaaaaa, },
    406 	{ 0xe107ffff, 0xffffffff, 0xffaaaaaa, },
    407 	{ 0xe007ffff, 0xffffffff, 0xffeaaaaa, },
    408 	{ 0xdf07ffff, 0xffffffff, 0xfffaaaaa, },
    409 	{ 0xde07ffff, 0xffffffff, 0xfffeaaaa, },
    410 	{ 0xdd07ffff, 0xffffffff, 0xffffaaaa, },
    411 	{ 0xdc07ffff, 0xffffffff, 0xffffeaaa, },
    412 	{ 0xdb07ffff, 0xffffffff, 0xfffffaaa, },
    413 	{ 0xda07ffff, 0xffffffff, 0xfffffeaa, },
    414 	{ 0xd907ffff, 0xffffffff, 0xffffffaa, },
    415 	{ 0xd807ffff, 0xffffffff, 0xffffffea, },
    416 	{ 0xd707ffff, 0xffffffff, 0xfffffffa, },
    417 	{ 0xd607ffff, 0xffffffff, 0xfffffffe, },
    418 	{ 0xd507ffff, 0xfffffe00, 0x00000000, },
    419 	{ 0xd407ffff, 0xffffff00, 0x00000000, },
    420 	{ 0xd307ffff, 0xffffff80, 0x00000000, },
    421 	{ 0xd207ffff, 0xffffffc0, 0x00000000, },
    422 	{ 0xd107ffff, 0xffffffe0, 0x00000000, },
    423 	{ 0xd007ffff, 0xfffffff0, 0x00000000, },
    424 	{ 0xcf07ffff, 0xfffffff8, 0x00000000, },
    425 	{ 0xce07ffff, 0xfffffffc, 0x00000000, },
    426 	{ 0xcd07ffff, 0xfffffffe, 0x00000000, },
    427 	{ 0xcc07ffff, 0xffffffff, 0x00000000, },
    428 	{ 0xcb07ffff, 0xffffffff, 0x80000000, },
    429 	{ 0xca07ffff, 0xffffffff, 0xc0000000, },
    430 	{ 0xc907ffff, 0xffffffff, 0xe0000000, },
    431 	{ 0xc807ffff, 0xffffffff, 0xf0000000, },
    432 	{ 0xc707ffff, 0xffffffff, 0xf8000000, },
    433 	{ 0xc607ffff, 0xffffffff, 0xfc000000, },
    434 	{ 0xc507ffff, 0xffffffff, 0xfe000000, },
    435 	{ 0xc407ffff, 0xffffffff, 0xff000000, },
    436 	{ 0xc307ffff, 0xffffffff, 0xff800000, },
    437 	{ 0xc207ffff, 0xffffffff, 0xffc00000, },
    438 	{ 0xc107ffff, 0xffffffff, 0xffe00000, },
    439 	{ 0xc007ffff, 0xffffffff, 0xfff00000, },
    440 	{ 0xbf07ffff, 0xffffffff, 0xfff80000, },
    441 };
    442 
    443 const struct fpn fpu_cordic_inv_gain1 =
    444 	{ 1, 0,  -1, 1, { 0x0004dba7, 0x6d421af2, 0xd33fafd1, }, };
    445 
    446 const struct fpn fpu_cordic_inv_gain2 =
    447 	{ 1, 0,   0, 1, { 0x0004d483, 0xec3803fc, 0xc5ff12f8, }, };
    448 
    449 #endif /* CORDIC_BOOTSTRAP */
    450 
    451 static inline void
    452 sfpn_to_fpn(struct fpn *fp, const struct sfpn *s)
    453 {
    454 	fp->fp_class = FPC_NUM;
    455 	fp->fp_sign = 0;
    456 	fp->fp_sticky = 0;
    457 	fp->fp_exp = s->sp_m0 >> 24;
    458 	if (fp->fp_exp & 0x80) {
    459 		fp->fp_exp |= 0xffffff00;
    460 	}
    461 	fp->fp_mant[0] = s->sp_m0 & 0x000fffff;
    462 	fp->fp_mant[1] = s->sp_m1;
    463 	fp->fp_mant[2] = s->sp_m2;
    464 }
    465 
    466 void
    467 fpu_cordit1(struct fpemu *fe, struct fpn *x0, struct fpn *y0, struct fpn *z0,
    468 	const struct fpn *vecmode)
    469 {
    470 	struct fpn t;
    471 	struct fpn x;
    472 	struct fpn y;
    473 	struct fpn z;
    474 	struct fpn *r;
    475 	int i;
    476 	int sign;
    477 
    478 	fpu_const(&t, FPU_CONST_1);
    479 	CPYFPN(&x, x0);
    480 	CPYFPN(&y, y0);
    481 	CPYFPN(&z, z0);
    482 
    483 	for (i = 0; i < EXT_FRACBITS; i++) {
    484 		struct fpn x1;
    485 
    486 		/* y < vecmode */
    487 		CPYFPN(&fe->fe_f1, &y);
    488 		CPYFPN(&fe->fe_f2, vecmode);
    489 		fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign;
    490 		r = fpu_add(fe);
    491 
    492 		if ((vecmode->fp_sign == 0 && r->fp_sign) ||
    493 		    (vecmode->fp_sign && z.fp_sign == 0)) {
    494 			sign = 1;
    495 		} else {
    496 			sign = 0;
    497 		}
    498 
    499 		/* y * t */
    500 		CPYFPN(&fe->fe_f1, &y);
    501 		CPYFPN(&fe->fe_f2, &t);
    502 		r = fpu_mul(fe);
    503 
    504 		/*
    505 		 * x1 = x - y*t (if sign)
    506 		 * x1 = x + y*t
    507 		 */
    508 		CPYFPN(&fe->fe_f2, r);
    509 		if (sign)
    510 			fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign;
    511 		CPYFPN(&fe->fe_f1, &x);
    512 		r = fpu_add(fe);
    513 		CPYFPN(&x1, r);
    514 
    515 		/* x * t */
    516 		CPYFPN(&fe->fe_f1, &x);
    517 		CPYFPN(&fe->fe_f2, &t);
    518 		r = fpu_mul(fe);
    519 
    520 		/*
    521 		 * y = y + x*t (if sign)
    522 		 * y = y - x*t
    523 		 */
    524 		CPYFPN(&fe->fe_f2, r);
    525 		if (!sign)
    526 			fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign;
    527 		CPYFPN(&fe->fe_f1, &y);
    528 		r = fpu_add(fe);
    529 		CPYFPN(&y, r);
    530 
    531 		/*
    532 		 * z = z - atan_table[i] (if sign)
    533 		 * z = z + atan_table[i]
    534 		 */
    535 		CPYFPN(&fe->fe_f1, &z);
    536 		sfpn_to_fpn(&fe->fe_f2, &atan_table[i]);
    537 		if (sign)
    538 			fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign;
    539 		r = fpu_add(fe);
    540 		CPYFPN(&z, r);
    541 
    542 		/* x = x1 */
    543 		CPYFPN(&x, &x1);
    544 
    545 		/* t /= 2 */
    546 		t.fp_exp--;
    547 	}
    548 
    549 	CPYFPN(x0, &x);
    550 	CPYFPN(y0, &y);
    551 	CPYFPN(z0, &z);
    552 }
    553 
    554 #if defined(CORDIC_BOOTSTRAP)
    555 static void
    556 fpu_cordit2(struct fpemu *fe, struct fpn *x0, struct fpn *y0, struct fpn *z0,
    557 	const struct fpn *vecmode)
    558 {
    559 	struct fpn t;
    560 	struct fpn x;
    561 	struct fpn y;
    562 	struct fpn z;
    563 	struct fpn *r;
    564 	int i;
    565 	int k;
    566 	int sign;
    567 
    568 	/* t = 0.5 */
    569 	fpu_const(&t, FPU_CONST_1);
    570 	t.fp_exp--;
    571 
    572 	CPYFPN(&x, x0);
    573 	CPYFPN(&y, y0);
    574 	CPYFPN(&z, z0);
    575 
    576 	k = 3;
    577 	for (i = 0; i < EXT_FRACBITS; i++) {
    578 		struct fpn x1;
    579 		int j;
    580 
    581 		for (j = 0; j < 2; j++) {
    582 			if ((vecmode->fp_sign == 0 && y.fp_sign) ||
    583 			    (vecmode->fp_sign && z.fp_sign == 0)) {
    584 				sign = 0;
    585 			} else {
    586 				sign = 1;
    587 			}
    588 
    589 			/* y * t */
    590 			CPYFPN(&fe->fe_f1, &y);
    591 			CPYFPN(&fe->fe_f2, &t);
    592 			r = fpu_mul(fe);
    593 
    594 			/*
    595 			 * x1 = x + y*t
    596 			 * x1 = x - y*t (if sign)
    597 			 */
    598 			CPYFPN(&fe->fe_f2, r);
    599 			if (sign)
    600 				fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign;
    601 			CPYFPN(&fe->fe_f1, &x);
    602 			r = fpu_add(fe);
    603 			CPYFPN(&x1, r);
    604 
    605 			/* x * t */
    606 			CPYFPN(&fe->fe_f1, &x);
    607 			CPYFPN(&fe->fe_f2, &t);
    608 			r = fpu_mul(fe);
    609 
    610 			/*
    611 			 * y = y + x*t
    612 			 * y = y - x*t (if sign)
    613 			 */
    614 			CPYFPN(&fe->fe_f2, r);
    615 			if (sign)
    616 				fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign;
    617 			CPYFPN(&fe->fe_f1, &y);
    618 			r = fpu_add(fe);
    619 			CPYFPN(&y, r);
    620 
    621 			/*
    622 			 * z = z + atanh_table[i] (if sign)
    623 			 * z = z - atanh_table[i]
    624 			 */
    625 			CPYFPN(&fe->fe_f1, &z);
    626 			sfpn_to_fpn(&fe->fe_f2, &atanh_table[i]);
    627 			if (!sign)
    628 				fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign;
    629 			r = fpu_add(fe);
    630 			CPYFPN(&z, r);
    631 
    632 			/* x = x1 */
    633 			CPYFPN(&x, &x1);
    634 
    635 			if (k > 0) {
    636 				k--;
    637 				break;
    638 			} else {
    639 				k = 3;
    640 			}
    641 		}
    642 
    643 		/* t /= 2 */
    644 		t.fp_exp--;
    645 	}
    646 
    647 	CPYFPN(x0, &x);
    648 	CPYFPN(y0, &y);
    649 	CPYFPN(z0, &z);
    650 }
    651 #endif /* CORDIC_BOOTSTRAP */
    652