Annotation of nono/m680x0/testacc.cpp, revision 1.1.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.