Annotation of nono/m680x0/testacc.cpp, revision 1.1.1.2

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.