|
|
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.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.1.7 ! root 64: xp_equal(uint32 actValue, m680x0CCR& actCCR, uint32 expValue,
1.1 root 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.1.7 ! root 98: xp_equal64(uint64 actValue, m680x0CCR& actCCR, uint64 expValue,
1.1 root 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.7 ! root 287: test_add(m680x0ACC& 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.7 ! root 317: test_add_8(m680x0ACC& 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.7 ! root 325: test_add_16(m680x0ACC& 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.7 ! root 333: test_add_32(m680x0ACC& 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.7 ! root 341: test_sub(m680x0ACC& 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.7 ! root 378: test_sub_8(m680x0ACC& 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.7 ! root 386: test_sub_16(m680x0ACC& 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.7 ! root 394: test_sub_32(m680x0ACC& 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.7 ! root 420: test_addx_32(m680x0ACC& 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.7 ! root 449: __CONCAT(perf_,name)(m680x0ACC& 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.7 ! root 473: perf_add_32(m680x0ACC& 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.7 ! root 512: std::unique_ptr<m680x0ACC> accptr(new m680x0ACC());
! 513: m680x0ACC& 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.