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