|
|
1.1 ! root 1: /* $NetBSD: fpu_cordic.c,v 1.4 2016/12/06 05:58:19 isaki 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 "fpu_emulate.h" ! 29: ! 30: /* ! 31: * sfpn = shoftened fp number; the idea is from fpu_log.c but not the same. ! 32: * The most significant byte of sp_m0 is EXP (signed byte) and the rest ! 33: * of sp_m0 is fp_mant[0]. ! 34: */ ! 35: struct sfpn { ! 36: uint32_t sp_m0; ! 37: uint32_t sp_m1; ! 38: uint32_t sp_m2; ! 39: }; ! 40: ! 41: #if defined(CORDIC_BOOTSTRAP) ! 42: /* ! 43: * 事前計算しておくテーブルを出力する。 ! 44: * 出力されたテーブルを #else 側に手動で貼り付ける。 ! 45: * ! 46: * % cc -c fpu_add.c ! 47: * % cc -c fpu_div.c ! 48: * % cc -c fpu_exp.c ! 49: * % cc -c fpu_explode.c ! 50: * % cc -c fpu_fmovecr.c ! 51: * % cc -c fpu_implode.c ! 52: * % cc -c fpu_log.c ! 53: * % cc -c fpu_mul.c ! 54: * % cc -c fpu_subr.c ! 55: * % cc -c fpu_cordic.c -DCORDIC_BOOTSTRAP ! 56: * % cc -o bootstrap_cordic *.o ! 57: * % ./bootstrap_cordic ! 58: */ ! 59: /* ! 60: * This is a bootstrap code to generate a pre-calculated tables such as ! 61: * atan_table[]. However, it's just for reference. ! 62: * If you want to run the bootstrap, you will define CORDIC_BOOTSTRAP ! 63: * and modify these files as a userland application. ! 64: */ ! 65: ! 66: #include <stdio.h> ! 67: #include <stdlib.h> ! 68: #include <string.h> ! 69: #include <float.h> ! 70: ! 71: static void prepare_cordic_const(struct fpemu *); ! 72: static struct fpn *fpu_gain1_cordic(struct fpemu *); ! 73: static struct fpn *fpu_atan_taylor(struct fpemu *); ! 74: static void printf_fpn(const struct fpn *); ! 75: static void printf_sfpn(const struct sfpn *); ! 76: static void fpn_to_sfpn(struct sfpn *, const struct fpn *); ! 77: ! 78: static struct sfpn atan_table[EXT_FRACBITS]; ! 79: static struct fpn inv_gain1; ! 80: ! 81: int ! 82: main(int argc, char *argv[]) ! 83: { ! 84: struct fpemu dummyfe; ! 85: int i; ! 86: struct fpn fp; ! 87: ! 88: memset(&dummyfe, 0, sizeof(dummyfe)); ! 89: prepare_cordic_const(&dummyfe); ! 90: ! 91: /* output as source code */ ! 92: printf("static const struct sfpn atan_table[] = {\n"); ! 93: for (i = 0; i < EXT_FRACBITS; i++) { ! 94: printf("\t"); ! 95: printf_sfpn(&atan_table[i]); ! 96: printf(",\n"); ! 97: } ! 98: printf("};\n\n"); ! 99: ! 100: printf("const struct fpn fpu_cordic_inv_gain1 =\n\t"); ! 101: printf_fpn(&inv_gain1); ! 102: printf(";\n\n"); ! 103: } ! 104: ! 105: /* ! 106: * This routine uses fpu_const(), fpu_add(), fpu_div(), fpu_logn() ! 107: * and fpu_atan_taylor() as bootstrap. ! 108: */ ! 109: static void ! 110: prepare_cordic_const(struct fpemu *fe) ! 111: { ! 112: struct fpn t; ! 113: struct fpn x; ! 114: struct fpn *r; ! 115: int i; ! 116: ! 117: /* atan_table */ ! 118: fpu_const(&t, FPU_CONST_1); ! 119: for (i = 0; i < EXT_FRACBITS; i++) { ! 120: /* atan(t) */ ! 121: CPYFPN(&fe->fe_f2, &t); ! 122: r = fpu_atan_taylor(fe); ! 123: fpn_to_sfpn(&atan_table[i], r); ! 124: ! 125: /* t /= 2 */ ! 126: t.fp_exp--; ! 127: } ! 128: ! 129: /* inv_gain1 = 1 / gain1cordic() */ ! 130: r = fpu_gain1_cordic(fe); ! 131: CPYFPN(&fe->fe_f2, r); ! 132: fpu_const(&fe->fe_f1, FPU_CONST_1); ! 133: r = fpu_div(fe); ! 134: CPYFPN(&inv_gain1, r); ! 135: } ! 136: ! 137: static struct fpn * ! 138: fpu_gain1_cordic(struct fpemu *fe) ! 139: { ! 140: struct fpn x; ! 141: struct fpn y; ! 142: struct fpn z; ! 143: struct fpn v; ! 144: ! 145: fpu_const(&x, FPU_CONST_1); ! 146: fpu_const(&y, FPU_CONST_0); ! 147: fpu_const(&z, FPU_CONST_0); ! 148: CPYFPN(&v, &x); ! 149: v.fp_sign = !v.fp_sign; ! 150: ! 151: fpu_cordit1(fe, &x, &y, &z, &v); ! 152: CPYFPN(&fe->fe_f2, &x); ! 153: return &fe->fe_f2; ! 154: } ! 155: ! 156: /* ! 157: * arctan(x) = pi/4 (for |x| = 1) ! 158: * ! 159: * x^3 x^5 x^7 ! 160: * arctan(x) = x - --- + --- - --- + ... (for |x| < 1) ! 161: * 3 5 7 ! 162: */ ! 163: static struct fpn * ! 164: fpu_atan_taylor(struct fpemu *fe) ! 165: { ! 166: struct fpn res; ! 167: struct fpn x2; ! 168: struct fpn s0; ! 169: struct fpn *s1; ! 170: struct fpn *r; ! 171: uint32_t k; ! 172: ! 173: /* arctan(1) is pi/4 */ ! 174: if (fe->fe_f2.fp_exp == 0) { ! 175: fpu_const(&fe->fe_f2, FPU_CONST_PI); ! 176: fe->fe_f2.fp_exp -= 2; ! 177: return &fe->fe_f2; ! 178: } ! 179: ! 180: /* s0 := x */ ! 181: CPYFPN(&s0, &fe->fe_f2); ! 182: ! 183: /* res := x */ ! 184: CPYFPN(&res, &fe->fe_f2); ! 185: ! 186: /* x2 := x * x */ ! 187: CPYFPN(&fe->fe_f1, &fe->fe_f2); ! 188: r = fpu_mul(fe); ! 189: CPYFPN(&x2, r); ! 190: ! 191: k = 3; ! 192: for (;;) { ! 193: /* s1 := -s0 * x2 */ ! 194: CPYFPN(&fe->fe_f1, &s0); ! 195: CPYFPN(&fe->fe_f2, &x2); ! 196: s1 = fpu_mul(fe); ! 197: s1->fp_sign ^= 1; ! 198: CPYFPN(&fe->fe_f1, s1); ! 199: ! 200: /* s0 := s1 for next loop */ ! 201: CPYFPN(&s0, s1); ! 202: ! 203: /* s1 := s1 / k */ ! 204: fpu_explode(fe, &fe->fe_f2, FTYPE_LNG, &k); ! 205: s1 = fpu_div(fe); ! 206: ! 207: /* break if s1 is enough small */ ! 208: if (ISZERO(s1)) ! 209: break; ! 210: if (res.fp_exp - s1->fp_exp >= FP_NMANT) ! 211: break; ! 212: ! 213: /* res += s1 */ ! 214: CPYFPN(&fe->fe_f2, s1); ! 215: CPYFPN(&fe->fe_f1, &res); ! 216: r = fpu_add(fe); ! 217: CPYFPN(&res, r); ! 218: ! 219: k += 2; ! 220: } ! 221: ! 222: CPYFPN(&fe->fe_f2, &res); ! 223: return &fe->fe_f2; ! 224: } ! 225: ! 226: static void ! 227: printf_fpn(const struct fpn *fp) ! 228: { ! 229: printf("{ %d, %d, %3d, %d, { 0x%08x, 0x%08x, 0x%08x, }, }", ! 230: fp->fp_class, fp->fp_sign, fp->fp_exp, fp->fp_sticky ? 1 : 0, ! 231: fp->fp_mant[0], fp->fp_mant[1], fp->fp_mant[2]); ! 232: } ! 233: ! 234: static void ! 235: printf_sfpn(const struct sfpn *sp) ! 236: { ! 237: printf("{ 0x%08x, 0x%08x, 0x%08x, }", ! 238: sp->sp_m0, sp->sp_m1, sp->sp_m2); ! 239: } ! 240: ! 241: static void ! 242: fpn_to_sfpn(struct sfpn *sp, const struct fpn *fp) ! 243: { ! 244: sp->sp_m0 = (fp->fp_exp << 24) | fp->fp_mant[0]; ! 245: sp->sp_m1 = fp->fp_mant[1]; ! 246: sp->sp_m2 = fp->fp_mant[2]; ! 247: } ! 248: ! 249: #else /* CORDIC_BOOTSTRAP */ ! 250: ! 251: static const struct sfpn atan_table[] = { ! 252: { 0xff06487e, 0xd5110b46, 0x11a80000, }, ! 253: { 0xfe076b19, 0xc1586ed3, 0xda2b7f0d, }, ! 254: { 0xfd07d6dd, 0x7e4b2037, 0x58ab6e33, }, ! 255: { 0xfc07f56e, 0xa6ab0bdb, 0x719644b5, }, ! 256: { 0xfb07fd56, 0xedcb3f7a, 0x71b65937, }, ! 257: { 0xfa07ff55, 0x6eea5d89, 0x2a13bce7, }, ! 258: { 0xf907ffd5, 0x56eedca6, 0xaddf3c5f, }, ! 259: { 0xf807fff5, 0x556eeea5, 0xcb403117, }, ! 260: { 0xf707fffd, 0x5556eeed, 0xca5d8956, }, ! 261: { 0xf607ffff, 0x55556eee, 0xea5ca6ab, }, ! 262: { 0xf507ffff, 0xd55556ee, 0xeedca5c8, }, ! 263: { 0xf407ffff, 0xf555556e, 0xeeeea5c8, }, ! 264: { 0xf307ffff, 0xfd555556, 0xeeeeedc8, }, ! 265: { 0xf207ffff, 0xff555555, 0x6eeeeee8, }, ! 266: { 0xf107ffff, 0xffd55555, 0x56eeeeed, }, ! 267: { 0xf007ffff, 0xfff55555, 0x556eeeed, }, ! 268: { 0xef07ffff, 0xfffd5555, 0x5556eeed, }, ! 269: { 0xee07ffff, 0xffff5555, 0x55556eed, }, ! 270: { 0xed07ffff, 0xffffd555, 0x555556ed, }, ! 271: { 0xec07ffff, 0xfffff555, 0x5555556d, }, ! 272: { 0xeb07ffff, 0xfffffd55, 0x55555555, }, ! 273: { 0xea07ffff, 0xffffff55, 0x55555554, }, ! 274: { 0xe907ffff, 0xffffffd5, 0x55555554, }, ! 275: { 0xe807ffff, 0xfffffff5, 0x55555554, }, ! 276: { 0xe707ffff, 0xfffffffd, 0x55555554, }, ! 277: { 0xe607ffff, 0xffffffff, 0x55555554, }, ! 278: { 0xe507ffff, 0xffffffff, 0xd5555554, }, ! 279: { 0xe407ffff, 0xffffffff, 0xf5555554, }, ! 280: { 0xe307ffff, 0xffffffff, 0xfd555554, }, ! 281: { 0xe207ffff, 0xffffffff, 0xff555554, }, ! 282: { 0xe107ffff, 0xffffffff, 0xffd55554, }, ! 283: { 0xe007ffff, 0xffffffff, 0xfff55554, }, ! 284: { 0xdf07ffff, 0xffffffff, 0xfffd5554, }, ! 285: { 0xde07ffff, 0xffffffff, 0xffff5554, }, ! 286: { 0xdd07ffff, 0xffffffff, 0xffffd554, }, ! 287: { 0xdc07ffff, 0xffffffff, 0xfffff554, }, ! 288: { 0xdb07ffff, 0xffffffff, 0xfffffd54, }, ! 289: { 0xda07ffff, 0xffffffff, 0xffffff54, }, ! 290: { 0xd907ffff, 0xffffffff, 0xffffffd4, }, ! 291: { 0xd807ffff, 0xffffffff, 0xfffffff4, }, ! 292: { 0xd707ffff, 0xffffffff, 0xfffffffc, }, ! 293: { 0xd7040000, 0x00000000, 0x00000000, }, ! 294: { 0xd6040000, 0x00000000, 0x00000000, }, ! 295: { 0xd5040000, 0x00000000, 0x00000000, }, ! 296: { 0xd4040000, 0x00000000, 0x00000000, }, ! 297: { 0xd3040000, 0x00000000, 0x00000000, }, ! 298: { 0xd2040000, 0x00000000, 0x00000000, }, ! 299: { 0xd1040000, 0x00000000, 0x00000000, }, ! 300: { 0xd0040000, 0x00000000, 0x00000000, }, ! 301: { 0xcf040000, 0x00000000, 0x00000000, }, ! 302: { 0xce040000, 0x00000000, 0x00000000, }, ! 303: { 0xcd040000, 0x00000000, 0x00000000, }, ! 304: { 0xcc040000, 0x00000000, 0x00000000, }, ! 305: { 0xcb040000, 0x00000000, 0x00000000, }, ! 306: { 0xca040000, 0x00000000, 0x00000000, }, ! 307: { 0xc9040000, 0x00000000, 0x00000000, }, ! 308: { 0xc8040000, 0x00000000, 0x00000000, }, ! 309: { 0xc7040000, 0x00000000, 0x00000000, }, ! 310: { 0xc6040000, 0x00000000, 0x00000000, }, ! 311: { 0xc5040000, 0x00000000, 0x00000000, }, ! 312: { 0xc4040000, 0x00000000, 0x00000000, }, ! 313: { 0xc3040000, 0x00000000, 0x00000000, }, ! 314: { 0xc2040000, 0x00000000, 0x00000000, }, ! 315: { 0xc1040000, 0x00000000, 0x00000000, }, ! 316: }; ! 317: ! 318: const struct fpn fpu_cordic_inv_gain1 = ! 319: { 1, 0, -1, 1, { 0x0004dba7, 0x6d421af2, 0xd33fafd1, }, }; ! 320: ! 321: #endif /* CORDIC_BOOTSTRAP */ ! 322: ! 323: static inline void ! 324: sfpn_to_fpn(struct fpn *fp, const struct sfpn *s) ! 325: { ! 326: fp->fp_class = FPC_NUM; ! 327: fp->fp_sign = 0; ! 328: fp->fp_sticky = 0; ! 329: fp->fp_exp = s->sp_m0 >> 24; ! 330: if (fp->fp_exp & 0x80) { ! 331: fp->fp_exp |= 0xffffff00; ! 332: } ! 333: fp->fp_mant[0] = s->sp_m0 & 0x000fffff; ! 334: fp->fp_mant[1] = s->sp_m1; ! 335: fp->fp_mant[2] = s->sp_m2; ! 336: } ! 337: ! 338: void ! 339: fpu_cordit1(struct fpemu *fe, struct fpn *x0, struct fpn *y0, struct fpn *z0, ! 340: const struct fpn *vecmode) ! 341: { ! 342: struct fpn t; ! 343: struct fpn x; ! 344: struct fpn y; ! 345: struct fpn z; ! 346: struct fpn *r; ! 347: int i; ! 348: int sign; ! 349: ! 350: fpu_const(&t, FPU_CONST_1); ! 351: CPYFPN(&x, x0); ! 352: CPYFPN(&y, y0); ! 353: CPYFPN(&z, z0); ! 354: ! 355: for (i = 0; i < EXT_FRACBITS; i++) { ! 356: struct fpn x1; ! 357: ! 358: /* y < vecmode */ ! 359: CPYFPN(&fe->fe_f1, &y); ! 360: CPYFPN(&fe->fe_f2, vecmode); ! 361: fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; ! 362: r = fpu_add(fe); ! 363: ! 364: if ((vecmode->fp_sign == 0 && r->fp_sign) || ! 365: (vecmode->fp_sign && z.fp_sign == 0)) { ! 366: sign = 1; ! 367: } else { ! 368: sign = 0; ! 369: } ! 370: ! 371: /* y * t */ ! 372: CPYFPN(&fe->fe_f1, &y); ! 373: CPYFPN(&fe->fe_f2, &t); ! 374: r = fpu_mul(fe); ! 375: ! 376: /* ! 377: * x1 = x - y*t (if sign) ! 378: * x1 = x + y*t ! 379: */ ! 380: CPYFPN(&fe->fe_f2, r); ! 381: if (sign) ! 382: fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; ! 383: CPYFPN(&fe->fe_f1, &x); ! 384: r = fpu_add(fe); ! 385: CPYFPN(&x1, r); ! 386: ! 387: /* x * t */ ! 388: CPYFPN(&fe->fe_f1, &x); ! 389: CPYFPN(&fe->fe_f2, &t); ! 390: r = fpu_mul(fe); ! 391: ! 392: /* ! 393: * y = y + x*t (if sign) ! 394: * y = y - x*t ! 395: */ ! 396: CPYFPN(&fe->fe_f2, r); ! 397: if (!sign) ! 398: fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; ! 399: CPYFPN(&fe->fe_f1, &y); ! 400: r = fpu_add(fe); ! 401: CPYFPN(&y, r); ! 402: ! 403: /* ! 404: * z = z - atan_table[i] (if sign) ! 405: * z = z + atan_table[i] ! 406: */ ! 407: CPYFPN(&fe->fe_f1, &z); ! 408: sfpn_to_fpn(&fe->fe_f2, &atan_table[i]); ! 409: if (sign) ! 410: fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; ! 411: r = fpu_add(fe); ! 412: CPYFPN(&z, r); ! 413: ! 414: /* x = x1 */ ! 415: CPYFPN(&x, &x1); ! 416: ! 417: /* t /= 2 */ ! 418: t.fp_exp--; ! 419: } ! 420: ! 421: CPYFPN(x0, &x); ! 422: CPYFPN(y0, &y); ! 423: CPYFPN(z0, &z); ! 424: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.