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

1.1       root        1: //
                      2: // nono
1.1.1.3   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
                      7: #include "m68030core.h"
                      8: #include "m68030acc.h"
1.1.1.3   root        9: #include <csignal>
1.1.1.4 ! root       10: #include <sys/time.h>
1.1       root       11: 
                     12: // パフォーマンステストの秒数
                     13: #define PERF_SEC       (3)
                     14: 
1.1.1.3   root       15: [[noreturn]] void usage();
1.1       root       16: 
1.1.1.3   root       17: static m68kcpu *cpu;
1.1       root       18: 
1.1.1.3   root       19: static int argc;                                       // getopt(3) 処理後の argc
                     20: static char **argv;                                    // getopt(3) 処理後の argv
                     21: static const char *testname;           // 現在のテスト名
                     22: static int total_errcnt;                       // 総エラー数
                     23: static int errcnt;                                     // 現在のセクションのエラー数
                     24: static char where[256];                                // エラー発生箇所
                     25: static volatile int perf_signaled;     // パフォーマンス測定用
                     26: static struct timeval perf_start;      // パフォーマンス測定開始時刻
                     27: static uint64 perf_count;                      // パフォーマンス測定用。処理回数
1.1       root       28: 
1.1.1.2   root       29: // value を16進数で指定のビット数分の文字列にする
1.1.1.3   root       30: static std::string
1.1.1.2   root       31: hex(uint32 value, int sz)
                     32: {
                     33:        char buf[32];
                     34: 
                     35:        switch (sz) {
                     36:         case 8:
                     37:                snprintf(buf, sizeof(buf), "%02x", value);
                     38:                break;
                     39:         case 16:
                     40:                snprintf(buf, sizeof(buf), "%04x", value);
                     41:                break;
                     42:         case 32:
                     43:         default:
                     44:                snprintf(buf, sizeof(buf), "%08x", value);
                     45:                break;
                     46:        }
                     47:        return std::string(buf);
                     48: }
                     49: 
1.1       root       50: // 整数(32bitまで)を検査する
1.1.1.3   root       51: static void __unused
1.1       root       52: xp_equal(uint32 expected, uint32 actual, const char *name)
                     53: {
                     54:        if (expected != actual) {
                     55:                if (errcnt == 0) {
                     56:                        printf("\n");
                     57:                }
                     58:                printf(" %s: %s expects 0x%08x but 0x%08x\n",
                     59:                        where, name, expected, actual);
                     60:                errcnt++;
                     61:        }
                     62: }
                     63: 
                     64: // 値(32bitまで)と CCR を検査する
1.1.1.3   root       65: static void
1.1       root       66: xp_equal(uint32 actValue, m68030ccr& actCCR, uint32 expValue,
                     67:        bool expX, bool expN, bool expZ, bool expV, bool expC)
                     68: {
                     69:        if (expValue != actValue ||
                     70:                expX != actCCR.IsX() ||
                     71:                expN != actCCR.IsN() ||
                     72:                expZ != actCCR.IsZ() ||
                     73:                expV != actCCR.IsV() ||
                     74:                expC != actCCR.IsC())
                     75:        {
                     76:                if (errcnt == 0) {
                     77:                        printf("\n");
                     78:                }
                     79:                printf("%s %s expects %08x %c%c%c%c%c but %08x %c%c%c%c%c\n",
                     80:                        testname, where,
                     81:                        expValue,
                     82:                        (expX ? 'X' : '-'),
                     83:                        (expN ? 'N' : '-'),
                     84:                        (expZ ? 'Z' : '-'),
                     85:                        (expV ? 'V' : '-'),
                     86:                        (expC ? 'C' : '-'),
                     87:                        actValue,
                     88:                        (actCCR.IsX() ? 'X' : '-'),
                     89:                        (actCCR.IsN() ? 'N' : '-'),
                     90:                        (actCCR.IsZ() ? 'Z' : '-'),
                     91:                        (actCCR.IsV() ? 'V' : '-'),
                     92:                        (actCCR.IsC() ? 'C' : '-')
                     93:                );
                     94:                errcnt++;
                     95:        }
                     96: }
                     97: 
                     98: // 値(64bit)と CCR を検査する
1.1.1.3   root       99: static void __unused
1.1       root      100: xp_equal64(uint64 actValue, m68030ccr& actCCR, uint64 expValue,
                    101:        bool expX, bool expN, bool expZ, bool expV, bool expC)
                    102: {
                    103:        if (expValue != actValue ||
                    104:                expX != actCCR.IsX() ||
                    105:                expN != actCCR.IsN() ||
                    106:                expZ != actCCR.IsZ() ||
                    107:                expV != actCCR.IsV() ||
                    108:                expC != actCCR.IsC())
                    109:        {
                    110:                if (errcnt == 0) {
                    111:                        printf("\n");
                    112:                }
                    113:                printf("%s %s expects %08x_%08x %c%c%c%c%c but %08x_%08x %c%c%c%c%c\n",
                    114:                        testname, where,
                    115:                        (uint32)(expValue >> 32),
                    116:                        (uint32)(expValue & 0xffffffff),
                    117:                        (expX ? 'X' : '-'),
                    118:                        (expN ? 'N' : '-'),
                    119:                        (expZ ? 'Z' : '-'),
                    120:                        (expV ? 'V' : '-'),
                    121:                        (expC ? 'C' : '-'),
                    122:                        (uint32)(actValue >> 32),
                    123:                        (uint32)(actValue & 0xffffffff),
                    124:                        (actCCR.IsX() ? 'X' : '-'),
                    125:                        (actCCR.IsN() ? 'N' : '-'),
                    126:                        (actCCR.IsZ() ? 'Z' : '-'),
                    127:                        (actCCR.IsV() ? 'V' : '-'),
                    128:                        (actCCR.IsC() ? 'C' : '-')
                    129:                );
                    130:                errcnt++;
                    131:        }
                    132: }
                    133: 
                    134: // このテストを実行するかどうか
                    135: // 引数なしなら全部実行。
                    136: // 引数ありなら一致すれば実行。
1.1.1.3   root      137: static bool
1.1       root      138: check_exec(const char *name)
                    139: {
                    140:        if (argc == 0) {
                    141:                return true;
                    142:        }
                    143: 
                    144:        // "test_"/"perf_" を除いた後ろが完全一致するか
                    145:        name += 5;
                    146:        for (int i = 0; i < argc; i++) {
                    147:                if (strcmp(name, argv[i]) == 0) {
                    148:                        return true;
                    149:                }
                    150:        }
                    151: 
                    152:        // サイズ部を除いて一致するか
                    153:        // add に対して addx が一致しないようにアンダーバーまでで調べる
1.1.1.3   root      154:        std::string name2(name);
                    155:        int u = name2.find('_');
                    156:        if (u != std::string::npos) {
                    157:                name2.erase(u, name2.size() - u);
1.1       root      158:        }
                    159:        for (int i = 0; i < argc; i++) {
1.1.1.3   root      160:                if (strcmp(name2.c_str(), argv[i]) == 0) {
1.1       root      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: 
1.1.1.3   root      173: static void
1.1       root      174: start_test_func(const char *name)
                    175: {
                    176:        testname = name;
                    177:        printf("%s ", testname);
                    178:        fflush(stdout);
                    179:        errcnt = 0;
                    180: }
                    181: 
1.1.1.3   root      182: static void
1.1       root      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: 
1.1.1.3   root      201: static void
1.1       root      202: signal_alarm(int signo)
                    203: {
                    204:        perf_signaled = 1;
                    205: }
                    206: 
1.1.1.3   root      207: static void
1.1       root      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: 
1.1.1.3   root      224: static void
1.1       root      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: // 乱数
1.1.1.3   root      237: static uint32
1.1       root      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
1.1.1.3   root      249: static uint64
1.1       root      250: BIT(int sz)
                    251: {
                    252:        return (1ULL << sz);
                    253: }
                    254: 
                    255: // 下位 sz ビットがすべて 1 の値を返す
1.1.1.3   root      256: static uint32
1.1       root      257: MASK(int sz)
                    258: {
                    259:        return (1ULL << sz) - 1;
                    260: }
                    261: 
                    262: // value を sz ビット符号付き整数とした時、負かどうかを返す
                    263: // sz は 8, 16, 32
1.1.1.3   root      264: static bool
1.1       root      265: ISNEG(uint64 value, int sz)
                    266: {
                    267:        return ((value & BIT(sz - 1)) != 0);
                    268: }
                    269: 
                    270: //
                    271: // add,sub
                    272: //
                    273: 
1.1.1.3   root      274: static uint32 add_table[] = {
1.1       root      275:        0x00000000,
                    276:        0x00000001,
                    277:        0x0000007f,
                    278:        0x00000080,
                    279:        0x000000ff,
                    280:        0x00007fff,
                    281:        0x00008000,
                    282:        0x0000ffff,
                    283:        0x7fffffff,
                    284:        0x80000000,
                    285:        0xffffffff,
                    286: };
                    287: 
1.1.1.3   root      288: static void
1.1       root      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: 
1.1.1.3   root      318: static void
1.1       root      319: test_add_8()
                    320: {
                    321:        start_test();
                    322:        test_add(8);
                    323:        end_test();
                    324: }
                    325: 
1.1.1.3   root      326: static void
1.1       root      327: test_add_16()
                    328: {
                    329:        start_test();
                    330:        test_add(16);
                    331:        end_test();
                    332: }
                    333: 
1.1.1.3   root      334: static void
1.1       root      335: test_add_32()
                    336: {
                    337:        start_test();
                    338:        test_add(32);
                    339:        end_test();
                    340: }
                    341: 
1.1.1.3   root      342: static void
1.1       root      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: 
1.1.1.3   root      379: static void
1.1       root      380: test_sub_8()
                    381: {
                    382:        start_test();
                    383:        test_sub(8);
                    384:        end_test();
                    385: }
                    386: 
1.1.1.3   root      387: static void
1.1       root      388: test_sub_16()
                    389: {
                    390:        start_test();
                    391:        test_sub(16);
                    392:        end_test();
                    393: }
                    394: 
1.1.1.3   root      395: static void
1.1       root      396: test_sub_32()
                    397: {
                    398:        start_test();
                    399:        test_sub(32);
                    400:        end_test();
                    401: }
                    402: 
                    403: 
                    404: //
                    405: // addx
                    406: //
1.1.1.3   root      407: static struct {
1.1       root      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: 
1.1.1.3   root      421: static void
1.1       root      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)       \
1.1.1.3   root      450: static void    \
1.1       root      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:        }       \
1.1.1.4 ! root      462:        (void)dst;      \
1.1       root      463:        END_PERF;       \
                    464: }
                    465: DEFINE_PERF_ROTATE(asl_32)
                    466: DEFINE_PERF_ROTATE(lsl_32)
                    467: DEFINE_PERF_ROTATE(roxl_32)
                    468: DEFINE_PERF_ROTATE(rol_32)
                    469: DEFINE_PERF_ROTATE(asr_32)
                    470: DEFINE_PERF_ROTATE(lsr_32)
                    471: DEFINE_PERF_ROTATE(roxr_32)
                    472: DEFINE_PERF_ROTATE(ror_32)
                    473: 
1.1.1.3   root      474: static void
1.1       root      475: perf_add_32()
                    476: {
                    477:        START_PERF;
                    478:        volatile uint32 dst = 0;
                    479:        for (; perf_signaled == 0; ) {
                    480:                uint32 src = xor32();
                    481:                dst = acc_add_32(cpu, src, dst);
                    482:                perf_count++;
                    483:        }
                    484:        END_PERF;
                    485: }
                    486: 
                    487: int
                    488: main(int ac, char *av[])
                    489: {
                    490:        int c;
                    491:        bool do_test;
                    492:        bool do_perf;
                    493: 
                    494:        do_test = true;
                    495:        do_perf = true;
                    496: 
                    497:        while ((c = getopt(ac, av, "tp")) != -1) {
                    498:                switch (c) {
                    499:                 case 't':      // test only
                    500:                        do_perf = false;
                    501:                        break;
                    502:                 case 'p':      // perf only
                    503:                        do_test = false;
                    504:                        break;
                    505:                 default:
                    506:                        usage();
                    507:                }
                    508:        }
                    509:        ac -= optind;
                    510:        av += optind;
                    511:        argc = ac;
1.1.1.3   root      512:        argv = av;
1.1       root      513: 
                    514:        // 本当はコンストラクタを呼ぶべきだが、そうすると必要なオブジェクトが
                    515:        // 芋づる式に増えて正しく解決するのは面倒。ここのテストではとりあえず
                    516:        // 存在しててアクセスできればいい程度なのでこれで誤魔化してある。
                    517:        cpu = (m68kcpu *)calloc(sizeof(*cpu), 1);
                    518: 
                    519:        if (do_test) {
                    520:                test_add_8();
                    521:                test_add_16();
                    522:                test_add_32();
                    523:                test_sub_8();
                    524:                test_sub_16();
                    525:                test_sub_32();
                    526:                test_addx_32();
                    527:        }
                    528: 
                    529:        if (do_perf) {
                    530:                perf_asl_32();
                    531:                perf_lsl_32();
                    532:                perf_roxl_32();
                    533:                perf_rol_32();
                    534:                perf_asr_32();
                    535:                perf_lsr_32();
                    536:                perf_roxr_32();
                    537:                perf_ror_32();
                    538:                perf_add_32();
                    539:        }
                    540: 
                    541:        return 0;
                    542: }
                    543: 
                    544: void
                    545: usage()
                    546: {
                    547:        fprintf(stderr, "usage: %s [-t] [-p]\n", getprogname());
                    548:        exit(1);
                    549: }

unix.superglobalmegacorp.com

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