|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.