|
|
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.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 m68kcpu *cpu;
1.1 root 18:
1.1.1.3 root 19: static int argc; // getopt(3) 処理後の argc
20: static char **argv; // getopt(3) 処理後の argv
21: static const char *testname; // 現在のテスト名
22: static int total_errcnt; // 総エラー数
23: static int errcnt; // 現在のセクションのエラー数
24: static char where[256]; // エラー発生箇所
25: static volatile int perf_signaled; // パフォーマンス測定用
26: static struct timeval perf_start; // パフォーマンス測定開始時刻
27: static uint64 perf_count; // パフォーマンス測定用。処理回数
1.1 root 28:
1.1.1.2 root 29: // value を16進数で指定のビット数分の文字列にする
1.1.1.3 root 30: static std::string
1.1.1.2 root 31: hex(uint32 value, int sz)
32: {
33: char buf[32];
34:
35: switch (sz) {
36: case 8:
37: snprintf(buf, sizeof(buf), "%02x", value);
38: break;
39: case 16:
40: snprintf(buf, sizeof(buf), "%04x", value);
41: break;
42: case 32:
43: default:
44: snprintf(buf, sizeof(buf), "%08x", value);
45: break;
46: }
47: return std::string(buf);
48: }
49:
1.1 root 50: // 整数(32bitまで)を検査する
1.1.1.3 root 51: static void __unused
1.1 root 52: xp_equal(uint32 expected, uint32 actual, const char *name)
53: {
54: if (expected != actual) {
55: if (errcnt == 0) {
56: printf("\n");
57: }
58: printf(" %s: %s expects 0x%08x but 0x%08x\n",
59: where, name, expected, actual);
60: errcnt++;
61: }
62: }
63:
64: // 値(32bitまで)と CCR を検査する
1.1.1.3 root 65: static void
1.1 root 66: xp_equal(uint32 actValue, m68030ccr& actCCR, uint32 expValue,
67: bool expX, bool expN, bool expZ, bool expV, bool expC)
68: {
69: if (expValue != actValue ||
70: expX != actCCR.IsX() ||
71: expN != actCCR.IsN() ||
72: expZ != actCCR.IsZ() ||
73: expV != actCCR.IsV() ||
74: expC != actCCR.IsC())
75: {
76: if (errcnt == 0) {
77: printf("\n");
78: }
79: printf("%s %s expects %08x %c%c%c%c%c but %08x %c%c%c%c%c\n",
80: testname, where,
81: expValue,
82: (expX ? 'X' : '-'),
83: (expN ? 'N' : '-'),
84: (expZ ? 'Z' : '-'),
85: (expV ? 'V' : '-'),
86: (expC ? 'C' : '-'),
87: actValue,
88: (actCCR.IsX() ? 'X' : '-'),
89: (actCCR.IsN() ? 'N' : '-'),
90: (actCCR.IsZ() ? 'Z' : '-'),
91: (actCCR.IsV() ? 'V' : '-'),
92: (actCCR.IsC() ? 'C' : '-')
93: );
94: errcnt++;
95: }
96: }
97:
98: // 値(64bit)と CCR を検査する
1.1.1.3 root 99: static void __unused
1.1 root 100: xp_equal64(uint64 actValue, m68030ccr& actCCR, uint64 expValue,
101: bool expX, bool expN, bool expZ, bool expV, bool expC)
102: {
103: if (expValue != actValue ||
104: expX != actCCR.IsX() ||
105: expN != actCCR.IsN() ||
106: expZ != actCCR.IsZ() ||
107: expV != actCCR.IsV() ||
108: expC != actCCR.IsC())
109: {
110: if (errcnt == 0) {
111: printf("\n");
112: }
113: printf("%s %s expects %08x_%08x %c%c%c%c%c but %08x_%08x %c%c%c%c%c\n",
114: testname, where,
115: (uint32)(expValue >> 32),
116: (uint32)(expValue & 0xffffffff),
117: (expX ? 'X' : '-'),
118: (expN ? 'N' : '-'),
119: (expZ ? 'Z' : '-'),
120: (expV ? 'V' : '-'),
121: (expC ? 'C' : '-'),
122: (uint32)(actValue >> 32),
123: (uint32)(actValue & 0xffffffff),
124: (actCCR.IsX() ? 'X' : '-'),
125: (actCCR.IsN() ? 'N' : '-'),
126: (actCCR.IsZ() ? 'Z' : '-'),
127: (actCCR.IsV() ? 'V' : '-'),
128: (actCCR.IsC() ? 'C' : '-')
129: );
130: errcnt++;
131: }
132: }
133:
134: // このテストを実行するかどうか
135: // 引数なしなら全部実行。
136: // 引数ありなら一致すれば実行。
1.1.1.3 root 137: static bool
1.1 root 138: check_exec(const char *name)
139: {
140: if (argc == 0) {
141: return true;
142: }
143:
144: // "test_"/"perf_" を除いた後ろが完全一致するか
145: name += 5;
146: for (int i = 0; i < argc; i++) {
147: if (strcmp(name, argv[i]) == 0) {
148: return true;
149: }
150: }
151:
152: // サイズ部を除いて一致するか
153: // add に対して addx が一致しないようにアンダーバーまでで調べる
1.1.1.3 root 154: std::string name2(name);
155: int u = name2.find('_');
156: if (u != std::string::npos) {
157: name2.erase(u, name2.size() - u);
1.1 root 158: }
159: for (int i = 0; i < argc; i++) {
1.1.1.3 root 160: if (strcmp(name2.c_str(), argv[i]) == 0) {
1.1 root 161: return true;
162: }
163: }
164:
165: return false;
166: }
167:
168: #define start_test() \
169: if (!check_exec(__FUNCTION__)) \
170: return; \
171: start_test_func(__FUNCTION__)
172:
1.1.1.3 root 173: static void
1.1 root 174: start_test_func(const char *name)
175: {
176: testname = name;
177: printf("%s ", testname);
178: fflush(stdout);
179: errcnt = 0;
180: }
181:
1.1.1.3 root 182: static void
1.1 root 183: end_test()
184: {
185: if (errcnt == 0) {
186: printf("ok\n");
187: } else {
188: printf("%d error(s)\n", errcnt);
189: }
190: total_errcnt += errcnt;
191: }
192:
193: #define START_PERF \
194: if (!check_exec(__FUNCTION__)) \
195: return; \
196: start_perf_func(__FUNCTION__)
197:
198: #define END_PERF \
199: end_perf_func()
200:
1.1.1.3 root 201: static void
1.1 root 202: signal_alarm(int signo)
203: {
204: perf_signaled = 1;
205: }
206:
1.1.1.3 root 207: static void
1.1 root 208: start_perf_func(const char *name)
209: {
210: testname = name;
211: printf("%s\t... ", testname);
212: fflush(stdout);
213:
214: perf_count = 0;
215: perf_signaled = 0;
216: signal(SIGALRM, signal_alarm);
217: struct itimerval it = {};
218: it.it_value.tv_sec = PERF_SEC;
219:
220: gettimeofday(&perf_start, NULL);
221: setitimer(ITIMER_REAL, &it, NULL);
222: }
223:
1.1.1.3 root 224: static void
1.1 root 225: end_perf_func()
226: {
227: struct timeval end, result;
228:
229: gettimeofday(&end, NULL);
230: timersub(&end, &perf_start, &result);
231:
232: uint64 usec = (uint64)result.tv_sec * 1000000 + (uint64)result.tv_usec;
233: printf("%" PRIu64 " times/usec\n", perf_count / usec);
234: }
235:
236: // 乱数
1.1.1.3 root 237: static uint32
1.1 root 238: xor32()
239: {
240: static uint32 y = 2463534242;
241: y = y ^ (y << 13);
242: y = y ^ (y >> 17);
243: y = y ^ (y << 5);
244: return y;
245: }
246:
247: // sz ビット目(最下位を0とする)を立てた値を返す
248: // sz は 0..63
1.1.1.3 root 249: static uint64
1.1 root 250: BIT(int sz)
251: {
252: return (1ULL << sz);
253: }
254:
255: // 下位 sz ビットがすべて 1 の値を返す
1.1.1.3 root 256: static uint32
1.1 root 257: MASK(int sz)
258: {
259: return (1ULL << sz) - 1;
260: }
261:
262: // value を sz ビット符号付き整数とした時、負かどうかを返す
263: // sz は 8, 16, 32
1.1.1.3 root 264: static bool
1.1 root 265: ISNEG(uint64 value, int sz)
266: {
267: return ((value & BIT(sz - 1)) != 0);
268: }
269:
270: //
271: // add,sub
272: //
273:
1.1.1.3 root 274: static uint32 add_table[] = {
1.1 root 275: 0x00000000,
276: 0x00000001,
277: 0x0000007f,
278: 0x00000080,
279: 0x000000ff,
280: 0x00007fff,
281: 0x00008000,
282: 0x0000ffff,
283: 0x7fffffff,
284: 0x80000000,
285: 0xffffffff,
286: };
287:
1.1.1.3 root 288: static void
1.1 root 289: test_add(int sz)
290: {
291: for (int i = 0; i < countof(add_table); i++) {
292: for (int j = 0; j < countof(add_table); j++) {
293: uint64 src = add_table[i] & MASK(sz);
294: uint64 dst = add_table[j] & MASK(sz);
295:
296: uint64 tmp = src + dst;
297: uint64 res = tmp & MASK(sz);
1.1.1.2 root 298: std::string w = hex(src, sz) + " + " + hex(dst, sz);
299: strlcpy(where, w.c_str(), sizeof(where));
1.1 root 300: bool C = tmp & BIT(sz);
301: bool V = ((res ^ src) & (res ^ dst)) & BIT(sz - 1);
302:
303: uint32 actual;
304: if (sz == 8) {
305: actual = acc_add_8(cpu, src, dst);
306: } else if (sz == 16) {
307: actual = acc_add_16(cpu, src, dst);
308: } else {
309: actual = acc_add_32(cpu, src, dst);
310: }
311:
312: xp_equal(actual, CCR, res,
313: C, ISNEG(res, sz), (res == 0), V, C);
314: }
315: }
316: }
317:
1.1.1.3 root 318: static void
1.1 root 319: test_add_8()
320: {
321: start_test();
322: test_add(8);
323: end_test();
324: }
325:
1.1.1.3 root 326: static void
1.1 root 327: test_add_16()
328: {
329: start_test();
330: test_add(16);
331: end_test();
332: }
333:
1.1.1.3 root 334: static void
1.1 root 335: test_add_32()
336: {
337: start_test();
338: test_add(32);
339: end_test();
340: }
341:
1.1.1.3 root 342: static void
1.1 root 343: test_sub(int sz)
344: {
345: for (int i = 0; i < countof(add_table); i++) {
346: for (int j = 0; j < countof(add_table); j++) {
347: uint64 src = add_table[i] & MASK(sz);
348: uint64 dst = add_table[j] & MASK(sz);
349:
350: uint64 tmp;
351: if (sz == 8) {
352: tmp = (uint64)dst - (uint64)src;
353: } else if (sz == 16) {
354: tmp = (uint64)dst - (uint64)src;
355: } else {
356: tmp = (uint64)dst - (uint64)src;
357: }
358: uint64 res = tmp & MASK(sz);
1.1.1.2 root 359: std::string w = hex(dst, sz) + " - " + hex(src, sz);
360: strlcpy(where, w.c_str(), sizeof(where));
1.1 root 361: bool C = tmp & BIT(sz);
362: bool V = ((src ^ dst) & (res ^ dst)) & BIT(sz - 1);
363:
364: uint32 actual;
365: if (sz == 8) {
366: actual = acc_sub_8(cpu, src, dst);
367: } else if (sz == 16) {
368: actual = acc_sub_16(cpu, src, dst);
369: } else {
370: actual = acc_sub_32(cpu, src, dst);
371: }
372:
373: xp_equal(actual, CCR, res,
374: C, ISNEG(res, sz), (res == 0), V, C);
375: }
376: }
377: }
378:
1.1.1.3 root 379: static void
1.1 root 380: test_sub_8()
381: {
382: start_test();
383: test_sub(8);
384: end_test();
385: }
386:
1.1.1.3 root 387: static void
1.1 root 388: test_sub_16()
389: {
390: start_test();
391: test_sub(16);
392: end_test();
393: }
394:
1.1.1.3 root 395: static void
1.1 root 396: test_sub_32()
397: {
398: start_test();
399: test_sub(32);
400: end_test();
401: }
402:
403:
404: //
405: // addx
406: //
1.1.1.3 root 407: static struct {
1.1 root 408: uint32 src, dst;
409: bool inX;
410: uint32 res;
411: bool expN, expZ, expV, expC;
412: } addx32_table[] = {
413: // src dst X res N Z V C
414: { 0x00000000, 0xffffffff, 0, 0xffffffff, 1, 0, 0, 0 },
415: { 0x00000000, 0xffffffff, 1, 0x00000000, 0, 1, 0, 1 },
416: { 0x7fffffff, 0x00000001, 0, 0x80000000, 1, 0, 1, 0 },
417: { 0x7fffffff, 0x00000000, 1, 0x80000000, 1, 0, 1, 0 },
418: { 0x7fffffff, 0x80000000, 1, 0x00000000, 0, 1, 0, 1 },
419: };
420:
1.1.1.3 root 421: static void
1.1 root 422: test_addx_32()
423: {
424: start_test();
425: for (int i = 0; i < countof(addx32_table); i++) {
426: uint32 src = addx32_table[i].src;
427: uint32 dst = addx32_table[i].dst;
428: bool inX = addx32_table[i].inX;
429: uint32 res = addx32_table[i].res;
430: bool expN = addx32_table[i].expN;
431: bool expZ = addx32_table[i].expZ;
432: bool expV = addx32_table[i].expV;
433: bool expC = addx32_table[i].expC;
434: sprintf(where, "%08x + %08x + %d", src, dst, inX);
435:
436: CCR.PutX(inX);
437: CCR.PutZ(true);
438: uint32 actual = acc_addx_32(cpu, src, dst);
439: xp_equal(actual, CCR, res, expC, expN, expZ, expV, expC);
440: }
441: end_test();
442: }
443:
444: //
445: // rotate/shift
446: //
447:
448: // ローテート/シフト系のパフォーマンス測定
449: #define DEFINE_PERF_ROTATE(name) \
1.1.1.3 root 450: static void \
1.1 root 451: __CONCAT(perf_,name)() \
452: { \
453: START_PERF; \
454: volatile uint32 dst = 0; \
455: for (; perf_signaled == 0;) { \
456: for (int count = 0; count < 32; count++) { \
457: uint32 src = xor32(); \
458: dst ^= __CONCAT(acc_,name)(cpu, src, count); \
459: perf_count++; \
460: } \
461: } \
1.1.1.4 ! root 462: (void)dst; \
1.1 root 463: END_PERF; \
464: }
465: DEFINE_PERF_ROTATE(asl_32)
466: DEFINE_PERF_ROTATE(lsl_32)
467: DEFINE_PERF_ROTATE(roxl_32)
468: DEFINE_PERF_ROTATE(rol_32)
469: DEFINE_PERF_ROTATE(asr_32)
470: DEFINE_PERF_ROTATE(lsr_32)
471: DEFINE_PERF_ROTATE(roxr_32)
472: DEFINE_PERF_ROTATE(ror_32)
473:
1.1.1.3 root 474: static void
1.1 root 475: perf_add_32()
476: {
477: START_PERF;
478: volatile uint32 dst = 0;
479: for (; perf_signaled == 0; ) {
480: uint32 src = xor32();
481: dst = acc_add_32(cpu, src, dst);
482: perf_count++;
483: }
484: END_PERF;
485: }
486:
487: int
488: main(int ac, char *av[])
489: {
490: int c;
491: bool do_test;
492: bool do_perf;
493:
494: do_test = true;
495: do_perf = true;
496:
497: while ((c = getopt(ac, av, "tp")) != -1) {
498: switch (c) {
499: case 't': // test only
500: do_perf = false;
501: break;
502: case 'p': // perf only
503: do_test = false;
504: break;
505: default:
506: usage();
507: }
508: }
509: ac -= optind;
510: av += optind;
511: argc = ac;
1.1.1.3 root 512: argv = av;
1.1 root 513:
514: // 本当はコンストラクタを呼ぶべきだが、そうすると必要なオブジェクトが
515: // 芋づる式に増えて正しく解決するのは面倒。ここのテストではとりあえず
516: // 存在しててアクセスできればいい程度なのでこれで誤魔化してある。
517: cpu = (m68kcpu *)calloc(sizeof(*cpu), 1);
518:
519: if (do_test) {
520: test_add_8();
521: test_add_16();
522: test_add_32();
523: test_sub_8();
524: test_sub_16();
525: test_sub_32();
526: test_addx_32();
527: }
528:
529: if (do_perf) {
530: perf_asl_32();
531: perf_lsl_32();
532: perf_roxl_32();
533: perf_rol_32();
534: perf_asr_32();
535: perf_lsr_32();
536: perf_roxr_32();
537: perf_ror_32();
538: perf_add_32();
539: }
540:
541: return 0;
542: }
543:
544: void
545: usage()
546: {
547: fprintf(stderr, "usage: %s [-t] [-p]\n", getprogname());
548: exit(1);
549: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.