1 1.4 isaki /* $NetBSD: fpu_cordic.c,v 1.4 2016/12/06 05:58:19 isaki Exp $ */ 2 1.1 isaki 3 1.1 isaki /* 4 1.1 isaki * Copyright (c) 2013 Tetsuya Isaki. All rights reserved. 5 1.1 isaki * 6 1.1 isaki * Redistribution and use in source and binary forms, with or without 7 1.1 isaki * modification, are permitted provided that the following conditions 8 1.1 isaki * are met: 9 1.1 isaki * 1. Redistributions of source code must retain the above copyright 10 1.1 isaki * notice, this list of conditions and the following disclaimer. 11 1.1 isaki * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 isaki * notice, this list of conditions and the following disclaimer in the 13 1.1 isaki * documentation and/or other materials provided with the distribution. 14 1.1 isaki * 15 1.1 isaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 1.1 isaki * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 1.1 isaki * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 1.1 isaki * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 1.1 isaki * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 1.1 isaki * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 1.1 isaki * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 1.1 isaki * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 1.1 isaki * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 1.1 isaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 1.1 isaki * SUCH DAMAGE. 26 1.1 isaki */ 27 1.1 isaki 28 1.1 isaki #include <sys/cdefs.h> 29 1.4 isaki __KERNEL_RCSID(0, "$NetBSD: fpu_cordic.c,v 1.4 2016/12/06 05:58:19 isaki Exp $"); 30 1.1 isaki 31 1.1 isaki #include <machine/ieee.h> 32 1.1 isaki 33 1.1 isaki #include "fpu_emulate.h" 34 1.1 isaki 35 1.1 isaki /* 36 1.1 isaki * sfpn = shoftened fp number; the idea is from fpu_log.c but not the same. 37 1.1 isaki * The most significant byte of sp_m0 is EXP (signed byte) and the rest 38 1.1 isaki * of sp_m0 is fp_mant[0]. 39 1.1 isaki */ 40 1.1 isaki struct sfpn { 41 1.1 isaki uint32_t sp_m0; 42 1.1 isaki uint32_t sp_m1; 43 1.1 isaki uint32_t sp_m2; 44 1.1 isaki }; 45 1.1 isaki 46 1.1 isaki #if defined(CORDIC_BOOTSTRAP) 47 1.1 isaki /* 48 1.1 isaki * This is a bootstrap code to generate a pre-calculated tables such as 49 1.4 isaki * atan_table[]. However, it's just for reference. 50 1.1 isaki * If you want to run the bootstrap, you will define CORDIC_BOOTSTRAP 51 1.1 isaki * and modify these files as a userland application. 52 1.1 isaki */ 53 1.1 isaki 54 1.1 isaki #include <stdio.h> 55 1.1 isaki #include <stdlib.h> 56 1.1 isaki #include <string.h> 57 1.1 isaki #include <float.h> 58 1.1 isaki 59 1.1 isaki static void prepare_cordic_const(struct fpemu *); 60 1.1 isaki static struct fpn *fpu_gain1_cordic(struct fpemu *); 61 1.2 isaki static struct fpn *fpu_atan_taylor(struct fpemu *); 62 1.1 isaki static void printf_fpn(const struct fpn *); 63 1.1 isaki static void printf_sfpn(const struct sfpn *); 64 1.1 isaki static void fpn_to_sfpn(struct sfpn *, const struct fpn *); 65 1.1 isaki 66 1.1 isaki static struct sfpn atan_table[EXT_FRACBITS]; 67 1.1 isaki static struct fpn inv_gain1; 68 1.3 isaki 69 1.1 isaki int 70 1.1 isaki main(int argc, char *argv[]) 71 1.1 isaki { 72 1.1 isaki struct fpemu dummyfe; 73 1.1 isaki int i; 74 1.1 isaki struct fpn fp; 75 1.1 isaki 76 1.1 isaki memset(&dummyfe, 0, sizeof(dummyfe)); 77 1.1 isaki prepare_cordic_const(&dummyfe); 78 1.1 isaki 79 1.1 isaki /* output as source code */ 80 1.1 isaki printf("static const struct sfpn atan_table[] = {\n"); 81 1.1 isaki for (i = 0; i < EXT_FRACBITS; i++) { 82 1.1 isaki printf("\t"); 83 1.1 isaki printf_sfpn(&atan_table[i]); 84 1.1 isaki printf(",\n"); 85 1.1 isaki } 86 1.1 isaki printf("};\n\n"); 87 1.1 isaki 88 1.1 isaki printf("const struct fpn fpu_cordic_inv_gain1 =\n\t"); 89 1.1 isaki printf_fpn(&inv_gain1); 90 1.1 isaki printf(";\n\n"); 91 1.1 isaki } 92 1.1 isaki 93 1.1 isaki /* 94 1.1 isaki * This routine uses fpu_const(), fpu_add(), fpu_div(), fpu_logn() 95 1.2 isaki * and fpu_atan_taylor() as bootstrap. 96 1.1 isaki */ 97 1.1 isaki static void 98 1.1 isaki prepare_cordic_const(struct fpemu *fe) 99 1.1 isaki { 100 1.1 isaki struct fpn t; 101 1.1 isaki struct fpn x; 102 1.1 isaki struct fpn *r; 103 1.1 isaki int i; 104 1.1 isaki 105 1.4 isaki /* atan_table */ 106 1.1 isaki fpu_const(&t, FPU_CONST_1); 107 1.1 isaki for (i = 0; i < EXT_FRACBITS; i++) { 108 1.1 isaki /* atan(t) */ 109 1.1 isaki CPYFPN(&fe->fe_f2, &t); 110 1.2 isaki r = fpu_atan_taylor(fe); 111 1.1 isaki fpn_to_sfpn(&atan_table[i], r); 112 1.1 isaki 113 1.1 isaki /* t /= 2 */ 114 1.1 isaki t.fp_exp--; 115 1.1 isaki } 116 1.1 isaki 117 1.1 isaki /* inv_gain1 = 1 / gain1cordic() */ 118 1.1 isaki r = fpu_gain1_cordic(fe); 119 1.1 isaki CPYFPN(&fe->fe_f2, r); 120 1.1 isaki fpu_const(&fe->fe_f1, FPU_CONST_1); 121 1.1 isaki r = fpu_div(fe); 122 1.1 isaki CPYFPN(&inv_gain1, r); 123 1.1 isaki } 124 1.1 isaki 125 1.1 isaki static struct fpn * 126 1.1 isaki fpu_gain1_cordic(struct fpemu *fe) 127 1.1 isaki { 128 1.1 isaki struct fpn x; 129 1.1 isaki struct fpn y; 130 1.1 isaki struct fpn z; 131 1.1 isaki struct fpn v; 132 1.1 isaki 133 1.1 isaki fpu_const(&x, FPU_CONST_1); 134 1.1 isaki fpu_const(&y, FPU_CONST_0); 135 1.1 isaki fpu_const(&z, FPU_CONST_0); 136 1.1 isaki CPYFPN(&v, &x); 137 1.1 isaki v.fp_sign = !v.fp_sign; 138 1.1 isaki 139 1.1 isaki fpu_cordit1(fe, &x, &y, &z, &v); 140 1.1 isaki CPYFPN(&fe->fe_f2, &x); 141 1.1 isaki return &fe->fe_f2; 142 1.1 isaki } 143 1.1 isaki 144 1.1 isaki /* 145 1.1 isaki * arctan(x) = pi/4 (for |x| = 1) 146 1.1 isaki * 147 1.1 isaki * x^3 x^5 x^7 148 1.1 isaki * arctan(x) = x - --- + --- - --- + ... (for |x| < 1) 149 1.1 isaki * 3 5 7 150 1.1 isaki */ 151 1.1 isaki static struct fpn * 152 1.2 isaki fpu_atan_taylor(struct fpemu *fe) 153 1.1 isaki { 154 1.1 isaki struct fpn res; 155 1.1 isaki struct fpn x2; 156 1.1 isaki struct fpn s0; 157 1.1 isaki struct fpn *s1; 158 1.1 isaki struct fpn *r; 159 1.1 isaki uint32_t k; 160 1.1 isaki 161 1.1 isaki /* arctan(1) is pi/4 */ 162 1.1 isaki if (fe->fe_f2.fp_exp == 0) { 163 1.1 isaki fpu_const(&fe->fe_f2, FPU_CONST_PI); 164 1.1 isaki fe->fe_f2.fp_exp -= 2; 165 1.1 isaki return &fe->fe_f2; 166 1.1 isaki } 167 1.1 isaki 168 1.1 isaki /* s0 := x */ 169 1.1 isaki CPYFPN(&s0, &fe->fe_f2); 170 1.1 isaki 171 1.1 isaki /* res := x */ 172 1.1 isaki CPYFPN(&res, &fe->fe_f2); 173 1.1 isaki 174 1.1 isaki /* x2 := x * x */ 175 1.1 isaki CPYFPN(&fe->fe_f1, &fe->fe_f2); 176 1.1 isaki r = fpu_mul(fe); 177 1.1 isaki CPYFPN(&x2, r); 178 1.1 isaki 179 1.1 isaki k = 3; 180 1.1 isaki for (;;) { 181 1.1 isaki /* s1 := -s0 * x2 */ 182 1.1 isaki CPYFPN(&fe->fe_f1, &s0); 183 1.1 isaki CPYFPN(&fe->fe_f2, &x2); 184 1.1 isaki s1 = fpu_mul(fe); 185 1.1 isaki s1->fp_sign ^= 1; 186 1.1 isaki CPYFPN(&fe->fe_f1, s1); 187 1.1 isaki 188 1.1 isaki /* s0 := s1 for next loop */ 189 1.1 isaki CPYFPN(&s0, s1); 190 1.1 isaki 191 1.1 isaki /* s1 := s1 / k */ 192 1.1 isaki fpu_explode(fe, &fe->fe_f2, FTYPE_LNG, &k); 193 1.1 isaki s1 = fpu_div(fe); 194 1.1 isaki 195 1.1 isaki /* break if s1 is enough small */ 196 1.1 isaki if (ISZERO(s1)) 197 1.1 isaki break; 198 1.1 isaki if (res.fp_exp - s1->fp_exp >= FP_NMANT) 199 1.1 isaki break; 200 1.1 isaki 201 1.1 isaki /* res += s1 */ 202 1.1 isaki CPYFPN(&fe->fe_f2, s1); 203 1.1 isaki CPYFPN(&fe->fe_f1, &res); 204 1.1 isaki r = fpu_add(fe); 205 1.1 isaki CPYFPN(&res, r); 206 1.1 isaki 207 1.1 isaki k += 2; 208 1.1 isaki } 209 1.1 isaki 210 1.1 isaki CPYFPN(&fe->fe_f2, &res); 211 1.1 isaki return &fe->fe_f2; 212 1.1 isaki } 213 1.1 isaki 214 1.1 isaki static void 215 1.1 isaki printf_fpn(const struct fpn *fp) 216 1.1 isaki { 217 1.1 isaki printf("{ %d, %d, %3d, %d, { 0x%08x, 0x%08x, 0x%08x, }, }", 218 1.1 isaki fp->fp_class, fp->fp_sign, fp->fp_exp, fp->fp_sticky ? 1 : 0, 219 1.1 isaki fp->fp_mant[0], fp->fp_mant[1], fp->fp_mant[2]); 220 1.1 isaki } 221 1.1 isaki 222 1.1 isaki static void 223 1.1 isaki printf_sfpn(const struct sfpn *sp) 224 1.1 isaki { 225 1.1 isaki printf("{ 0x%08x, 0x%08x, 0x%08x, }", 226 1.1 isaki sp->sp_m0, sp->sp_m1, sp->sp_m2); 227 1.1 isaki } 228 1.1 isaki 229 1.1 isaki static void 230 1.1 isaki fpn_to_sfpn(struct sfpn *sp, const struct fpn *fp) 231 1.1 isaki { 232 1.1 isaki sp->sp_m0 = (fp->fp_exp << 24) | fp->fp_mant[0]; 233 1.1 isaki sp->sp_m1 = fp->fp_mant[1]; 234 1.1 isaki sp->sp_m2 = fp->fp_mant[2]; 235 1.1 isaki } 236 1.1 isaki 237 1.1 isaki #else /* CORDIC_BOOTSTRAP */ 238 1.1 isaki 239 1.1 isaki static const struct sfpn atan_table[] = { 240 1.1 isaki { 0xff06487e, 0xd5110b46, 0x11a80000, }, 241 1.1 isaki { 0xfe076b19, 0xc1586ed3, 0xda2b7f0d, }, 242 1.1 isaki { 0xfd07d6dd, 0x7e4b2037, 0x58ab6e33, }, 243 1.1 isaki { 0xfc07f56e, 0xa6ab0bdb, 0x719644b5, }, 244 1.1 isaki { 0xfb07fd56, 0xedcb3f7a, 0x71b65937, }, 245 1.1 isaki { 0xfa07ff55, 0x6eea5d89, 0x2a13bce7, }, 246 1.1 isaki { 0xf907ffd5, 0x56eedca6, 0xaddf3c5f, }, 247 1.1 isaki { 0xf807fff5, 0x556eeea5, 0xcb403117, }, 248 1.1 isaki { 0xf707fffd, 0x5556eeed, 0xca5d8956, }, 249 1.1 isaki { 0xf607ffff, 0x55556eee, 0xea5ca6ab, }, 250 1.1 isaki { 0xf507ffff, 0xd55556ee, 0xeedca5c8, }, 251 1.1 isaki { 0xf407ffff, 0xf555556e, 0xeeeea5c8, }, 252 1.1 isaki { 0xf307ffff, 0xfd555556, 0xeeeeedc8, }, 253 1.1 isaki { 0xf207ffff, 0xff555555, 0x6eeeeee8, }, 254 1.1 isaki { 0xf107ffff, 0xffd55555, 0x56eeeeed, }, 255 1.1 isaki { 0xf007ffff, 0xfff55555, 0x556eeeed, }, 256 1.1 isaki { 0xef07ffff, 0xfffd5555, 0x5556eeed, }, 257 1.1 isaki { 0xee07ffff, 0xffff5555, 0x55556eed, }, 258 1.1 isaki { 0xed07ffff, 0xffffd555, 0x555556ed, }, 259 1.1 isaki { 0xec07ffff, 0xfffff555, 0x5555556d, }, 260 1.1 isaki { 0xeb07ffff, 0xfffffd55, 0x55555555, }, 261 1.1 isaki { 0xea07ffff, 0xffffff55, 0x55555554, }, 262 1.1 isaki { 0xe907ffff, 0xffffffd5, 0x55555554, }, 263 1.1 isaki { 0xe807ffff, 0xfffffff5, 0x55555554, }, 264 1.1 isaki { 0xe707ffff, 0xfffffffd, 0x55555554, }, 265 1.1 isaki { 0xe607ffff, 0xffffffff, 0x55555554, }, 266 1.1 isaki { 0xe507ffff, 0xffffffff, 0xd5555554, }, 267 1.1 isaki { 0xe407ffff, 0xffffffff, 0xf5555554, }, 268 1.1 isaki { 0xe307ffff, 0xffffffff, 0xfd555554, }, 269 1.1 isaki { 0xe207ffff, 0xffffffff, 0xff555554, }, 270 1.1 isaki { 0xe107ffff, 0xffffffff, 0xffd55554, }, 271 1.1 isaki { 0xe007ffff, 0xffffffff, 0xfff55554, }, 272 1.1 isaki { 0xdf07ffff, 0xffffffff, 0xfffd5554, }, 273 1.1 isaki { 0xde07ffff, 0xffffffff, 0xffff5554, }, 274 1.1 isaki { 0xdd07ffff, 0xffffffff, 0xffffd554, }, 275 1.1 isaki { 0xdc07ffff, 0xffffffff, 0xfffff554, }, 276 1.1 isaki { 0xdb07ffff, 0xffffffff, 0xfffffd54, }, 277 1.1 isaki { 0xda07ffff, 0xffffffff, 0xffffff54, }, 278 1.1 isaki { 0xd907ffff, 0xffffffff, 0xffffffd4, }, 279 1.1 isaki { 0xd807ffff, 0xffffffff, 0xfffffff4, }, 280 1.1 isaki { 0xd707ffff, 0xffffffff, 0xfffffffc, }, 281 1.1 isaki { 0xd7040000, 0x00000000, 0x00000000, }, 282 1.1 isaki { 0xd6040000, 0x00000000, 0x00000000, }, 283 1.1 isaki { 0xd5040000, 0x00000000, 0x00000000, }, 284 1.1 isaki { 0xd4040000, 0x00000000, 0x00000000, }, 285 1.1 isaki { 0xd3040000, 0x00000000, 0x00000000, }, 286 1.1 isaki { 0xd2040000, 0x00000000, 0x00000000, }, 287 1.1 isaki { 0xd1040000, 0x00000000, 0x00000000, }, 288 1.1 isaki { 0xd0040000, 0x00000000, 0x00000000, }, 289 1.1 isaki { 0xcf040000, 0x00000000, 0x00000000, }, 290 1.1 isaki { 0xce040000, 0x00000000, 0x00000000, }, 291 1.1 isaki { 0xcd040000, 0x00000000, 0x00000000, }, 292 1.1 isaki { 0xcc040000, 0x00000000, 0x00000000, }, 293 1.1 isaki { 0xcb040000, 0x00000000, 0x00000000, }, 294 1.1 isaki { 0xca040000, 0x00000000, 0x00000000, }, 295 1.1 isaki { 0xc9040000, 0x00000000, 0x00000000, }, 296 1.1 isaki { 0xc8040000, 0x00000000, 0x00000000, }, 297 1.1 isaki { 0xc7040000, 0x00000000, 0x00000000, }, 298 1.1 isaki { 0xc6040000, 0x00000000, 0x00000000, }, 299 1.1 isaki { 0xc5040000, 0x00000000, 0x00000000, }, 300 1.1 isaki { 0xc4040000, 0x00000000, 0x00000000, }, 301 1.1 isaki { 0xc3040000, 0x00000000, 0x00000000, }, 302 1.1 isaki { 0xc2040000, 0x00000000, 0x00000000, }, 303 1.1 isaki { 0xc1040000, 0x00000000, 0x00000000, }, 304 1.1 isaki }; 305 1.1 isaki 306 1.1 isaki const struct fpn fpu_cordic_inv_gain1 = 307 1.1 isaki { 1, 0, -1, 1, { 0x0004dba7, 0x6d421af2, 0xd33fafd1, }, }; 308 1.1 isaki 309 1.1 isaki #endif /* CORDIC_BOOTSTRAP */ 310 1.1 isaki 311 1.1 isaki static inline void 312 1.1 isaki sfpn_to_fpn(struct fpn *fp, const struct sfpn *s) 313 1.1 isaki { 314 1.1 isaki fp->fp_class = FPC_NUM; 315 1.1 isaki fp->fp_sign = 0; 316 1.1 isaki fp->fp_sticky = 0; 317 1.1 isaki fp->fp_exp = s->sp_m0 >> 24; 318 1.1 isaki if (fp->fp_exp & 0x80) { 319 1.1 isaki fp->fp_exp |= 0xffffff00; 320 1.1 isaki } 321 1.1 isaki fp->fp_mant[0] = s->sp_m0 & 0x000fffff; 322 1.1 isaki fp->fp_mant[1] = s->sp_m1; 323 1.1 isaki fp->fp_mant[2] = s->sp_m2; 324 1.1 isaki } 325 1.1 isaki 326 1.1 isaki void 327 1.1 isaki fpu_cordit1(struct fpemu *fe, struct fpn *x0, struct fpn *y0, struct fpn *z0, 328 1.1 isaki const struct fpn *vecmode) 329 1.1 isaki { 330 1.1 isaki struct fpn t; 331 1.1 isaki struct fpn x; 332 1.1 isaki struct fpn y; 333 1.1 isaki struct fpn z; 334 1.1 isaki struct fpn *r; 335 1.1 isaki int i; 336 1.1 isaki int sign; 337 1.1 isaki 338 1.1 isaki fpu_const(&t, FPU_CONST_1); 339 1.1 isaki CPYFPN(&x, x0); 340 1.1 isaki CPYFPN(&y, y0); 341 1.1 isaki CPYFPN(&z, z0); 342 1.1 isaki 343 1.1 isaki for (i = 0; i < EXT_FRACBITS; i++) { 344 1.1 isaki struct fpn x1; 345 1.1 isaki 346 1.1 isaki /* y < vecmode */ 347 1.1 isaki CPYFPN(&fe->fe_f1, &y); 348 1.1 isaki CPYFPN(&fe->fe_f2, vecmode); 349 1.1 isaki fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; 350 1.1 isaki r = fpu_add(fe); 351 1.1 isaki 352 1.1 isaki if ((vecmode->fp_sign == 0 && r->fp_sign) || 353 1.1 isaki (vecmode->fp_sign && z.fp_sign == 0)) { 354 1.1 isaki sign = 1; 355 1.1 isaki } else { 356 1.1 isaki sign = 0; 357 1.1 isaki } 358 1.1 isaki 359 1.1 isaki /* y * t */ 360 1.1 isaki CPYFPN(&fe->fe_f1, &y); 361 1.1 isaki CPYFPN(&fe->fe_f2, &t); 362 1.1 isaki r = fpu_mul(fe); 363 1.1 isaki 364 1.1 isaki /* 365 1.1 isaki * x1 = x - y*t (if sign) 366 1.1 isaki * x1 = x + y*t 367 1.1 isaki */ 368 1.1 isaki CPYFPN(&fe->fe_f2, r); 369 1.1 isaki if (sign) 370 1.1 isaki fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; 371 1.1 isaki CPYFPN(&fe->fe_f1, &x); 372 1.1 isaki r = fpu_add(fe); 373 1.1 isaki CPYFPN(&x1, r); 374 1.1 isaki 375 1.1 isaki /* x * t */ 376 1.1 isaki CPYFPN(&fe->fe_f1, &x); 377 1.1 isaki CPYFPN(&fe->fe_f2, &t); 378 1.1 isaki r = fpu_mul(fe); 379 1.1 isaki 380 1.1 isaki /* 381 1.1 isaki * y = y + x*t (if sign) 382 1.1 isaki * y = y - x*t 383 1.1 isaki */ 384 1.1 isaki CPYFPN(&fe->fe_f2, r); 385 1.1 isaki if (!sign) 386 1.1 isaki fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; 387 1.1 isaki CPYFPN(&fe->fe_f1, &y); 388 1.1 isaki r = fpu_add(fe); 389 1.1 isaki CPYFPN(&y, r); 390 1.1 isaki 391 1.1 isaki /* 392 1.1 isaki * z = z - atan_table[i] (if sign) 393 1.1 isaki * z = z + atan_table[i] 394 1.1 isaki */ 395 1.1 isaki CPYFPN(&fe->fe_f1, &z); 396 1.1 isaki sfpn_to_fpn(&fe->fe_f2, &atan_table[i]); 397 1.1 isaki if (sign) 398 1.1 isaki fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; 399 1.1 isaki r = fpu_add(fe); 400 1.1 isaki CPYFPN(&z, r); 401 1.1 isaki 402 1.1 isaki /* x = x1 */ 403 1.1 isaki CPYFPN(&x, &x1); 404 1.1 isaki 405 1.1 isaki /* t /= 2 */ 406 1.1 isaki t.fp_exp--; 407 1.1 isaki } 408 1.1 isaki 409 1.1 isaki CPYFPN(x0, &x); 410 1.1 isaki CPYFPN(y0, &y); 411 1.1 isaki CPYFPN(z0, &z); 412 1.1 isaki } 413