|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2017 [email protected] ! 4: // ! 5: ! 6: #include "header.h" ! 7: #include <csignal> ! 8: #include "m68030core.h" ! 9: #include "m68030acc.h" ! 10: ! 11: // パフォーマンステストの秒数 ! 12: #define PERF_SEC (3) ! 13: ! 14: void usage(); ! 15: ! 16: m68kcpu *cpu; ! 17: ! 18: int argc; // getopt(3) 処理後の argc ! 19: const char **argv; // getopt(3) 処理後の argv ! 20: const char *testname; // 現在のテスト名 ! 21: int total_errcnt; // 総エラー数 ! 22: int errcnt; // 現在のセクションのエラー数 ! 23: char where[256]; // エラー発生箇所 ! 24: volatile int perf_signaled; // パフォーマンス測定用 ! 25: struct timeval perf_start; // パフォーマンス測定開始時刻 ! 26: uint64 perf_count; // パフォーマンス測定用。処理回数 ! 27: ! 28: // 整数(32bitまで)を検査する ! 29: void ! 30: xp_equal(uint32 expected, uint32 actual, const char *name) ! 31: { ! 32: if (expected != actual) { ! 33: if (errcnt == 0) { ! 34: printf("\n"); ! 35: } ! 36: printf(" %s: %s expects 0x%08x but 0x%08x\n", ! 37: where, name, expected, actual); ! 38: errcnt++; ! 39: } ! 40: } ! 41: ! 42: // 値(32bitまで)と CCR を検査する ! 43: void ! 44: xp_equal(uint32 actValue, m68030ccr& actCCR, uint32 expValue, ! 45: bool expX, bool expN, bool expZ, bool expV, bool expC) ! 46: { ! 47: if (expValue != actValue || ! 48: expX != actCCR.IsX() || ! 49: expN != actCCR.IsN() || ! 50: expZ != actCCR.IsZ() || ! 51: expV != actCCR.IsV() || ! 52: expC != actCCR.IsC()) ! 53: { ! 54: if (errcnt == 0) { ! 55: printf("\n"); ! 56: } ! 57: printf("%s %s expects %08x %c%c%c%c%c but %08x %c%c%c%c%c\n", ! 58: testname, where, ! 59: expValue, ! 60: (expX ? 'X' : '-'), ! 61: (expN ? 'N' : '-'), ! 62: (expZ ? 'Z' : '-'), ! 63: (expV ? 'V' : '-'), ! 64: (expC ? 'C' : '-'), ! 65: actValue, ! 66: (actCCR.IsX() ? 'X' : '-'), ! 67: (actCCR.IsN() ? 'N' : '-'), ! 68: (actCCR.IsZ() ? 'Z' : '-'), ! 69: (actCCR.IsV() ? 'V' : '-'), ! 70: (actCCR.IsC() ? 'C' : '-') ! 71: ); ! 72: errcnt++; ! 73: } ! 74: } ! 75: ! 76: // 値(64bit)と CCR を検査する ! 77: void ! 78: xp_equal64(uint64 actValue, m68030ccr& actCCR, uint64 expValue, ! 79: bool expX, bool expN, bool expZ, bool expV, bool expC) ! 80: { ! 81: if (expValue != actValue || ! 82: expX != actCCR.IsX() || ! 83: expN != actCCR.IsN() || ! 84: expZ != actCCR.IsZ() || ! 85: expV != actCCR.IsV() || ! 86: expC != actCCR.IsC()) ! 87: { ! 88: if (errcnt == 0) { ! 89: printf("\n"); ! 90: } ! 91: printf("%s %s expects %08x_%08x %c%c%c%c%c but %08x_%08x %c%c%c%c%c\n", ! 92: testname, where, ! 93: (uint32)(expValue >> 32), ! 94: (uint32)(expValue & 0xffffffff), ! 95: (expX ? 'X' : '-'), ! 96: (expN ? 'N' : '-'), ! 97: (expZ ? 'Z' : '-'), ! 98: (expV ? 'V' : '-'), ! 99: (expC ? 'C' : '-'), ! 100: (uint32)(actValue >> 32), ! 101: (uint32)(actValue & 0xffffffff), ! 102: (actCCR.IsX() ? 'X' : '-'), ! 103: (actCCR.IsN() ? 'N' : '-'), ! 104: (actCCR.IsZ() ? 'Z' : '-'), ! 105: (actCCR.IsV() ? 'V' : '-'), ! 106: (actCCR.IsC() ? 'C' : '-') ! 107: ); ! 108: errcnt++; ! 109: } ! 110: } ! 111: ! 112: // このテストを実行するかどうか ! 113: // 引数なしなら全部実行。 ! 114: // 引数ありなら一致すれば実行。 ! 115: bool ! 116: check_exec(const char *name) ! 117: { ! 118: if (argc == 0) { ! 119: return true; ! 120: } ! 121: ! 122: // "test_"/"perf_" を除いた後ろが完全一致するか ! 123: name += 5; ! 124: for (int i = 0; i < argc; i++) { ! 125: if (strcmp(name, argv[i]) == 0) { ! 126: return true; ! 127: } ! 128: } ! 129: ! 130: // サイズ部を除いて一致するか ! 131: // add に対して addx が一致しないようにアンダーバーまでで調べる ! 132: char name2[strlen(name) + 1]; ! 133: strcpy(name2, name); ! 134: char *u = strchr(name2, '_'); ! 135: if (u) { ! 136: *u = '\0'; ! 137: } ! 138: for (int i = 0; i < argc; i++) { ! 139: if (strcmp(name2, argv[i]) == 0) { ! 140: return true; ! 141: } ! 142: } ! 143: ! 144: return false; ! 145: } ! 146: ! 147: #define start_test() \ ! 148: if (!check_exec(__FUNCTION__)) \ ! 149: return; \ ! 150: start_test_func(__FUNCTION__) ! 151: ! 152: void ! 153: start_test_func(const char *name) ! 154: { ! 155: testname = name; ! 156: printf("%s ", testname); ! 157: fflush(stdout); ! 158: errcnt = 0; ! 159: } ! 160: ! 161: void ! 162: end_test() ! 163: { ! 164: if (errcnt == 0) { ! 165: printf("ok\n"); ! 166: } else { ! 167: printf("%d error(s)\n", errcnt); ! 168: } ! 169: total_errcnt += errcnt; ! 170: } ! 171: ! 172: #define START_PERF \ ! 173: if (!check_exec(__FUNCTION__)) \ ! 174: return; \ ! 175: start_perf_func(__FUNCTION__) ! 176: ! 177: #define END_PERF \ ! 178: end_perf_func() ! 179: ! 180: void ! 181: signal_alarm(int signo) ! 182: { ! 183: perf_signaled = 1; ! 184: } ! 185: ! 186: void ! 187: start_perf_func(const char *name) ! 188: { ! 189: testname = name; ! 190: printf("%s\t... ", testname); ! 191: fflush(stdout); ! 192: ! 193: perf_count = 0; ! 194: perf_signaled = 0; ! 195: signal(SIGALRM, signal_alarm); ! 196: struct itimerval it = {}; ! 197: it.it_value.tv_sec = PERF_SEC; ! 198: ! 199: gettimeofday(&perf_start, NULL); ! 200: setitimer(ITIMER_REAL, &it, NULL); ! 201: } ! 202: ! 203: void ! 204: end_perf_func() ! 205: { ! 206: struct timeval end, result; ! 207: ! 208: gettimeofday(&end, NULL); ! 209: timersub(&end, &perf_start, &result); ! 210: ! 211: uint64 usec = (uint64)result.tv_sec * 1000000 + (uint64)result.tv_usec; ! 212: printf("%" PRIu64 " times/usec\n", perf_count / usec); ! 213: } ! 214: ! 215: // 乱数 ! 216: uint32 ! 217: xor32() ! 218: { ! 219: static uint32 y = 2463534242; ! 220: y = y ^ (y << 13); ! 221: y = y ^ (y >> 17); ! 222: y = y ^ (y << 5); ! 223: return y; ! 224: } ! 225: ! 226: // sz ビット目(最下位を0とする)を立てた値を返す ! 227: // sz は 0..63 ! 228: uint64 ! 229: BIT(int sz) ! 230: { ! 231: return (1ULL << sz); ! 232: } ! 233: ! 234: // 下位 sz ビットがすべて 1 の値を返す ! 235: uint32 ! 236: MASK(int sz) ! 237: { ! 238: return (1ULL << sz) - 1; ! 239: } ! 240: ! 241: // value を sz ビット符号付き整数とした時、負かどうかを返す ! 242: // sz は 8, 16, 32 ! 243: bool ! 244: ISNEG(uint64 value, int sz) ! 245: { ! 246: return ((value & BIT(sz - 1)) != 0); ! 247: } ! 248: ! 249: // ! 250: // add,sub ! 251: // ! 252: ! 253: uint32 add_table[] = { ! 254: 0x00000000, ! 255: 0x00000001, ! 256: 0x0000007f, ! 257: 0x00000080, ! 258: 0x000000ff, ! 259: 0x00007fff, ! 260: 0x00008000, ! 261: 0x0000ffff, ! 262: 0x7fffffff, ! 263: 0x80000000, ! 264: 0xffffffff, ! 265: }; ! 266: ! 267: void ! 268: test_add(int sz) ! 269: { ! 270: for (int i = 0; i < countof(add_table); i++) { ! 271: for (int j = 0; j < countof(add_table); j++) { ! 272: uint64 src = add_table[i] & MASK(sz); ! 273: uint64 dst = add_table[j] & MASK(sz); ! 274: ! 275: uint64 tmp = src + dst; ! 276: uint64 res = tmp & MASK(sz); ! 277: sprintf(where, "%0*" PRIx64 " + %0*" PRIx64, ! 278: (sz / 4), src, (sz / 4), dst); ! 279: bool C = tmp & BIT(sz); ! 280: bool V = ((res ^ src) & (res ^ dst)) & BIT(sz - 1); ! 281: ! 282: uint32 actual; ! 283: if (sz == 8) { ! 284: actual = acc_add_8(cpu, src, dst); ! 285: } else if (sz == 16) { ! 286: actual = acc_add_16(cpu, src, dst); ! 287: } else { ! 288: actual = acc_add_32(cpu, src, dst); ! 289: } ! 290: ! 291: xp_equal(actual, CCR, res, ! 292: C, ISNEG(res, sz), (res == 0), V, C); ! 293: } ! 294: } ! 295: } ! 296: ! 297: void ! 298: test_add_8() ! 299: { ! 300: start_test(); ! 301: test_add(8); ! 302: end_test(); ! 303: } ! 304: ! 305: void ! 306: test_add_16() ! 307: { ! 308: start_test(); ! 309: test_add(16); ! 310: end_test(); ! 311: } ! 312: ! 313: void ! 314: test_add_32() ! 315: { ! 316: start_test(); ! 317: test_add(32); ! 318: end_test(); ! 319: } ! 320: ! 321: void ! 322: test_sub(int sz) ! 323: { ! 324: for (int i = 0; i < countof(add_table); i++) { ! 325: for (int j = 0; j < countof(add_table); j++) { ! 326: uint64 src = add_table[i] & MASK(sz); ! 327: uint64 dst = add_table[j] & MASK(sz); ! 328: ! 329: uint64 tmp; ! 330: if (sz == 8) { ! 331: tmp = (uint64)dst - (uint64)src; ! 332: } else if (sz == 16) { ! 333: tmp = (uint64)dst - (uint64)src; ! 334: } else { ! 335: tmp = (uint64)dst - (uint64)src; ! 336: } ! 337: uint64 res = tmp & MASK(sz); ! 338: sprintf(where, "%0*" PRIx64 " - %0*" PRIx64, ! 339: (sz / 4), dst, (sz / 4), src); ! 340: bool C = tmp & BIT(sz); ! 341: bool V = ((src ^ dst) & (res ^ dst)) & BIT(sz - 1); ! 342: ! 343: uint32 actual; ! 344: if (sz == 8) { ! 345: actual = acc_sub_8(cpu, src, dst); ! 346: } else if (sz == 16) { ! 347: actual = acc_sub_16(cpu, src, dst); ! 348: } else { ! 349: actual = acc_sub_32(cpu, src, dst); ! 350: } ! 351: ! 352: xp_equal(actual, CCR, res, ! 353: C, ISNEG(res, sz), (res == 0), V, C); ! 354: } ! 355: } ! 356: } ! 357: ! 358: void ! 359: test_sub_8() ! 360: { ! 361: start_test(); ! 362: test_sub(8); ! 363: end_test(); ! 364: } ! 365: ! 366: void ! 367: test_sub_16() ! 368: { ! 369: start_test(); ! 370: test_sub(16); ! 371: end_test(); ! 372: } ! 373: ! 374: void ! 375: test_sub_32() ! 376: { ! 377: start_test(); ! 378: test_sub(32); ! 379: end_test(); ! 380: } ! 381: ! 382: ! 383: // ! 384: // addx ! 385: // ! 386: struct { ! 387: uint32 src, dst; ! 388: bool inX; ! 389: uint32 res; ! 390: bool expN, expZ, expV, expC; ! 391: } addx32_table[] = { ! 392: // src dst X res N Z V C ! 393: { 0x00000000, 0xffffffff, 0, 0xffffffff, 1, 0, 0, 0 }, ! 394: { 0x00000000, 0xffffffff, 1, 0x00000000, 0, 1, 0, 1 }, ! 395: { 0x7fffffff, 0x00000001, 0, 0x80000000, 1, 0, 1, 0 }, ! 396: { 0x7fffffff, 0x00000000, 1, 0x80000000, 1, 0, 1, 0 }, ! 397: { 0x7fffffff, 0x80000000, 1, 0x00000000, 0, 1, 0, 1 }, ! 398: }; ! 399: ! 400: void ! 401: test_addx_32() ! 402: { ! 403: start_test(); ! 404: for (int i = 0; i < countof(addx32_table); i++) { ! 405: uint32 src = addx32_table[i].src; ! 406: uint32 dst = addx32_table[i].dst; ! 407: bool inX = addx32_table[i].inX; ! 408: uint32 res = addx32_table[i].res; ! 409: bool expN = addx32_table[i].expN; ! 410: bool expZ = addx32_table[i].expZ; ! 411: bool expV = addx32_table[i].expV; ! 412: bool expC = addx32_table[i].expC; ! 413: sprintf(where, "%08x + %08x + %d", src, dst, inX); ! 414: ! 415: CCR.PutX(inX); ! 416: CCR.PutZ(true); ! 417: uint32 actual = acc_addx_32(cpu, src, dst); ! 418: xp_equal(actual, CCR, res, expC, expN, expZ, expV, expC); ! 419: } ! 420: end_test(); ! 421: } ! 422: ! 423: // ! 424: // rotate/shift ! 425: // ! 426: ! 427: // ローテート/シフト系のパフォーマンス測定 ! 428: #define DEFINE_PERF_ROTATE(name) \ ! 429: void \ ! 430: __CONCAT(perf_,name)() \ ! 431: { \ ! 432: START_PERF; \ ! 433: volatile uint32 dst = 0; \ ! 434: for (; perf_signaled == 0;) { \ ! 435: for (int count = 0; count < 32; count++) { \ ! 436: uint32 src = xor32(); \ ! 437: dst ^= __CONCAT(acc_,name)(cpu, src, count); \ ! 438: perf_count++; \ ! 439: } \ ! 440: } \ ! 441: END_PERF; \ ! 442: } ! 443: DEFINE_PERF_ROTATE(asl_32) ! 444: DEFINE_PERF_ROTATE(lsl_32) ! 445: DEFINE_PERF_ROTATE(roxl_32) ! 446: DEFINE_PERF_ROTATE(rol_32) ! 447: DEFINE_PERF_ROTATE(asr_32) ! 448: DEFINE_PERF_ROTATE(lsr_32) ! 449: DEFINE_PERF_ROTATE(roxr_32) ! 450: DEFINE_PERF_ROTATE(ror_32) ! 451: ! 452: void ! 453: perf_add_32() ! 454: { ! 455: START_PERF; ! 456: volatile uint32 dst = 0; ! 457: for (; perf_signaled == 0; ) { ! 458: uint32 src = xor32(); ! 459: dst = acc_add_32(cpu, src, dst); ! 460: perf_count++; ! 461: } ! 462: END_PERF; ! 463: } ! 464: ! 465: int ! 466: main(int ac, char *av[]) ! 467: { ! 468: int c; ! 469: bool do_test; ! 470: bool do_perf; ! 471: ! 472: do_test = true; ! 473: do_perf = true; ! 474: ! 475: while ((c = getopt(ac, av, "tp")) != -1) { ! 476: switch (c) { ! 477: case 't': // test only ! 478: do_perf = false; ! 479: break; ! 480: case 'p': // perf only ! 481: do_test = false; ! 482: break; ! 483: default: ! 484: usage(); ! 485: } ! 486: } ! 487: ac -= optind; ! 488: av += optind; ! 489: argc = ac; ! 490: argv = (const char **)av; ! 491: ! 492: // 本当はコンストラクタを呼ぶべきだが、そうすると必要なオブジェクトが ! 493: // 芋づる式に増えて正しく解決するのは面倒。ここのテストではとりあえず ! 494: // 存在しててアクセスできればいい程度なのでこれで誤魔化してある。 ! 495: cpu = (m68kcpu *)calloc(sizeof(*cpu), 1); ! 496: ! 497: if (do_test) { ! 498: test_add_8(); ! 499: test_add_16(); ! 500: test_add_32(); ! 501: test_sub_8(); ! 502: test_sub_16(); ! 503: test_sub_32(); ! 504: test_addx_32(); ! 505: } ! 506: ! 507: if (do_perf) { ! 508: perf_asl_32(); ! 509: perf_lsl_32(); ! 510: perf_roxl_32(); ! 511: perf_rol_32(); ! 512: perf_asr_32(); ! 513: perf_lsr_32(); ! 514: perf_roxr_32(); ! 515: perf_ror_32(); ! 516: perf_add_32(); ! 517: } ! 518: ! 519: return 0; ! 520: } ! 521: ! 522: void ! 523: usage() ! 524: { ! 525: fprintf(stderr, "usage: %s [-t] [-p]\n", getprogname()); ! 526: exit(1); ! 527: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.