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

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       root       10: 
                     11: // パフォーマンステストの秒数
                     12: #define PERF_SEC       (3)
                     13: 
1.1.1.3 ! root       14: [[noreturn]] void usage();
1.1       root       15: 
1.1.1.3 ! root       16: static m68kcpu *cpu;
1.1       root       17: 
1.1.1.3 ! root       18: static int argc;                                       // getopt(3) 処理後の argc
        !            19: static char **argv;                                    // getopt(3) 処理後の argv
        !            20: static const char *testname;           // 現在のテスト名
        !            21: static int total_errcnt;                       // 総エラー数
        !            22: static int errcnt;                                     // 現在のセクションのエラー数
        !            23: static char where[256];                                // エラー発生箇所
        !            24: static volatile int perf_signaled;     // パフォーマンス測定用
        !            25: static struct timeval perf_start;      // パフォーマンス測定開始時刻
        !            26: static uint64 perf_count;                      // パフォーマンス測定用。処理回数
1.1       root       27: 
1.1.1.2   root       28: // value を16進数で指定のビット数分の文字列にする
1.1.1.3 ! root       29: static std::string
1.1.1.2   root       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まで)を検査する
1.1.1.3 ! root       50: static void __unused
1.1       root       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 を検査する
1.1.1.3 ! root       64: static void
1.1       root       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 を検査する
1.1.1.3 ! root       98: static void __unused
1.1       root       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: // 引数ありなら一致すれば実行。
1.1.1.3 ! root      136: static bool
1.1       root      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 が一致しないようにアンダーバーまでで調べる
1.1.1.3 ! root      153:        std::string name2(name);
        !           154:        int u = name2.find('_');
        !           155:        if (u != std::string::npos) {
        !           156:                name2.erase(u, name2.size() - u);
1.1       root      157:        }
                    158:        for (int i = 0; i < argc; i++) {
1.1.1.3 ! root      159:                if (strcmp(name2.c_str(), argv[i]) == 0) {
1.1       root      160:                        return true;
                    161:                }
                    162:        }
                    163: 
                    164:        return false;
                    165: }
                    166: 
                    167: #define start_test() \
                    168:        if (!check_exec(__FUNCTION__))  \
                    169:                return; \
                    170:        start_test_func(__FUNCTION__)
                    171: 
1.1.1.3 ! root      172: static void
1.1       root      173: start_test_func(const char *name)
                    174: {
                    175:        testname = name;
                    176:        printf("%s ", testname);
                    177:        fflush(stdout);
                    178:        errcnt = 0;
                    179: }
                    180: 
1.1.1.3 ! root      181: static void
1.1       root      182: end_test()
                    183: {
                    184:        if (errcnt == 0) {
                    185:                printf("ok\n");
                    186:        } else {
                    187:                printf("%d error(s)\n", errcnt);
                    188:        }
                    189:        total_errcnt += errcnt;
                    190: }
                    191: 
                    192: #define START_PERF \
                    193:        if (!check_exec(__FUNCTION__))  \
                    194:                return; \
                    195:        start_perf_func(__FUNCTION__)
                    196: 
                    197: #define END_PERF       \
                    198:        end_perf_func()
                    199: 
1.1.1.3 ! root      200: static void
1.1       root      201: signal_alarm(int signo)
                    202: {
                    203:        perf_signaled = 1;
                    204: }
                    205: 
1.1.1.3 ! root      206: static void
1.1       root      207: start_perf_func(const char *name)
                    208: {
                    209:        testname = name;
                    210:        printf("%s\t... ", testname);
                    211:        fflush(stdout);
                    212: 
                    213:        perf_count = 0;
                    214:        perf_signaled = 0;
                    215:        signal(SIGALRM, signal_alarm);
                    216:        struct itimerval it = {};
                    217:        it.it_value.tv_sec = PERF_SEC;
                    218: 
                    219:        gettimeofday(&perf_start, NULL);
                    220:        setitimer(ITIMER_REAL, &it, NULL);
                    221: }
                    222: 
1.1.1.3 ! root      223: static void
1.1       root      224: end_perf_func()
                    225: {
                    226:        struct timeval end, result;
                    227: 
                    228:        gettimeofday(&end, NULL);
                    229:        timersub(&end, &perf_start, &result);
                    230: 
                    231:        uint64 usec = (uint64)result.tv_sec * 1000000 + (uint64)result.tv_usec;
                    232:        printf("%" PRIu64 " times/usec\n", perf_count / usec);
                    233: }
                    234: 
                    235: // 乱数
1.1.1.3 ! root      236: static uint32
1.1       root      237: xor32()
                    238: {
                    239:        static uint32 y = 2463534242;
                    240:        y = y ^ (y << 13);
                    241:        y = y ^ (y >> 17);
                    242:        y = y ^ (y << 5);
                    243:        return y;
                    244: }
                    245: 
                    246: // sz ビット目(最下位を0とする)を立てた値を返す
                    247: // sz は 0..63
1.1.1.3 ! root      248: static uint64
1.1       root      249: BIT(int sz)
                    250: {
                    251:        return (1ULL << sz);
                    252: }
                    253: 
                    254: // 下位 sz ビットがすべて 1 の値を返す
1.1.1.3 ! root      255: static uint32
1.1       root      256: MASK(int sz)
                    257: {
                    258:        return (1ULL << sz) - 1;
                    259: }
                    260: 
                    261: // value を sz ビット符号付き整数とした時、負かどうかを返す
                    262: // sz は 8, 16, 32
1.1.1.3 ! root      263: static bool
1.1       root      264: ISNEG(uint64 value, int sz)
                    265: {
                    266:        return ((value & BIT(sz - 1)) != 0);
                    267: }
                    268: 
                    269: //
                    270: // add,sub
                    271: //
                    272: 
1.1.1.3 ! root      273: static uint32 add_table[] = {
1.1       root      274:        0x00000000,
                    275:        0x00000001,
                    276:        0x0000007f,
                    277:        0x00000080,
                    278:        0x000000ff,
                    279:        0x00007fff,
                    280:        0x00008000,
                    281:        0x0000ffff,
                    282:        0x7fffffff,
                    283:        0x80000000,
                    284:        0xffffffff,
                    285: };
                    286: 
1.1.1.3 ! root      287: static void
1.1       root      288: test_add(int sz)
                    289: {
                    290:        for (int i = 0; i < countof(add_table); i++) {
                    291:                for (int j = 0; j < countof(add_table); j++) {
                    292:                        uint64 src = add_table[i] & MASK(sz);
                    293:                        uint64 dst = add_table[j] & MASK(sz);
                    294: 
                    295:                        uint64 tmp = src + dst;
                    296:                        uint64 res = tmp & MASK(sz);
1.1.1.2   root      297:                        std::string w = hex(src, sz) + " + " + hex(dst, sz);
                    298:                        strlcpy(where, w.c_str(), sizeof(where));
1.1       root      299:                        bool C = tmp & BIT(sz);
                    300:                        bool V = ((res ^ src) & (res ^ dst)) & BIT(sz - 1);
                    301: 
                    302:                        uint32 actual;
                    303:                        if (sz == 8) {
                    304:                                actual = acc_add_8(cpu, src, dst);
                    305:                        } else if (sz == 16) {
                    306:                                actual = acc_add_16(cpu, src, dst);
                    307:                        } else {
                    308:                                actual = acc_add_32(cpu, src, dst);
                    309:                        }
                    310: 
                    311:                        xp_equal(actual, CCR, res,
                    312:                                C, ISNEG(res, sz), (res == 0), V, C);
                    313:                }
                    314:        }
                    315: }
                    316: 
1.1.1.3 ! root      317: static void
1.1       root      318: test_add_8()
                    319: {
                    320:        start_test();
                    321:        test_add(8);
                    322:        end_test();
                    323: }
                    324: 
1.1.1.3 ! root      325: static void
1.1       root      326: test_add_16()
                    327: {
                    328:        start_test();
                    329:        test_add(16);
                    330:        end_test();
                    331: }
                    332: 
1.1.1.3 ! root      333: static void
1.1       root      334: test_add_32()
                    335: {
                    336:        start_test();
                    337:        test_add(32);
                    338:        end_test();
                    339: }
                    340: 
1.1.1.3 ! root      341: static void
1.1       root      342: test_sub(int sz)
                    343: {
                    344:        for (int i = 0; i < countof(add_table); i++) {
                    345:                for (int j = 0; j < countof(add_table); j++) {
                    346:                        uint64 src = add_table[i] & MASK(sz);
                    347:                        uint64 dst = add_table[j] & MASK(sz);
                    348: 
                    349:                        uint64 tmp;
                    350:                        if (sz == 8) {
                    351:                                tmp = (uint64)dst - (uint64)src;
                    352:                        } else if (sz == 16) {
                    353:                                tmp = (uint64)dst - (uint64)src;
                    354:                        } else {
                    355:                                tmp = (uint64)dst - (uint64)src;
                    356:                        }
                    357:                        uint64 res = tmp & MASK(sz);
1.1.1.2   root      358:                        std::string w = hex(dst, sz) + " - " + hex(src, sz);
                    359:                        strlcpy(where, w.c_str(), sizeof(where));
1.1       root      360:                        bool C = tmp & BIT(sz);
                    361:                        bool V = ((src ^ dst) & (res ^ dst)) & BIT(sz - 1);
                    362: 
                    363:                        uint32 actual;
                    364:                        if (sz == 8) {
                    365:                                actual = acc_sub_8(cpu, src, dst);
                    366:                        } else if (sz == 16) {
                    367:                                actual = acc_sub_16(cpu, src, dst);
                    368:                        } else {
                    369:                                actual = acc_sub_32(cpu, src, dst);
                    370:                        }
                    371: 
                    372:                        xp_equal(actual, CCR, res,
                    373:                                C, ISNEG(res, sz), (res == 0), V, C);
                    374:                }
                    375:        }
                    376: }
                    377: 
1.1.1.3 ! root      378: static void
1.1       root      379: test_sub_8()
                    380: {
                    381:        start_test();
                    382:        test_sub(8);
                    383:        end_test();
                    384: }
                    385: 
1.1.1.3 ! root      386: static void
1.1       root      387: test_sub_16()
                    388: {
                    389:        start_test();
                    390:        test_sub(16);
                    391:        end_test();
                    392: }
                    393: 
1.1.1.3 ! root      394: static void
1.1       root      395: test_sub_32()
                    396: {
                    397:        start_test();
                    398:        test_sub(32);
                    399:        end_test();
                    400: }
                    401: 
                    402: 
                    403: //
                    404: // addx
                    405: //
1.1.1.3 ! root      406: static struct {
1.1       root      407:        uint32 src, dst;
                    408:        bool inX;
                    409:        uint32 res;
                    410:        bool expN, expZ, expV, expC;
                    411: } addx32_table[] = {
                    412:        // src        dst         X     res         N  Z  V  C
                    413:        { 0x00000000, 0xffffffff, 0,    0xffffffff, 1, 0, 0, 0 },
                    414:        { 0x00000000, 0xffffffff, 1,    0x00000000, 0, 1, 0, 1 },
                    415:        { 0x7fffffff, 0x00000001, 0,    0x80000000, 1, 0, 1, 0 },
                    416:        { 0x7fffffff, 0x00000000, 1,    0x80000000, 1, 0, 1, 0 },
                    417:        { 0x7fffffff, 0x80000000, 1,    0x00000000, 0, 1, 0, 1 },
                    418: };
                    419: 
1.1.1.3 ! root      420: static void
1.1       root      421: test_addx_32()
                    422: {
                    423:        start_test();
                    424:        for (int i = 0; i < countof(addx32_table); i++) {
                    425:                uint32 src = addx32_table[i].src;
                    426:                uint32 dst = addx32_table[i].dst;
                    427:                bool   inX = addx32_table[i].inX;
                    428:                uint32 res = addx32_table[i].res;
                    429:                bool  expN = addx32_table[i].expN;
                    430:                bool  expZ = addx32_table[i].expZ;
                    431:                bool  expV = addx32_table[i].expV;
                    432:                bool  expC = addx32_table[i].expC;
                    433:                sprintf(where, "%08x + %08x + %d", src, dst, inX);
                    434: 
                    435:                CCR.PutX(inX);
                    436:                CCR.PutZ(true);
                    437:                uint32 actual = acc_addx_32(cpu, src, dst);
                    438:                xp_equal(actual, CCR, res, expC, expN, expZ, expV, expC);
                    439:        }
                    440:        end_test();
                    441: }
                    442: 
                    443: //
                    444: // rotate/shift
                    445: //
                    446: 
                    447: // ローテート/シフト系のパフォーマンス測定
                    448: #define DEFINE_PERF_ROTATE(name)       \
1.1.1.3 ! root      449: static void    \
1.1       root      450: __CONCAT(perf_,name)() \
                    451: {      \
                    452:        START_PERF;     \
                    453:        volatile uint32 dst = 0;        \
                    454:        for (; perf_signaled == 0;) {   \
                    455:                for (int count = 0; count < 32; count++) {      \
                    456:                        uint32 src = xor32();   \
                    457:                        dst ^= __CONCAT(acc_,name)(cpu, src, count);    \
                    458:                        perf_count++;   \
                    459:                }       \
                    460:        }       \
                    461:        END_PERF;       \
                    462: }
                    463: DEFINE_PERF_ROTATE(asl_32)
                    464: DEFINE_PERF_ROTATE(lsl_32)
                    465: DEFINE_PERF_ROTATE(roxl_32)
                    466: DEFINE_PERF_ROTATE(rol_32)
                    467: DEFINE_PERF_ROTATE(asr_32)
                    468: DEFINE_PERF_ROTATE(lsr_32)
                    469: DEFINE_PERF_ROTATE(roxr_32)
                    470: DEFINE_PERF_ROTATE(ror_32)
                    471: 
1.1.1.3 ! root      472: static void
1.1       root      473: perf_add_32()
                    474: {
                    475:        START_PERF;
                    476:        volatile uint32 dst = 0;
                    477:        for (; perf_signaled == 0; ) {
                    478:                uint32 src = xor32();
                    479:                dst = acc_add_32(cpu, src, dst);
                    480:                perf_count++;
                    481:        }
                    482:        END_PERF;
                    483: }
                    484: 
                    485: int
                    486: main(int ac, char *av[])
                    487: {
                    488:        int c;
                    489:        bool do_test;
                    490:        bool do_perf;
                    491: 
                    492:        do_test = true;
                    493:        do_perf = true;
                    494: 
                    495:        while ((c = getopt(ac, av, "tp")) != -1) {
                    496:                switch (c) {
                    497:                 case 't':      // test only
                    498:                        do_perf = false;
                    499:                        break;
                    500:                 case 'p':      // perf only
                    501:                        do_test = false;
                    502:                        break;
                    503:                 default:
                    504:                        usage();
                    505:                }
                    506:        }
                    507:        ac -= optind;
                    508:        av += optind;
                    509:        argc = ac;
1.1.1.3 ! root      510:        argv = av;
1.1       root      511: 
                    512:        // 本当はコンストラクタを呼ぶべきだが、そうすると必要なオブジェクトが
                    513:        // 芋づる式に増えて正しく解決するのは面倒。ここのテストではとりあえず
                    514:        // 存在しててアクセスできればいい程度なのでこれで誤魔化してある。
                    515:        cpu = (m68kcpu *)calloc(sizeof(*cpu), 1);
                    516: 
                    517:        if (do_test) {
                    518:                test_add_8();
                    519:                test_add_16();
                    520:                test_add_32();
                    521:                test_sub_8();
                    522:                test_sub_16();
                    523:                test_sub_32();
                    524:                test_addx_32();
                    525:        }
                    526: 
                    527:        if (do_perf) {
                    528:                perf_asl_32();
                    529:                perf_lsl_32();
                    530:                perf_roxl_32();
                    531:                perf_rol_32();
                    532:                perf_asr_32();
                    533:                perf_lsr_32();
                    534:                perf_roxr_32();
                    535:                perf_ror_32();
                    536:                perf_add_32();
                    537:        }
                    538: 
                    539:        return 0;
                    540: }
                    541: 
                    542: void
                    543: usage()
                    544: {
                    545:        fprintf(stderr, "usage: %s [-t] [-p]\n", getprogname());
                    546:        exit(1);
                    547: }

unix.superglobalmegacorp.com

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