|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2017 [email protected]
4: //
5:
6: #include "header.h"
7: #include <csignal>
8: #include "m68030core.h"
9: #include "m68030acc.h"
10:
11: // パフォーマンステストの秒数
12: #define PERF_SEC (3)
13:
14: void usage();
15:
16: m68kcpu *cpu;
17:
18: int argc; // getopt(3) 処理後の argc
19: const char **argv; // getopt(3) 処理後の argv
20: const char *testname; // 現在のテスト名
21: int total_errcnt; // 総エラー数
22: int errcnt; // 現在のセクションのエラー数
23: char where[256]; // エラー発生箇所
24: volatile int perf_signaled; // パフォーマンス測定用
25: struct timeval perf_start; // パフォーマンス測定開始時刻
26: uint64 perf_count; // パフォーマンス測定用。処理回数
27:
1.1.1.2 ! root 28: // value を16進数で指定のビット数分の文字列にする
! 29: std::string
! 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まで)を検査する
50: void
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 を検査する
64: void
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 を検査する
98: void
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: // 引数ありなら一致すれば実行。
136: bool
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 が一致しないようにアンダーバーまでで調べる
153: char name2[strlen(name) + 1];
154: strcpy(name2, name);
155: char *u = strchr(name2, '_');
156: if (u) {
157: *u = '\0';
158: }
159: for (int i = 0; i < argc; i++) {
160: if (strcmp(name2, argv[i]) == 0) {
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:
173: void
174: start_test_func(const char *name)
175: {
176: testname = name;
177: printf("%s ", testname);
178: fflush(stdout);
179: errcnt = 0;
180: }
181:
182: void
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:
201: void
202: signal_alarm(int signo)
203: {
204: perf_signaled = 1;
205: }
206:
207: void
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:
224: void
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: // 乱数
237: uint32
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
249: uint64
250: BIT(int sz)
251: {
252: return (1ULL << sz);
253: }
254:
255: // 下位 sz ビットがすべて 1 の値を返す
256: uint32
257: MASK(int sz)
258: {
259: return (1ULL << sz) - 1;
260: }
261:
262: // value を sz ビット符号付き整数とした時、負かどうかを返す
263: // sz は 8, 16, 32
264: bool
265: ISNEG(uint64 value, int sz)
266: {
267: return ((value & BIT(sz - 1)) != 0);
268: }
269:
270: //
271: // add,sub
272: //
273:
274: uint32 add_table[] = {
275: 0x00000000,
276: 0x00000001,
277: 0x0000007f,
278: 0x00000080,
279: 0x000000ff,
280: 0x00007fff,
281: 0x00008000,
282: 0x0000ffff,
283: 0x7fffffff,
284: 0x80000000,
285: 0xffffffff,
286: };
287:
288: void
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:
318: void
319: test_add_8()
320: {
321: start_test();
322: test_add(8);
323: end_test();
324: }
325:
326: void
327: test_add_16()
328: {
329: start_test();
330: test_add(16);
331: end_test();
332: }
333:
334: void
335: test_add_32()
336: {
337: start_test();
338: test_add(32);
339: end_test();
340: }
341:
342: void
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:
379: void
380: test_sub_8()
381: {
382: start_test();
383: test_sub(8);
384: end_test();
385: }
386:
387: void
388: test_sub_16()
389: {
390: start_test();
391: test_sub(16);
392: end_test();
393: }
394:
395: void
396: test_sub_32()
397: {
398: start_test();
399: test_sub(32);
400: end_test();
401: }
402:
403:
404: //
405: // addx
406: //
407: struct {
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:
421: void
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) \
450: void \
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: } \
462: END_PERF; \
463: }
464: DEFINE_PERF_ROTATE(asl_32)
465: DEFINE_PERF_ROTATE(lsl_32)
466: DEFINE_PERF_ROTATE(roxl_32)
467: DEFINE_PERF_ROTATE(rol_32)
468: DEFINE_PERF_ROTATE(asr_32)
469: DEFINE_PERF_ROTATE(lsr_32)
470: DEFINE_PERF_ROTATE(roxr_32)
471: DEFINE_PERF_ROTATE(ror_32)
472:
473: void
474: perf_add_32()
475: {
476: START_PERF;
477: volatile uint32 dst = 0;
478: for (; perf_signaled == 0; ) {
479: uint32 src = xor32();
480: dst = acc_add_32(cpu, src, dst);
481: perf_count++;
482: }
483: END_PERF;
484: }
485:
486: int
487: main(int ac, char *av[])
488: {
489: int c;
490: bool do_test;
491: bool do_perf;
492:
493: do_test = true;
494: do_perf = true;
495:
496: while ((c = getopt(ac, av, "tp")) != -1) {
497: switch (c) {
498: case 't': // test only
499: do_perf = false;
500: break;
501: case 'p': // perf only
502: do_test = false;
503: break;
504: default:
505: usage();
506: }
507: }
508: ac -= optind;
509: av += optind;
510: argc = ac;
511: argv = (const char **)av;
512:
513: // 本当はコンストラクタを呼ぶべきだが、そうすると必要なオブジェクトが
514: // 芋づる式に増えて正しく解決するのは面倒。ここのテストではとりあえず
515: // 存在しててアクセスできればいい程度なのでこれで誤魔化してある。
516: cpu = (m68kcpu *)calloc(sizeof(*cpu), 1);
517:
518: if (do_test) {
519: test_add_8();
520: test_add_16();
521: test_add_32();
522: test_sub_8();
523: test_sub_16();
524: test_sub_32();
525: test_addx_32();
526: }
527:
528: if (do_perf) {
529: perf_asl_32();
530: perf_lsl_32();
531: perf_roxl_32();
532: perf_rol_32();
533: perf_asr_32();
534: perf_lsr_32();
535: perf_roxr_32();
536: perf_ror_32();
537: perf_add_32();
538: }
539:
540: return 0;
541: }
542:
543: void
544: usage()
545: {
546: fprintf(stderr, "usage: %s [-t] [-p]\n", getprogname());
547: exit(1);
548: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.