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

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

unix.superglobalmegacorp.com

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