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