|
|
1.1 ! root 1: // ! 2: // XM6i ! 3: // Copyright (c) 2013 Y.Sugahara ! 4: // ! 5: // [ fpn → BCD 変換 ] ! 6: // ! 7: ! 8: #include "fpu_emulate.h" ! 9: #include "fpu_bcd.h" ! 10: #include <string.h> ! 11: #include <stdint.h> ! 12: #include <stdio.h> ! 13: #include <math.h> ! 14: #include <stdlib.h> ! 15: ! 16: //#define FPU_BCD_DEBUG ! 17: ! 18: #if defined(FPU_BCD_DEBUG) ! 19: #define DPRINTF(msg, ...) printf(msg, ## __VA_ARGS__) ! 20: #define dump(s, a) debug_dump(s, a) ! 21: #else ! 22: #define DPRINTF(msg, ...) /**/ ! 23: #define dump(s, a) /**/ ! 24: #endif ! 25: ! 26: static int fpu_bcd_iszero(const BCD *a); ! 27: static uint8_t fpu_bcd_shr(BCD *a); ! 28: static uint8_t fpu_bcd_shr_n(BCD *a, int n); ! 29: uint8_t fpu_bcd_shl(BCD *a); ! 30: static uint8_t fpu_bcd_shl_n(BCD *a, int n); ! 31: static uint8_t fpu_bcd_add_d(BCD *a, const BCD *b); ! 32: static void fpu_bcd_add_last_n(BCD *a, uint8_t n); ! 33: static void fpu_bcd_round_cy(BCD *a, uint8_t cy); ! 34: static void fpu_bcd_round(BCD *a); ! 35: static void fpu_bcd_add(BCD *a, const BCD *b); ! 36: static void fpu_bcd_mul(BCD *a, const BCD *b); ! 37: static void fpu_bcd_exp2(BCD *a, int n); ! 38: static int getbit(struct fpn *fp, int n); ! 39: static void fpu_itobcd(BCD *a, int x); ! 40: static void fpu_fpntobcd(BCD *res, struct fpn *fp); ! 41: ! 42: #if defined(FPU_BCD_DEBUG) ! 43: static void __attribute__((__unused__)) ! 44: debug_dump(const char *s, const BCD *a) ! 45: { ! 46: int i; ! 47: ! 48: printf("%10s ", s); ! 49: printf("e=%+5d ", a->e); ! 50: printf("%d.", a->d[0]); ! 51: for (i = 1; i < FPU_BCD_DIGIT; i++) { ! 52: printf("%d", a->d[i]); ! 53: } ! 54: printf("\n"); ! 55: } ! 56: #endif ! 57: ! 58: /* ! 59: * (a == 0) ! 60: */ ! 61: static int ! 62: fpu_bcd_iszero(const BCD *a) ! 63: { ! 64: int i; ! 65: for (i = 0; i < FPU_BCD_DIGIT; i++) { ! 66: if (a->d[i]) return 0; ! 67: } ! 68: return 1; ! 69: } ! 70: ! 71: /* ! 72: * a >>= 1 ! 73: * return: carry digit ! 74: */ ! 75: static uint8_t ! 76: fpu_bcd_shr(BCD *a) ! 77: { ! 78: int i; ! 79: uint8_t cy; ! 80: ! 81: cy = a->d[FPU_BCD_DIGIT - 1]; ! 82: for (i = FPU_BCD_DIGIT - 1; i >= 1; i--) { ! 83: a->d[i] = a->d[i - 1]; ! 84: } ! 85: a->d[0] = 0; ! 86: dump("shr", a); ! 87: return cy; ! 88: } ! 89: ! 90: /* ! 91: * a >>= n ! 92: */ ! 93: static uint8_t ! 94: fpu_bcd_shr_n(BCD *a, int n) ! 95: { ! 96: uint8_t cy; ! 97: int count; ! 98: ! 99: if (n <= 0) return 0; ! 100: count = FPU_BCD_DIGIT - n; ! 101: if (count < 0) { ! 102: memset(a->d, 0, FPU_BCD_DIGIT * sizeof(a->d[0])); ! 103: return 0; ! 104: } ! 105: cy = a->d[count]; ! 106: ! 107: memmove(&a->d[n], &a->d[0], count * sizeof(a->d[0])); ! 108: memset(&a->d[0], 0, n * sizeof(a->d[0])); ! 109: return cy; ! 110: } ! 111: ! 112: /* ! 113: * a <<= 1 ! 114: * return: carry digit ! 115: */ ! 116: /* 使われてないけど対称性のため残してある。どうすべ */ ! 117: uint8_t ! 118: fpu_bcd_shl(BCD *a) ! 119: { ! 120: int i; ! 121: uint8_t cy; ! 122: ! 123: cy = a->d[0]; ! 124: for (i = 0; i < FPU_BCD_DIGIT - 1; i++) { ! 125: a->d[i] = a->d[i + 1]; ! 126: } ! 127: a->d[FPU_BCD_DIGIT - 1] = 0; ! 128: dump("shl", a); ! 129: return cy; ! 130: } ! 131: ! 132: /* ! 133: * a <<= n ! 134: * return: carry digit ! 135: */ ! 136: static uint8_t ! 137: fpu_bcd_shl_n(BCD *a, int n) ! 138: { ! 139: uint8_t cy; ! 140: ! 141: if (n <= 0) ! 142: return 0; ! 143: if (n >= FPU_BCD_DIGIT) { ! 144: memset(a->d, 0, FPU_BCD_DIGIT * sizeof(a->d[0])); ! 145: return 0; ! 146: } ! 147: cy = a->d[n - 1]; ! 148: ! 149: memmove(&a->d[0], &a->d[n], (FPU_BCD_DIGIT - n) * sizeof(a->d[0])); ! 150: memset(&a->d[FPU_BCD_DIGIT - n], 0, n * sizeof(a->d[0])); ! 151: return cy; ! 152: } ! 153: ! 154: /* ! 155: * a = a + b ! 156: * add digit only ! 157: */ ! 158: static uint8_t ! 159: fpu_bcd_add_d(BCD *a, const BCD *b) ! 160: { ! 161: uint8_t cy = 0; ! 162: int i; ! 163: ! 164: for (i = FPU_BCD_DIGIT - 1; i >= 0; i--) { ! 165: a->d[i] = a->d[i] + b->d[i] + cy; ! 166: if (a->d[i] >= 10) { ! 167: a->d[i] -= 10; ! 168: cy = 1; ! 169: } else { ! 170: cy = 0; ! 171: } ! 172: } ! 173: return cy; ! 174: } ! 175: ! 176: /* ! 177: * a = a[last digit] + n ! 178: * for rounding ! 179: */ ! 180: static void ! 181: fpu_bcd_add_last_n(BCD *a, uint8_t n) ! 182: { ! 183: uint8_t cy = n; ! 184: int i; ! 185: ! 186: for (i = FPU_BCD_DIGIT - 1; i >= 0; i--) { ! 187: a->d[i] += cy; ! 188: if (a->d[i] >= 10) { ! 189: a->d[i] -= 10; ! 190: cy = 1; ! 191: } else { ! 192: cy = 0; ! 193: /* breakable because no more carry */ ! 194: break; ! 195: } ! 196: } ! 197: ! 198: if (cy) { ! 199: cy = fpu_bcd_shr(a); ! 200: a->d[0] = 1; ! 201: a->e++; ! 202: fpu_bcd_round_cy(a, cy); ! 203: } ! 204: dump("add_last_n", a); ! 205: } ! 206: ! 207: /* ! 208: * banker's rounding by carry ! 209: */ ! 210: static void ! 211: fpu_bcd_round_cy(BCD *a, uint8_t cy) ! 212: { ! 213: if (cy > 5 ! 214: || (cy == 5 && a->d[FPU_BCD_DIGIT - 1] % 2 != 0)) { ! 215: fpu_bcd_add_last_n(a, 1); ! 216: } ! 217: } ! 218: ! 219: /* ! 220: * rounding at last digit ! 221: */ ! 222: static void ! 223: fpu_bcd_round(BCD *a) ! 224: { ! 225: if (a->d[FPU_BCD_DIGIT - 1] >= 5) { ! 226: fpu_bcd_add_last_n(a, 10); ! 227: a->d[FPU_BCD_DIGIT - 1] = 0; ! 228: } ! 229: } ! 230: ! 231: /* ! 232: * a = a + b ! 233: */ ! 234: static void ! 235: fpu_bcd_add(BCD *a, const BCD *b) ! 236: { ! 237: uint8_t cy = 0; ! 238: BCD t0; ! 239: BCD *t = &t0; ! 240: ! 241: if (fpu_bcd_iszero(a)) { ! 242: *a = *b; ! 243: return; ! 244: } ! 245: if (fpu_bcd_iszero(b)) { ! 246: return; ! 247: } ! 248: ! 249: *t = *b; ! 250: ! 251: while (a->e != t->e) { ! 252: if (a->e > t->e) { ! 253: t->e++; ! 254: cy = fpu_bcd_shr(t); ! 255: } else if (a->e < t->e) { ! 256: a->e++; ! 257: cy = fpu_bcd_shr(a); ! 258: } ! 259: } ! 260: fpu_bcd_round_cy(a, cy); ! 261: ! 262: dump("add:a", a); ! 263: dump("add:t", t); ! 264: cy = fpu_bcd_add_d(a, t); ! 265: ! 266: if (cy) { ! 267: // last digit rounding ! 268: cy = fpu_bcd_shr(a); ! 269: a->d[0] = 1; ! 270: a->e++; ! 271: fpu_bcd_round_cy(a, cy); ! 272: } ! 273: dump("add", a); ! 274: } ! 275: ! 276: /* ! 277: * a = a * b ! 278: */ ! 279: static void ! 280: fpu_bcd_mul(BCD *a, const BCD *b) ! 281: { ! 282: /* need DIGIT * 2 + 1 for mul + cy */ ! 283: uint8_t t0[FPU_BCD_DIGIT * 2 + 1 + 1]; ! 284: uint8_t *t = &t0[1]; ! 285: int i, j, k; ! 286: ! 287: dump("mul:a", a); ! 288: dump("mul:b", b); ! 289: memset(t0, 0, sizeof(t0)); ! 290: ! 291: for (i = FPU_BCD_DIGIT - 1; i >= 0; i--) { ! 292: for (j = FPU_BCD_DIGIT - 1; j >= 0; j--) { ! 293: t[i + j] += a->d[i] * b->d[j]; ! 294: for (k = i + j; k >= 0; k--) { ! 295: if (t[k] >= 10) { ! 296: /* t[-1] available */ ! 297: t[k - 1] += t[k] / 10; ! 298: t[k] %= 10; ! 299: } else { ! 300: break; ! 301: } ! 302: } ! 303: } ! 304: } ! 305: ! 306: a->e = a->e + b->e; ! 307: if (t[-1]) { ! 308: a->e++; ! 309: /* copy 1 digit shifted */ ! 310: memcpy(a->d, &t[-1], sizeof(a->d)); ! 311: fpu_bcd_round_cy(a, t[FPU_BCD_DIGIT - 1]); ! 312: } else { ! 313: memcpy(a->d, t, sizeof(a->d)); ! 314: fpu_bcd_round_cy(a, t[FPU_BCD_DIGIT]); ! 315: } ! 316: dump("mul", a); ! 317: } ! 318: ! 319: /* ! 320: * a = pow(2, n) ! 321: */ ! 322: static void ! 323: fpu_bcd_exp2(BCD *a, int n) ! 324: { ! 325: BCD r0; ! 326: BCD *r = &r0; ! 327: int i; ! 328: #if defined(FPU_BCD_DEBUG) ! 329: int save_n = n; ! 330: #endif ! 331: DPRINTF("exp2 n=%d\n", n); ! 332: memset(a, 0, sizeof(*a)); ! 333: a->d[0] = 1; ! 334: ! 335: if (n == 0) { ! 336: } else { ! 337: memset(r, 0, sizeof(*r)); ! 338: if (n > 0) { ! 339: /* r = 2 */ ! 340: r->d[0] = 2; ! 341: } else { ! 342: n = -n; ! 343: /* r = 0.5 */ ! 344: r->e = -1; ! 345: r->d[0] = 5; ! 346: } ! 347: ! 348: for (i = 0; i < 32; i++) { ! 349: if (n & (1 << i)) { ! 350: n ^= (1 << i); ! 351: fpu_bcd_mul(a, r); ! 352: } ! 353: if (n == 0) break; ! 354: fpu_bcd_mul(r, r); ! 355: } ! 356: } ! 357: dump("exp2", a); ! 358: #if defined(__NetBSD__) /* とりあえず */ ! 359: DPRINTF("%18s %.*e\n", "pow", FPU_BCD_DIGIT-1, pow(2, save_n)); ! 360: #else ! 361: DPRINTF("%18s %.*Le\n", "powl", FPU_BCD_DIGIT-1, powl(2, save_n)); ! 362: #endif ! 363: } ! 364: ! 365: /* relative mantissa bit */ ! 366: int ! 367: getbit(struct fpn *fp, int n) ! 368: { ! 369: int t; ! 370: uint32_t x; ! 371: int b; ! 372: ! 373: t = n + (32 - FP_LG); ! 374: x = fp->fp_mant[(t - 1) / 32]; ! 375: b = x & (1 << (31 - ((t - 1) % 32))); ! 376: DPRINTF("n=%d %d\n", n, b); ! 377: return b; ! 378: } ! 379: ! 380: static void ! 381: fpu_itobcd(BCD *a, int x) ! 382: { ! 383: int i; ! 384: BCD r0; ! 385: BCD *r = &r0; ! 386: ! 387: memset(a, 0, sizeof(*a)); ! 388: ! 389: x = abs(x); ! 390: ! 391: for (i = 0; i < 32; i++) { ! 392: if (x == 0) break; ! 393: if (x & (1 << i)) { ! 394: x ^= (1 << i); ! 395: fpu_bcd_exp2(r, i); ! 396: fpu_bcd_add(a, r); ! 397: } ! 398: } ! 399: } ! 400: ! 401: /* Convert fpn to internal BCD structure */ ! 402: static void ! 403: fpu_fpntobcd(BCD *res, struct fpn *fp) ! 404: { ! 405: BCD bcd_r0; ! 406: BCD *bcd_r = &bcd_r0; ! 407: BCD bcd_a0; ! 408: BCD *bcd_a = &bcd_a0; ! 409: BCD bcd_b0; ! 410: BCD *bcd_b = &bcd_b0; ! 411: int i; ! 412: ! 413: memset(bcd_r, 0, sizeof(*bcd_r)); ! 414: memset(bcd_a, 0, sizeof(*bcd_a)); ! 415: memset(bcd_b, 0, sizeof(*bcd_b)); ! 416: ! 417: for (i = FP_NMANT - 1; i >= 0; i--) { ! 418: // 最下位ビットから取り出していく ! 419: if (getbit(fp, i)) { ! 420: ! 421: // 調べるビットの相当する 2^(exp-i) を計算する ! 422: fpu_bcd_exp2(bcd_r, fp->fp_exp - i); ! 423: dump("r", bcd_r); ! 424: ! 425: fpu_bcd_add(bcd_b, bcd_r); ! 426: dump("b", bcd_b); ! 427: } ! 428: } ! 429: dump("b", bcd_b); ! 430: ! 431: fpu_bcd_round(bcd_b); ! 432: dump("b", bcd_b); ! 433: ! 434: /* とりあえず */ ! 435: *res = *bcd_b; ! 436: return; ! 437: } ! 438: ! 439: /* ! 440: * fpn -> 96-bit packed BCD(space) ! 441: */ ! 442: void ! 443: fpu_ftop(struct fpemu *fe, struct fpn *fp, uint32_t *space, int kfactor) ! 444: { ! 445: BCD b0, *b; ! 446: BCD e0, *e; ! 447: int i; ! 448: int shift; ! 449: ! 450: b = &b0; ! 451: e = &e0; ! 452: ! 453: space[0] = 0; ! 454: space[1] = 0; ! 455: space[2] = 0; ! 456: ! 457: if (fp->fp_sign) { ! 458: space[0] |= 0x80000000; ! 459: } ! 460: ! 461: if (ISINF(fp)) { ! 462: space[0] |= 0x7fff0000; ! 463: return; ! 464: } ! 465: ! 466: /* fp をアンパックド BCD に変換 */ ! 467: fpu_fpntobcd(b, fp); ! 468: ! 469: /* ! 470: * k-factor ! 471: */ ! 472: DPRINTF("kfactor=%d\n", kfactor); ! 473: if (kfactor <= 0) { ! 474: /* ! 475: * FORTRAN "F" format. ! 476: * 小数以下 -k 桁まで出力する。 ! 477: */ ! 478: if (b->e >= 17) { ! 479: /* 10^17以上の値なら17桁で小数に到達しないので k=+17 と等価 */ ! 480: kfactor = 17; ! 481: } else { ! 482: shift = FPU_BCD_DIGIT - b->e + kfactor - 2; ! 483: } ! 484: } ! 485: if (kfactor > 0) { ! 486: if (kfactor > 17) { ! 487: fe->fe_fpsr |= FPSR_OPERR; ! 488: kfactor = 17; ! 489: } ! 490: /* ! 491: * FORTRAN "E" format. ! 492: * k は小数点位置に関わらず出力する桁数(文字数) を表す。 ! 493: * 1 なら 1桁だけ(つまり整数部のみ)、17 で全桁となる。 ! 494: */ ! 495: shift = FPU_BCD_DIGIT - kfactor - 1; ! 496: } ! 497: dump("k:0", b); ! 498: fpu_bcd_shr_n(b, shift); ! 499: dump("k:1", b); ! 500: fpu_bcd_round(b); ! 501: /* 四捨五入に使った最終桁はもう不要 */ ! 502: b->d[FPU_BCD_DIGIT - 1] = 0; ! 503: dump("k:2", b); ! 504: fpu_bcd_shl_n(b, shift); ! 505: dump("k:3", b); ! 506: ! 507: /* ! 508: * ここから 68881 の パックド BCD に変換していく ! 509: */ ! 510: /* exp の変換 */ ! 511: /* P 形式の EXP フィールドは 10 基数 */ ! 512: if (b->e < 0) { ! 513: space[0] |= 0x40000000; ! 514: } ! 515: ! 516: fpu_itobcd(e, abs(b->e)); ! 517: fpu_bcd_shr_n(e, 3 - e->e); ! 518: space[0] |= e->d[0] << 12; /* EXP3 */ ! 519: space[0] |= e->d[1] << 24; /* EXP2 */ ! 520: space[0] |= e->d[2] << 20; /* EXP1 */ ! 521: space[0] |= e->d[3] << 16; /* EXP0 */ ! 522: ! 523: space[0] |= b->d[0]; ! 524: DPRINTF("BCD[0]=%08x\n", space[0]); ! 525: ! 526: /* 小数部 */ ! 527: for (i = 1; i < 9; i++) { ! 528: space[1] <<= 4; ! 529: space[1] |= b->d[i]; ! 530: } ! 531: ! 532: for (i = 9; i < 17; i++) { ! 533: space[2] <<= 4; ! 534: space[2] |= b->d[i]; ! 535: } ! 536: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.