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

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.1.7   root        8: #include "m680x0acc.h"
1.1.1.8 ! root        9: #include "stopwatch.h"
1.1.1.3   root       10: #include <csignal>
1.1.1.4   root       11: #include <sys/time.h>
1.1       root       12: 
                     13: // パフォーマンステストの秒数
                     14: #define PERF_SEC       (3)
                     15: 
1.1.1.3   root       16: [[noreturn]] void usage();
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;     // パフォーマンス測定用
1.1.1.8 ! root       25: static Stopwatch sw;                           // パフォーマンス測定用
1.1.1.3   root       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.1.7   root       65: xp_equal(uint32 actValue, m680x0CCR& actCCR, uint32 expValue,
1.1       root       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.1.7   root       99: xp_equal64(uint64 actValue, m680x0CCR& actCCR, uint64 expValue,
1.1       root      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: 
1.1.1.8 ! root      219:        sw.Restart();
1.1       root      220:        setitimer(ITIMER_REAL, &it, NULL);
                    221: }
                    222: 
1.1.1.3   root      223: static void
1.1       root      224: end_perf_func()
                    225: {
1.1.1.8 ! root      226:        sw.Stop();
1.1       root      227: 
1.1.1.8 ! root      228:        uint64 usec = nsec_to_usec(sw.Elapsed_nsec());
1.1       root      229:        printf("%" PRIu64 " times/usec\n", perf_count / usec);
                    230: }
                    231: 
                    232: // 乱数
1.1.1.3   root      233: static uint32
1.1       root      234: xor32()
                    235: {
                    236:        static uint32 y = 2463534242;
                    237:        y = y ^ (y << 13);
                    238:        y = y ^ (y >> 17);
                    239:        y = y ^ (y << 5);
                    240:        return y;
                    241: }
                    242: 
                    243: // sz ビット目(最下位を0とする)を立てた値を返す
                    244: // sz は 0..63
1.1.1.3   root      245: static uint64
1.1       root      246: BIT(int sz)
                    247: {
                    248:        return (1ULL << sz);
                    249: }
                    250: 
                    251: // 下位 sz ビットがすべて 1 の値を返す
1.1.1.3   root      252: static uint32
1.1       root      253: MASK(int sz)
                    254: {
                    255:        return (1ULL << sz) - 1;
                    256: }
                    257: 
                    258: // value を sz ビット符号付き整数とした時、負かどうかを返す
                    259: // sz は 8, 16, 32
1.1.1.3   root      260: static bool
1.1       root      261: ISNEG(uint64 value, int sz)
                    262: {
                    263:        return ((value & BIT(sz - 1)) != 0);
                    264: }
                    265: 
                    266: //
                    267: // add,sub
                    268: //
                    269: 
1.1.1.3   root      270: static uint32 add_table[] = {
1.1       root      271:        0x00000000,
                    272:        0x00000001,
                    273:        0x0000007f,
                    274:        0x00000080,
                    275:        0x000000ff,
                    276:        0x00007fff,
                    277:        0x00008000,
                    278:        0x0000ffff,
                    279:        0x7fffffff,
                    280:        0x80000000,
                    281:        0xffffffff,
                    282: };
                    283: 
1.1.1.3   root      284: static void
1.1.1.7   root      285: test_add(m680x0ACC& acc, int sz)
1.1       root      286: {
                    287:        for (int i = 0; i < countof(add_table); i++) {
                    288:                for (int j = 0; j < countof(add_table); j++) {
                    289:                        uint64 src = add_table[i] & MASK(sz);
                    290:                        uint64 dst = add_table[j] & MASK(sz);
                    291: 
                    292:                        uint64 tmp = src + dst;
                    293:                        uint64 res = tmp & MASK(sz);
1.1.1.2   root      294:                        std::string w = hex(src, sz) + " + " + hex(dst, sz);
                    295:                        strlcpy(where, w.c_str(), sizeof(where));
1.1       root      296:                        bool C = tmp & BIT(sz);
                    297:                        bool V = ((res ^ src) & (res ^ dst)) & BIT(sz - 1);
                    298: 
                    299:                        uint32 actual;
                    300:                        if (sz == 8) {
1.1.1.5   root      301:                                actual = acc.add_8(src, dst);
1.1       root      302:                        } else if (sz == 16) {
1.1.1.5   root      303:                                actual = acc.add_16(src, dst);
1.1       root      304:                        } else {
1.1.1.5   root      305:                                actual = acc.add_32(src, dst);
1.1       root      306:                        }
                    307: 
1.1.1.5   root      308:                        xp_equal(actual, acc, res,
1.1       root      309:                                C, ISNEG(res, sz), (res == 0), V, C);
                    310:                }
                    311:        }
                    312: }
                    313: 
1.1.1.3   root      314: static void
1.1.1.7   root      315: test_add_8(m680x0ACC& acc)
1.1       root      316: {
                    317:        start_test();
1.1.1.5   root      318:        test_add(acc, 8);
1.1       root      319:        end_test();
                    320: }
                    321: 
1.1.1.3   root      322: static void
1.1.1.7   root      323: test_add_16(m680x0ACC& acc)
1.1       root      324: {
                    325:        start_test();
1.1.1.5   root      326:        test_add(acc, 16);
1.1       root      327:        end_test();
                    328: }
                    329: 
1.1.1.3   root      330: static void
1.1.1.7   root      331: test_add_32(m680x0ACC& acc)
1.1       root      332: {
                    333:        start_test();
1.1.1.5   root      334:        test_add(acc, 32);
1.1       root      335:        end_test();
                    336: }
                    337: 
1.1.1.3   root      338: static void
1.1.1.7   root      339: test_sub(m680x0ACC& acc, int sz)
1.1       root      340: {
                    341:        for (int i = 0; i < countof(add_table); i++) {
                    342:                for (int j = 0; j < countof(add_table); j++) {
                    343:                        uint64 src = add_table[i] & MASK(sz);
                    344:                        uint64 dst = add_table[j] & MASK(sz);
                    345: 
                    346:                        uint64 tmp;
                    347:                        if (sz == 8) {
                    348:                                tmp = (uint64)dst - (uint64)src;
                    349:                        } else if (sz == 16) {
                    350:                                tmp = (uint64)dst - (uint64)src;
                    351:                        } else {
                    352:                                tmp = (uint64)dst - (uint64)src;
                    353:                        }
                    354:                        uint64 res = tmp & MASK(sz);
1.1.1.2   root      355:                        std::string w = hex(dst, sz) + " - " + hex(src, sz);
                    356:                        strlcpy(where, w.c_str(), sizeof(where));
1.1       root      357:                        bool C = tmp & BIT(sz);
                    358:                        bool V = ((src ^ dst) & (res ^ dst)) & BIT(sz - 1);
                    359: 
                    360:                        uint32 actual;
                    361:                        if (sz == 8) {
1.1.1.5   root      362:                                actual = acc.sub_8(src, dst);
1.1       root      363:                        } else if (sz == 16) {
1.1.1.5   root      364:                                actual = acc.sub_16(src, dst);
1.1       root      365:                        } else {
1.1.1.5   root      366:                                actual = acc.sub_32(src, dst);
1.1       root      367:                        }
                    368: 
1.1.1.5   root      369:                        xp_equal(actual, acc, res,
1.1       root      370:                                C, ISNEG(res, sz), (res == 0), V, C);
                    371:                }
                    372:        }
                    373: }
                    374: 
1.1.1.3   root      375: static void
1.1.1.7   root      376: test_sub_8(m680x0ACC& acc)
1.1       root      377: {
                    378:        start_test();
1.1.1.5   root      379:        test_sub(acc, 8);
1.1       root      380:        end_test();
                    381: }
                    382: 
1.1.1.3   root      383: static void
1.1.1.7   root      384: test_sub_16(m680x0ACC& acc)
1.1       root      385: {
                    386:        start_test();
1.1.1.5   root      387:        test_sub(acc, 16);
1.1       root      388:        end_test();
                    389: }
                    390: 
1.1.1.3   root      391: static void
1.1.1.7   root      392: test_sub_32(m680x0ACC& acc)
1.1       root      393: {
                    394:        start_test();
1.1.1.5   root      395:        test_sub(acc, 32);
1.1       root      396:        end_test();
                    397: }
                    398: 
                    399: 
                    400: //
                    401: // addx
                    402: //
1.1.1.3   root      403: static struct {
1.1       root      404:        uint32 src, dst;
                    405:        bool inX;
                    406:        uint32 res;
                    407:        bool expN, expZ, expV, expC;
                    408: } addx32_table[] = {
                    409:        // src        dst         X     res         N  Z  V  C
                    410:        { 0x00000000, 0xffffffff, 0,    0xffffffff, 1, 0, 0, 0 },
                    411:        { 0x00000000, 0xffffffff, 1,    0x00000000, 0, 1, 0, 1 },
                    412:        { 0x7fffffff, 0x00000001, 0,    0x80000000, 1, 0, 1, 0 },
                    413:        { 0x7fffffff, 0x00000000, 1,    0x80000000, 1, 0, 1, 0 },
                    414:        { 0x7fffffff, 0x80000000, 1,    0x00000000, 0, 1, 0, 1 },
                    415: };
                    416: 
1.1.1.3   root      417: static void
1.1.1.7   root      418: test_addx_32(m680x0ACC& acc)
1.1       root      419: {
                    420:        start_test();
                    421:        for (int i = 0; i < countof(addx32_table); i++) {
                    422:                uint32 src = addx32_table[i].src;
                    423:                uint32 dst = addx32_table[i].dst;
                    424:                bool   inX = addx32_table[i].inX;
                    425:                uint32 res = addx32_table[i].res;
                    426:                bool  expN = addx32_table[i].expN;
                    427:                bool  expZ = addx32_table[i].expZ;
                    428:                bool  expV = addx32_table[i].expV;
                    429:                bool  expC = addx32_table[i].expC;
1.1.1.6   root      430:                snprintf(where, sizeof(where), "%08x + %08x + %d", src, dst, inX);
1.1       root      431: 
1.1.1.5   root      432:                acc.SetX(inX);
                    433:                acc.SetZ(true);
                    434:                uint32 actual = acc.addx_32(src, dst);
                    435:                xp_equal(actual, acc, res, expC, expN, expZ, expV, expC);
1.1       root      436:        }
                    437:        end_test();
                    438: }
                    439: 
                    440: //
                    441: // rotate/shift
                    442: //
                    443: 
                    444: // ローテート/シフト系のパフォーマンス測定
                    445: #define DEFINE_PERF_ROTATE(name)       \
1.1.1.3   root      446: static void    \
1.1.1.7   root      447: __CONCAT(perf_,name)(m680x0ACC& acc)   \
1.1       root      448: {      \
                    449:        START_PERF;     \
                    450:        volatile uint32 dst = 0;        \
                    451:        for (; perf_signaled == 0;) {   \
                    452:                for (int count = 0; count < 32; count++) {      \
                    453:                        uint32 src = xor32();   \
1.1.1.5   root      454:                        dst ^= acc.name(src, count);    \
1.1       root      455:                        perf_count++;   \
                    456:                }       \
                    457:        }       \
1.1.1.4   root      458:        (void)dst;      \
1.1       root      459:        END_PERF;       \
                    460: }
                    461: DEFINE_PERF_ROTATE(asl_32)
                    462: DEFINE_PERF_ROTATE(lsl_32)
                    463: DEFINE_PERF_ROTATE(roxl_32)
                    464: DEFINE_PERF_ROTATE(rol_32)
                    465: DEFINE_PERF_ROTATE(asr_32)
                    466: DEFINE_PERF_ROTATE(lsr_32)
                    467: DEFINE_PERF_ROTATE(roxr_32)
                    468: DEFINE_PERF_ROTATE(ror_32)
                    469: 
1.1.1.3   root      470: static void
1.1.1.7   root      471: perf_add_32(m680x0ACC& acc)
1.1       root      472: {
                    473:        START_PERF;
                    474:        volatile uint32 dst = 0;
                    475:        for (; perf_signaled == 0; ) {
                    476:                uint32 src = xor32();
1.1.1.5   root      477:                dst = acc.add_32(src, dst);
1.1       root      478:                perf_count++;
                    479:        }
                    480:        END_PERF;
                    481: }
                    482: 
                    483: int
                    484: main(int ac, char *av[])
                    485: {
                    486:        int c;
                    487:        bool do_test;
                    488:        bool do_perf;
                    489: 
                    490:        do_test = true;
                    491:        do_perf = true;
                    492: 
                    493:        while ((c = getopt(ac, av, "tp")) != -1) {
                    494:                switch (c) {
                    495:                 case 't':      // test only
                    496:                        do_perf = false;
                    497:                        break;
                    498:                 case 'p':      // perf only
                    499:                        do_test = false;
                    500:                        break;
                    501:                 default:
                    502:                        usage();
                    503:                }
                    504:        }
                    505:        ac -= optind;
                    506:        av += optind;
                    507:        argc = ac;
1.1.1.3   root      508:        argv = av;
1.1       root      509: 
1.1.1.7   root      510:        std::unique_ptr<m680x0ACC> accptr(new m680x0ACC());
                    511:        m680x0ACC& acc = *(accptr.get());
1.1       root      512: 
                    513:        if (do_test) {
1.1.1.5   root      514:                test_add_8(acc);
                    515:                test_add_16(acc);
                    516:                test_add_32(acc);
                    517:                test_sub_8(acc);
                    518:                test_sub_16(acc);
                    519:                test_sub_32(acc);
                    520:                test_addx_32(acc);
1.1       root      521:        }
                    522: 
                    523:        if (do_perf) {
1.1.1.5   root      524:                perf_asl_32(acc);
                    525:                perf_lsl_32(acc);
                    526:                perf_roxl_32(acc);
                    527:                perf_rol_32(acc);
                    528:                perf_asr_32(acc);
                    529:                perf_lsr_32(acc);
                    530:                perf_roxr_32(acc);
                    531:                perf_ror_32(acc);
                    532:                perf_add_32(acc);
1.1       root      533:        }
                    534: 
                    535:        return 0;
                    536: }
                    537: 
                    538: void
                    539: usage()
                    540: {
                    541:        fprintf(stderr, "usage: %s [-t] [-p]\n", getprogname());
                    542:        exit(1);
                    543: }

unix.superglobalmegacorp.com

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