|
|
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:
7: #include "m68030core.h"
8: #include "m68030acc.h"
1.1.1.3 ! root 9: #include <csignal>
1.1 root 10:
11: // パフォーマンステストの秒数
12: #define PERF_SEC (3)
13:
1.1.1.3 ! root 14: [[noreturn]] void usage();
1.1 root 15:
1.1.1.3 ! root 16: static m68kcpu *cpu;
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; // パフォーマンス測定用
! 25: static struct timeval perf_start; // パフォーマンス測定開始時刻
! 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 root 65: xp_equal(uint32 actValue, m68030ccr& actCCR, uint32 expValue,
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 root 99: xp_equal64(uint64 actValue, m68030ccr& actCCR, uint64 expValue,
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:
219: gettimeofday(&perf_start, NULL);
220: setitimer(ITIMER_REAL, &it, NULL);
221: }
222:
1.1.1.3 ! root 223: static void
1.1 root 224: end_perf_func()
225: {
226: struct timeval end, result;
227:
228: gettimeofday(&end, NULL);
229: timersub(&end, &perf_start, &result);
230:
231: uint64 usec = (uint64)result.tv_sec * 1000000 + (uint64)result.tv_usec;
232: printf("%" PRIu64 " times/usec\n", perf_count / usec);
233: }
234:
235: // 乱数
1.1.1.3 ! root 236: static uint32
1.1 root 237: xor32()
238: {
239: static uint32 y = 2463534242;
240: y = y ^ (y << 13);
241: y = y ^ (y >> 17);
242: y = y ^ (y << 5);
243: return y;
244: }
245:
246: // sz ビット目(最下位を0とする)を立てた値を返す
247: // sz は 0..63
1.1.1.3 ! root 248: static uint64
1.1 root 249: BIT(int sz)
250: {
251: return (1ULL << sz);
252: }
253:
254: // 下位 sz ビットがすべて 1 の値を返す
1.1.1.3 ! root 255: static uint32
1.1 root 256: MASK(int sz)
257: {
258: return (1ULL << sz) - 1;
259: }
260:
261: // value を sz ビット符号付き整数とした時、負かどうかを返す
262: // sz は 8, 16, 32
1.1.1.3 ! root 263: static bool
1.1 root 264: ISNEG(uint64 value, int sz)
265: {
266: return ((value & BIT(sz - 1)) != 0);
267: }
268:
269: //
270: // add,sub
271: //
272:
1.1.1.3 ! root 273: static uint32 add_table[] = {
1.1 root 274: 0x00000000,
275: 0x00000001,
276: 0x0000007f,
277: 0x00000080,
278: 0x000000ff,
279: 0x00007fff,
280: 0x00008000,
281: 0x0000ffff,
282: 0x7fffffff,
283: 0x80000000,
284: 0xffffffff,
285: };
286:
1.1.1.3 ! root 287: static void
1.1 root 288: test_add(int sz)
289: {
290: for (int i = 0; i < countof(add_table); i++) {
291: for (int j = 0; j < countof(add_table); j++) {
292: uint64 src = add_table[i] & MASK(sz);
293: uint64 dst = add_table[j] & MASK(sz);
294:
295: uint64 tmp = src + dst;
296: uint64 res = tmp & MASK(sz);
1.1.1.2 root 297: std::string w = hex(src, sz) + " + " + hex(dst, sz);
298: strlcpy(where, w.c_str(), sizeof(where));
1.1 root 299: bool C = tmp & BIT(sz);
300: bool V = ((res ^ src) & (res ^ dst)) & BIT(sz - 1);
301:
302: uint32 actual;
303: if (sz == 8) {
304: actual = acc_add_8(cpu, src, dst);
305: } else if (sz == 16) {
306: actual = acc_add_16(cpu, src, dst);
307: } else {
308: actual = acc_add_32(cpu, src, dst);
309: }
310:
311: xp_equal(actual, CCR, res,
312: C, ISNEG(res, sz), (res == 0), V, C);
313: }
314: }
315: }
316:
1.1.1.3 ! root 317: static void
1.1 root 318: test_add_8()
319: {
320: start_test();
321: test_add(8);
322: end_test();
323: }
324:
1.1.1.3 ! root 325: static void
1.1 root 326: test_add_16()
327: {
328: start_test();
329: test_add(16);
330: end_test();
331: }
332:
1.1.1.3 ! root 333: static void
1.1 root 334: test_add_32()
335: {
336: start_test();
337: test_add(32);
338: end_test();
339: }
340:
1.1.1.3 ! root 341: static void
1.1 root 342: test_sub(int sz)
343: {
344: for (int i = 0; i < countof(add_table); i++) {
345: for (int j = 0; j < countof(add_table); j++) {
346: uint64 src = add_table[i] & MASK(sz);
347: uint64 dst = add_table[j] & MASK(sz);
348:
349: uint64 tmp;
350: if (sz == 8) {
351: tmp = (uint64)dst - (uint64)src;
352: } else if (sz == 16) {
353: tmp = (uint64)dst - (uint64)src;
354: } else {
355: tmp = (uint64)dst - (uint64)src;
356: }
357: uint64 res = tmp & MASK(sz);
1.1.1.2 root 358: std::string w = hex(dst, sz) + " - " + hex(src, sz);
359: strlcpy(where, w.c_str(), sizeof(where));
1.1 root 360: bool C = tmp & BIT(sz);
361: bool V = ((src ^ dst) & (res ^ dst)) & BIT(sz - 1);
362:
363: uint32 actual;
364: if (sz == 8) {
365: actual = acc_sub_8(cpu, src, dst);
366: } else if (sz == 16) {
367: actual = acc_sub_16(cpu, src, dst);
368: } else {
369: actual = acc_sub_32(cpu, src, dst);
370: }
371:
372: xp_equal(actual, CCR, res,
373: C, ISNEG(res, sz), (res == 0), V, C);
374: }
375: }
376: }
377:
1.1.1.3 ! root 378: static void
1.1 root 379: test_sub_8()
380: {
381: start_test();
382: test_sub(8);
383: end_test();
384: }
385:
1.1.1.3 ! root 386: static void
1.1 root 387: test_sub_16()
388: {
389: start_test();
390: test_sub(16);
391: end_test();
392: }
393:
1.1.1.3 ! root 394: static void
1.1 root 395: test_sub_32()
396: {
397: start_test();
398: test_sub(32);
399: end_test();
400: }
401:
402:
403: //
404: // addx
405: //
1.1.1.3 ! root 406: static struct {
1.1 root 407: uint32 src, dst;
408: bool inX;
409: uint32 res;
410: bool expN, expZ, expV, expC;
411: } addx32_table[] = {
412: // src dst X res N Z V C
413: { 0x00000000, 0xffffffff, 0, 0xffffffff, 1, 0, 0, 0 },
414: { 0x00000000, 0xffffffff, 1, 0x00000000, 0, 1, 0, 1 },
415: { 0x7fffffff, 0x00000001, 0, 0x80000000, 1, 0, 1, 0 },
416: { 0x7fffffff, 0x00000000, 1, 0x80000000, 1, 0, 1, 0 },
417: { 0x7fffffff, 0x80000000, 1, 0x00000000, 0, 1, 0, 1 },
418: };
419:
1.1.1.3 ! root 420: static void
1.1 root 421: test_addx_32()
422: {
423: start_test();
424: for (int i = 0; i < countof(addx32_table); i++) {
425: uint32 src = addx32_table[i].src;
426: uint32 dst = addx32_table[i].dst;
427: bool inX = addx32_table[i].inX;
428: uint32 res = addx32_table[i].res;
429: bool expN = addx32_table[i].expN;
430: bool expZ = addx32_table[i].expZ;
431: bool expV = addx32_table[i].expV;
432: bool expC = addx32_table[i].expC;
433: sprintf(where, "%08x + %08x + %d", src, dst, inX);
434:
435: CCR.PutX(inX);
436: CCR.PutZ(true);
437: uint32 actual = acc_addx_32(cpu, src, dst);
438: xp_equal(actual, CCR, res, expC, expN, expZ, expV, expC);
439: }
440: end_test();
441: }
442:
443: //
444: // rotate/shift
445: //
446:
447: // ローテート/シフト系のパフォーマンス測定
448: #define DEFINE_PERF_ROTATE(name) \
1.1.1.3 ! root 449: static void \
1.1 root 450: __CONCAT(perf_,name)() \
451: { \
452: START_PERF; \
453: volatile uint32 dst = 0; \
454: for (; perf_signaled == 0;) { \
455: for (int count = 0; count < 32; count++) { \
456: uint32 src = xor32(); \
457: dst ^= __CONCAT(acc_,name)(cpu, src, count); \
458: perf_count++; \
459: } \
460: } \
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 root 473: perf_add_32()
474: {
475: START_PERF;
476: volatile uint32 dst = 0;
477: for (; perf_signaled == 0; ) {
478: uint32 src = xor32();
479: dst = acc_add_32(cpu, src, dst);
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:
512: // 本当はコンストラクタを呼ぶべきだが、そうすると必要なオブジェクトが
513: // 芋づる式に増えて正しく解決するのは面倒。ここのテストではとりあえず
514: // 存在しててアクセスできればいい程度なのでこれで誤魔化してある。
515: cpu = (m68kcpu *)calloc(sizeof(*cpu), 1);
516:
517: if (do_test) {
518: test_add_8();
519: test_add_16();
520: test_add_32();
521: test_sub_8();
522: test_sub_16();
523: test_sub_32();
524: test_addx_32();
525: }
526:
527: if (do_perf) {
528: perf_asl_32();
529: perf_lsl_32();
530: perf_roxl_32();
531: perf_rol_32();
532: perf_asr_32();
533: perf_lsr_32();
534: perf_roxr_32();
535: perf_ror_32();
536: perf_add_32();
537: }
538:
539: return 0;
540: }
541:
542: void
543: usage()
544: {
545: fprintf(stderr, "usage: %s [-t] [-p]\n", getprogname());
546: exit(1);
547: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.