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

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

unix.superglobalmegacorp.com

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