|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2021 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: // instruction test for m88100
8: //
9: // optestm88k_gen.cpp (this file)
10: // |
11: // | compile and link on the host
12: // v
13: // optestm88k_gen
14: // |
15: // | (executing it will create following files)
16: // v
17: // +--> optestm88k_add.s ---+
18: // +--> optestm88k_bitfield.s ---+
19: // +--> optestm88k_lda.s ---+
20: // +--> optestm88k_logical.s ---+
21: // +--> optestm88k_muldiv.s ---+
22: // +--> optestm88k_sub.s ---+
23: // +--> optestm88k_table.c ---+
24: // +--> optestm88k_table.h ---+
25: // |
26: // optestm88k_main.[ch] ---+
27: // optestm88k_code.s ---+
28: // | compile and link on m88k
29: // v
30: // optestm88k
31:
32: // XXX mul/div/divu 命令の FPU disabled のケースは未検査
33:
34: #include "header.h"
35: #include <sys/stat.h>
36: #include <sys/wait.h>
37: #include <algorithm>
38: #include <map>
39: #include <tuple>
40: #include <vector>
41:
42: // テスト情報 (グローバル)
43: static const char *testname;
44: static int testnum;
45: // 出力先 (グローバル)
46: static FILE *fp;
47:
48: #define IMM (0xff)
49:
50: // 理解しやすさのため 1, 2, 3 で表現しているが実際は r11, r12, r13 を使う
51: static constexpr uint32 R3(uint32 d, uint32 s1, uint32 s2) {
52: d = (d > 0) ? (d + 10) : 0;
53: s1 = (s1 > 0) ? (s1 + 10) : 0;
54: s2 = (s2 > 0) ? (s2 + 10) : 0;
55: return (d << 16) | (s1 << 8) | s2;
56: }
57: // 3オペランドの場合のレジスタの組み合わせ
58: static std::vector<uint32> reglist3 = {
59: R3(0, 0, 0),
60: R3(0, 0, 1),
61: R3(0, 1, 0),
62: R3(0, 1, 1),
63: R3(0, 1, 2),
64:
65: R3(1, 0, 0),
66: R3(1, 0, 1),
67: R3(1, 1, 0),
68: R3(1, 1, 1),
69: R3(1, 0, 2),
70: R3(1, 2, 0),
71: R3(1, 2, 2),
72: R3(1, 1, 2),
73: R3(1, 2, 1),
74: R3(1, 2, 3),
75: };
76:
77: // 2オペランド(+IMM)の場合のレジスタの組み合わせ
78: #define R2(d, s1) R3(d, s1, 0)
79: static std::vector<uint32> reglist2 = {
80: R2(0, 0),
81: R2(0, 1),
82: R2(1, 0),
83: R2(1, 1),
84: R2(1, 2),
85: };
86:
87: // r0 用の値リスト
88: static std::vector<uint32> v0 = {
89: 0,
90: };
91: // 数値演算用の入力値リスト
92: static std::vector<uint32> vlist_arith = {
93: 0,
94: 1,
95: 2,
96: 0x7f,
97: 0x80,
98: 0xff,
99: 0x7fff,
100: 0x8000,
101: 0xffff,
102: 0x7fffffff,
103: 0x80000000,
104: 0xffffffff,
105: };
106: // ビットフィールド用の入力値リスト
107: // XXX どのパターンで試せばいいか
108: static std::vector<uint32> vlist_bf = {
109: 0x00000000,
110: 0x87654321,
111: 0xffffffff,
112: };
113: // ビットフィールド用の入力 W,O リスト
114: // XXX どのパターンで試せばいいか
115: #define WO(w, o) (((w) << 5) | (o))
116: static std::vector<uint32> vlist_wo = {
117: WO( 0, 0),
118: WO( 0, 1),
119: WO( 0, 2),
120: WO( 0, 31),
121: WO( 1, 0),
122: WO( 1, 1),
123: WO( 1, 31),
124: WO(16, 0),
125: WO(16, 15),
126: WO(16, 16),
127: WO(16, 17),
128: WO(16, 31),
129: WO(31, 0),
130: WO(31, 1),
131: WO(31, 31),
132: };
133: // ff0/ff1 用の入力値リスト
134: static std::vector<uint32> vlist_ff = {
135: 0x00000000,
136: 0x00000001,
137: 0x00000020,
138: 0x00000480,
139: 0x00009000,
140: 0x00010000,
141: 0x00200000,
142: 0x06000000,
143: 0xf0000000,
144: };
145:
146: template <class T>
147: using Tuple3 = std::tuple<T, T, T>;
148: template <class T>
149: using Tuple4 = std::tuple<T, T, T, T>;
150: template <class T>
151: using Tuple5 = std::tuple<T, T, T, T, T>;
152:
153: static std::vector<Tuple5<uint32>> test_arith_reg;
154: static std::vector<Tuple4<uint32>> test_arith_imm;
155: static std::vector<Tuple5<uint32>> test_bitfield_reg;
156: static std::vector<Tuple4<uint32>> test_bitfield_imm;
157: static std::vector<Tuple3<uint32>> test_ff01;
158:
159: // 2オペランドテストの要素を変数に取り出す部分 (副作用のあるマクロ)
160: #define VAR_DIADIC(t, rd, rs2, vs2) \
161: uint32 rd = std::get<0>(t); \
162: uint32 rs2 = std::get<1>(t); \
163: uint32 vs2 = std::get<2>(t)
164:
165: // 3オペランドテストの要素を変数に取り出す部分 (副作用のあるマクロ)
166: #define VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2) \
167: uint32 rd = std::get<0>(t); \
168: uint32 rs1 = std::get<1>(t); \
169: uint32 rs2 = std::get<2>(t); \
170: uint32 vs1 = std::get<3>(t); \
171: uint32 vs2 = std::get<4>(t)
172:
173: // 3オペランド(IMM)テストの要素を変数に取り出す部分 (副作用のあるマクロ)
174: #define VAR_TRI_IMM(t, rd, rs1, vs1, imm) \
175: uint32 rd = std::get<0>(t); \
176: uint32 rs1 = std::get<1>(t); \
177: uint32 vs1 = std::get<2>(t); \
178: uint32 imm = std::get<3>(t)
179:
180:
181: // fp に出力
182: static void out(const char *fmt, ...)
183: {
184: va_list ap;
185:
186: va_start(ap, fmt);
187: vfprintf(fp, fmt, ap);
188: va_end(ap);
189: }
190:
191: // レジスタ regno に即値 imm をセットする
192: static void
193: MOV_imm(int regno, uint32 imm)
194: {
195: if (regno == 0) {
196: // nop
197: } else if (imm == 0) {
198: out(" xor %%r%d, %%r%d, %%r%d\n", regno, regno, regno);
199: } else if (imm < 0x10000) {
200: out(" or %%r%d, %%r0, 0x%04x\n", regno, imm);
201: } else if (imm == 0xffffffff) {
202: out(" or.c %%r%d, %%r0, %%r0 | MOV %%r%d, 0xffffffff\n",
203: regno, regno);
204: } else {
205: out(" or.u %%r%d, %%r0, 0x%04x | MOV %%r%d, 0x%08x\n",
206: regno, (imm >> 16), regno, imm);
207: out(" or %%r%d, %%r%d, 0x%04x\n", regno, regno, imm & 0xffff);
208: }
209: }
210:
211:
212: //
213: // ここからテストコード
214: //
215:
216: // r2: 引数1: グローバル変数の先頭
217: // r2[0] = &exception_occurred
218: // r2[1] = &exception_expected
219: // r3: 引数2: 今回のテストのパラメータの先頭。内容は code ごとに異なる。
220: //
221: // r9: r1 のバックアップ
222: // r10: 期待 rD
223: // r11: rD (テストで使う)、結果の rD をここに入れて返す
224: // r12: rS1 (テストで使う)
225: // r13: rS2 (テストで使う)
226:
227: // add でのオーバーフロー条件
228: static inline bool
229: isovf_add(uint32 s1, uint32 s2, uint32 res)
230: {
231: return (int32)((s1 ^ res) & (s2 ^ res)) < 0;
232: }
233:
234: // sub でのオーバーフロー条件
235: static inline bool
236: isovf_sub(uint32 s1, uint32 s2, uint32 res)
237: {
238: return (int32)((s1 ^ s2) & (s1 ^ res)) < 0;
239: }
240:
241: // 汎用演算命令共通のテストパターン出力部分
242: static void
243: gen_generic_test(const char *mnemonic,
244: uint32 rd, uint32 rs1, uint32 rs2, uint32 vs1, uint32 vs2, uint32 exp_rd)
245: {
246: // rs2 が IMM なら #imm
247: bool is_imm = (rs2 == IMM);
248: uint32& imm = vs2;
249:
250: out("test_%s_%d:\n", testname, testnum);
251: if (is_imm) {
252: out(" /* %s r%d, r%d, #0x%04x (S1=$%08x) */\n",
253: mnemonic, rd, rs1, imm, vs1);
254: } else {
255: out(" /* %s r%d, r%d, r%d (S1=$%08x, S2=$%08x) */\n",
256: mnemonic, rd, rs1, rs2, vs1, vs2);
257: }
258:
259: out(" .word 0x%08x | exp_rd\n", exp_rd);
260: // ここからコード
261: MOV_imm(rs1, vs1);
262: if (!is_imm && rs1 != rs2) {
263: MOV_imm(rs2, vs2);
264: }
265:
266: if (is_imm) {
267: out(" %s %%r%d, %%r%d, 0x%04x | test\n", mnemonic, rd, rs1, imm);
268: } else {
269: out(" %s %%r%d, %%r%d, %%r%d | test\n", mnemonic, rd, rs1, rs2);
270: }
271:
272: if (rd != 11) {
273: out(" or %%r11, %%r0, %%r%d\n", rd);
274: }
275: out(" jmp %%r1\n");
276: out("\n");
277:
278: testnum++;
279: }
280:
281: // 2項ビットフィールド命令共通のテストパターン出力部分
282: // (gen_generic_test と似てるけど微妙に違う)
283: static void
284: gen_bitfield_test(const char *mnemonic,
285: uint32 rd, uint32 rs1, uint32 vs1, uint32 wo, uint32 exp_rd)
286: {
287: uint32 w = (wo >> 5) & 0x1f; // XXX 表記上は 0 なのか 32 なのか
288: uint32 o = wo & 0x1f;
289:
290: out("test_%s_%d:\n", testname, testnum);
291: out(" /* %s r%d, r%d, %d<%d> (S1=$%08x) */\n",
292: mnemonic, rd, rs1, w, o, vs1);
293:
294: out(" .word 0x%08x | exp_rd\n", exp_rd);
295: // ここからコード
296: MOV_imm(rs1, vs1);
297:
298: out(" %s %%r%d, %%r%d, %d<%d> | test\n", mnemonic, rd, rs1, w, o);
299:
300: if (rd != 11) {
301: out(" or %%r11, %%r0, %%r%d\n", rd);
302: }
303: out(" jmp %%r1\n");
304: out("\n");
305:
306: testnum++;
307: }
308:
309: // ff0/ff1 命令共通のテストパターン出力部分
310: // (gen_generic_test と似てるけど微妙に違う)
311: static void
312: gen_ff01_test(const char *mnemonic,
313: uint32 rd, uint32 rs2, uint32 vs2, uint32 exp_rd)
314: {
315: out("test_%s_%d:\n", testname, testnum);
316: out(" /* %s r%d, r%d (S2=$%08x) */\n",
317: mnemonic, rd, rs2, vs2);
318:
319: out(" .word 0x%08x | exp_rd\n", exp_rd);
320: // ここからコード
321: MOV_imm(rs2, vs2);
322:
323: out(" %s %%r%d, %%r%d | test\n", mnemonic, rd, rs2);
324:
325: if (rd != 11) {
326: out(" or %%r11, %%r0, %%r%d\n", rd);
327: }
328: out(" jmp %%r1\n");
329: out("\n");
330:
331: testnum++;
332: }
333:
334: // add/sub 命令共通のテストパターン出力部分
335: // rs2 == IMM なら即値指定。
336: // scale == true なら lda rD, rS1[rS2] 形式。
337: static void
338: gen_addsub_test(const char *mnemonic,
339: uint32 rd, uint32 rs1, uint32 rs2, uint32 vs1, uint32 vs2, int cin,
340: uint32 exp_rd, uint32 exp_cy, bool exception = false, bool is_scale = false)
341: {
342: // rs2 が IMM なら #imm
343: bool is_imm = (rs2 == IMM);
344: uint32& imm = vs2;
345:
346: out("test_%s_%d:\n", testname, testnum);
347: if (is_imm) {
348: out(" /* %s r%d, r%d, #0x%04x (S1=$%08x, Cin=%d) */\n",
349: mnemonic, rd, rs1, imm, vs1, cin);
350: } else if (is_scale) {
351: out(" /* %s r%d, r%d[r%d] (S1=$%08x, S2=$%08x) */\n",
352: mnemonic, rd, rs1, rs2, vs1, vs2);
353: } else {
354: out(" /* %s r%d, r%d, r%d (S1=$%08x, S2=$%08x, Cin=%d) */\n",
355: mnemonic, rd, rs1, rs2, vs1, vs2, cin);
356: }
357:
358: out(" .word 0x%08x | exp_rd\n", exp_rd);
359: out(" .word 0x%08x | Cin|ExpCy|Exception|0\n",
360: (cin << 24) | (exp_cy << 16) | (exception << 8));
361: // ここからテストコード
362: // ソースレジスタをセット、実行、結果を保存
363: MOV_imm(rs1, vs1);
364: if (!is_imm && rs1 != rs2) {
365: MOV_imm(rs2, vs2);
366: }
367: if (exception) {
368: // 例外期待なら、rD (と Cy)の期待値は命令実行前の値 (p.6-19, 6.6)
369: out(" or %%r10, %%r0, %%r%d\n", rd);
370: } else {
371: MOV_imm(10, exp_rd);
372: }
373:
374: if (exception) {
375: out(" | exception is expected\n");
376: }
377: if (is_imm) {
378: out(" %s %%r%d, %%r%d, 0x%04x | test\n", mnemonic, rd, rs1, imm);
379: } else if (is_scale) {
380: out(" %s %%r%d, %%r%d[%%r%d] | test\n", mnemonic, rd, rs1, rs2);
381: } else {
382: out(" %s %%r%d, %%r%d, %%r%d | test\n", mnemonic, rd, rs1, rs2);
383: }
384:
385: if (rd != 11) {
386: out(" or %%r11, %%r0, %%r%d\n", rd);
387: }
388: out(" jmp %%r1\n");
389: out("\n");
390:
391: testnum++;
392: }
393:
394: // div 命令共通のテストパターン出力部分
395: static void
396: gen_div_test(const char *mnemonic,
397: uint32 rd, uint32 rs1, uint32 rs2, uint32 vs1, uint32 vs2,
398: uint32 exp_rd, bool exception = false)
399: {
400: // rs2 が IMM なら #imm
401: bool is_imm = (rs2 == IMM);
402: uint32& imm = vs2;
403:
404: out("test_%s_%d:\n", testname, testnum);
405: if (is_imm) {
406: out(" /* %s r%d, r%d, #0x%04x (S1=$%08x) */\n",
407: mnemonic, rd, rs1, imm, vs1);
408: } else {
409: out(" /* %s r%d, r%d, r%d (S1=$%08x, S2=$%08x) */\n",
410: mnemonic, rd, rs1, rs2, vs1, vs2);
411: }
412:
413: out(" .word 0x%08x | exp_rd\n", exp_rd);
414: out(" .word 0x%08x | exp_ex\n", exception ? 2 : 0);
415: // ここからテストコード
416: // ソースレジスタをセット、実行、結果を保存
417: MOV_imm(rs1, vs1);
418: if (!is_imm && rs1 != rs2) {
419: MOV_imm(rs2, vs2);
420: }
421: if (exception) {
422: // 例外期待なら、rD の期待値は命令実行前の値 (p.6-40, 6.8.3)
423: out(" or %%r10, %%r0, %%r%d\n", rd);
424: } else {
425: MOV_imm(10, exp_rd);
426: }
427:
428: if (exception) {
429: out(" | exception is expected\n");
430: }
431: if (is_imm) {
432: out(" %s %%r%d, %%r%d, 0x%04x | test\n", mnemonic, rd, rs1, imm);
433: } else {
434: out(" %s %%r%d, %%r%d, %%r%d | test\n", mnemonic, rd, rs1, rs2);
435: }
436:
437: if (rd != 11) {
438: out(" or %%r11, %%r0, %%r%d\n", rd);
439: }
440: out(" jmp %%r1\n");
441: out("\n");
442:
443: testnum++;
444: }
445:
446: static void
447: gen_add()
448: {
449: for (const auto& t : test_arith_reg) {
450: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
451:
452: for (int cin = 0; cin <= 1; cin++) {
453: // 期待値
454: uint64 result = (uint64)vs1 + vs2;
455: uint32 exp_rd = (uint32)result;
456: uint32 exp_cy = cin;
457: if (rd == 0) {
458: exp_rd = 0;
459: }
460: bool exp_ex = isovf_add(vs1, vs2, result);
461: if (exp_ex) {
462: exp_cy = cin;
463: }
464:
465: gen_addsub_test("add",
466: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy, exp_ex);
467: }
468: }
469: }
470:
471: static void
472: gen_add_ci()
473: {
474: for (const auto& t : test_arith_reg) {
475: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
476:
477: for (int cin = 0; cin <= 1; cin++) {
478: // 期待値
479: uint64 result = (uint64)vs1 + vs2 + cin;
480: uint32 exp_rd = (uint32)result;
481: uint32 exp_cy = cin;
482: if (rd == 0) {
483: exp_rd = 0;
484: }
485: bool exp_ex = isovf_add(vs1, vs2, result);
486: if (exp_ex) {
487: exp_cy = cin;
488: }
489:
490: gen_addsub_test("add.ci",
491: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy, exp_ex);
492: }
493: }
494: }
495:
496: static void
497: gen_add_co()
498: {
499: for (const auto& t : test_arith_reg) {
500: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
501:
502: for (int cin = 0; cin <= 1; cin++) {
503: // 期待値
504: uint64 result = (uint64)vs1 + vs2;
505: uint32 exp_rd = (uint32)result;
506: uint32 exp_cy = result >> 32;
507: if (rd == 0) {
508: exp_rd = 0;
509: }
510: bool exp_ex = isovf_add(vs1, vs2, result);
511: if (exp_ex) {
512: exp_cy = cin;
513: }
514:
515: gen_addsub_test("add.co",
516: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy, exp_ex);
517: }
518: }
519: }
520:
521: static void
522: gen_add_cio()
523: {
524: for (const auto& t : test_arith_reg) {
525: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
526:
527: for (int cin = 0; cin <= 1; cin++) {
528: // 期待値
529: uint64 result = (uint64)vs1 + vs2 + cin;
530: uint32 exp_rd = (uint32)result;
531: uint32 exp_cy = result >> 32;
532: if (rd == 0) {
533: exp_rd = 0;
534: }
535: bool exp_ex = isovf_add(vs1, vs2, result);
536: if (exp_ex) {
537: exp_cy = cin;
538: }
539:
540: gen_addsub_test("add.cio",
541: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy, exp_ex);
542: }
543: }
544: }
545:
546: static void
547: gen_add_imm()
548: {
549: for (const auto& t : test_arith_imm) {
550: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
551:
552: for (int cin = 0; cin <= 1; cin++) {
553: // 期待値
554: uint64 result = (uint64)vs1 + imm;
555: uint32 exp_rd = (uint32)result;
556: uint32 exp_cy = cin;
557: if (rd == 0) {
558: exp_rd = 0;
559: }
560: bool exp_ex = isovf_add(vs1, imm, result);
561: if (exp_ex) {
562: exp_cy = cin;
563: }
564:
565: gen_addsub_test("add",
566: rd, rs1, IMM, vs1, imm, cin, exp_rd, exp_cy, exp_ex);
567: }
568: }
569: }
570:
571: // addu rD, rS1, rS2 と lda rD, rS1, rS2 は名前が違うだけで同じ…
572: static void
573: gen_addu_lda(const char *mnemonic)
574: {
575: for (const auto& t : test_arith_reg) {
576: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
577:
578: for (int cin = 0; cin <= 1; cin++) {
579: // 期待値
580: uint64 result = (uint64)vs1 + vs2;
581: uint32 exp_rd = (uint32)result;
582: uint32 exp_cy = cin;
583: if (rd == 0) {
584: exp_rd = 0;
585: }
586:
587: gen_addsub_test(mnemonic,
588: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy);
589: }
590: }
591: }
592:
593: static void
594: gen_addu()
595: {
596: gen_addu_lda("addu");
597: }
598:
599: static void
600: gen_addu_ci()
601: {
602: for (const auto& t : test_arith_reg) {
603: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
604:
605: for (int cin = 0; cin <= 1; cin++) {
606: // 期待値
607: uint64 result = (uint64)vs1 + vs2 + cin;
608: uint32 exp_rd = (uint32)result;
609: uint32 exp_cy = cin;
610: if (rd == 0) {
611: exp_rd = 0;
612: }
613:
614: gen_addsub_test("addu.ci",
615: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy);
616: }
617: }
618: }
619:
620: static void
621: gen_addu_co()
622: {
623: for (const auto& t : test_arith_reg) {
624: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
625:
626: for (int cin = 0; cin <= 1; cin++) {
627: // 期待値
628: uint64 result = (uint64)vs1 + vs2;
629: uint32 exp_rd = (uint32)result;
630: uint32 exp_cy = result >> 32;
631: if (rd == 0) {
632: exp_rd = 0;
633: }
634:
635: gen_addsub_test("addu.co",
636: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy);
637: }
638: }
639: }
640:
641: static void
642: gen_addu_cio()
643: {
644: for (const auto& t : test_arith_reg) {
645: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
646:
647: for (int cin = 0; cin <= 1; cin++) {
648: // 期待値
649: uint64 result = (uint64)vs1 + vs2 + cin;
650: uint32 exp_rd = (uint32)result;
651: uint32 exp_cy = result >> 32;
652: if (rd == 0) {
653: exp_rd = 0;
654: }
655:
656: gen_addsub_test("addu.cio",
657: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy);
658: }
659: }
660: }
661:
662: // addu rD, rS1, #imm と lda rD, rS1, #imm は名前が違うだけで同じ…
663: static void
664: gen_addu_lda_imm(const char *mnemonic)
665: {
666: for (const auto& t : test_arith_imm) {
667: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
668:
669: for (int cin = 0; cin <= 1; cin++) {
670: // 期待値
671: uint64 result = (uint64)vs1 + imm;
672: uint32 exp_rd = (uint32)result;
673: uint32 exp_cy = cin;
674: if (rd == 0) {
675: exp_rd = 0;
676: }
677:
678: gen_addsub_test(mnemonic,
679: rd, rs1, IMM, vs1, imm, cin, exp_rd, exp_cy);
680: }
681: }
682: }
683:
684: static void
685: gen_addu_imm()
686: {
687: gen_addu_lda_imm("addu");
688: }
689:
690: static void
691: gen_and()
692: {
693: for (const auto& t : test_arith_reg) {
694: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
695: uint32 exp_rd = vs1 & vs2;
696: if (rd == 0) {
697: exp_rd = 0;
698: }
699: gen_generic_test("and", rd, rs1, rs2, vs1, vs2, exp_rd);
700: }
701: }
702:
703: static void
704: gen_and_c()
705: {
706: for (const auto& t : test_arith_reg) {
707: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
708: uint32 exp_rd = vs1 & ~vs2;
709: if (rd == 0) {
710: exp_rd = 0;
711: }
712: gen_generic_test("and.c", rd, rs1, rs2, vs1, vs2, exp_rd);
713: }
714: }
715:
716: static void
717: gen_and_imm()
718: {
719: for (const auto& t : test_arith_imm) {
720: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
721: uint32 exp_rd = vs1 & (imm | 0xffff0000);
722: if (rd == 0) {
723: exp_rd = 0;
724: }
725: gen_generic_test("and", rd, rs1, IMM, vs1, imm, exp_rd);
726: }
727: }
728:
729: static void
730: gen_and_u()
731: {
732: for (const auto& t : test_arith_imm) {
733: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
734: uint32 exp_rd = vs1 & ((imm << 16) | 0xffff);
735: if (rd == 0) {
736: exp_rd = 0;
737: }
738: gen_generic_test("and.u", rd, rs1, IMM, vs1, imm, exp_rd);
739: }
740: }
741:
742: static uint32
743: calc_clr(uint32 src, uint32 wo)
744: {
745: uint32 w = ((wo >> 5) & 0x1f) ?: 32;
746: uint32 o = wo & 0x1f;
747: uint32 mask = (uint32)(((1ULL << w) - 1) << o);
748: return src & ~mask;
749: }
750:
751: static void
752: gen_clr_imm()
753: {
754: for (const auto& t : test_bitfield_imm) {
755: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
756: uint32 exp_rd = calc_clr(vs1, imm);
757: if (rd == 0) {
758: exp_rd = 0;
759: }
760: gen_bitfield_test("clr", rd, rs1, vs1, imm, exp_rd);
761: }
762: }
763:
764: static void
765: gen_clr_reg()
766: {
767: for (const auto& t : test_bitfield_reg) {
768: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
769: uint32 exp_rd = calc_clr(vs1, vs2);
770: if (rd == 0) {
771: exp_rd = 0;
772: }
773: gen_generic_test("clr", rd, rs1, rs2, vs1, vs2, exp_rd);
774: }
775: }
776:
777: static uint32
778: calc_cmp(uint32 vs1, uint32 vs2)
779: {
780: // 期待値
781: uint32 exp_rd = 0;
782:
783: exp_rd |= (vs1 >= vs2) ? 0x0800 : 0;
784: exp_rd |= (vs1 < vs2) ? 0x0400 : 0;
785: exp_rd |= (vs1 <= vs2) ? 0x0200 : 0;
786: exp_rd |= (vs1 > vs2) ? 0x0100 : 0;
787: exp_rd |= ((int32)vs1 >= (int32)vs2) ? 0x0080 : 0;
788: exp_rd |= ((int32)vs1 < (int32)vs2) ? 0x0040 : 0;
789: exp_rd |= ((int32)vs1 <= (int32)vs2) ? 0x0020 : 0;
790: exp_rd |= ((int32)vs1 > (int32)vs2) ? 0x0010 : 0;
791: exp_rd |= (vs1 != vs2) ? 0x0008 : 0;
792: exp_rd |= (vs1 == vs2) ? 0x0004 : 0;
793:
794: return exp_rd;
795: }
796:
797: static void
798: gen_cmp()
799: {
800: for (const auto& t : test_arith_reg) {
801: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
802: uint32 exp_rd = calc_cmp(vs1, vs2);
803: if (rd == 0) {
804: exp_rd = 0;
805: }
806: gen_generic_test("cmp", rd, rs1, rs2, vs1, vs2, exp_rd);
807: }
808: }
809:
810: static void
811: gen_cmp_imm()
812: {
813: for (const auto& t : test_arith_imm) {
814: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
815: uint32 exp_rd = calc_cmp(vs1, imm);
816: if (rd == 0) {
817: exp_rd = 0;
818: }
819: gen_generic_test("cmp", rd, rs1, IMM, vs1, imm, exp_rd);
820: }
821: }
822:
823: // 符号付きで x / y の期待値を計算する。
824: // 計算可能な場合は *exp_rd に結果を書き戻し *exp_ex に false を書き戻す。
825: // 例外を期待する場合は *exp_ex に true を書き戻す。
826: static void
827: calc_div(uint32 *exp_rd, bool *exp_ex, int32 x, int32 y)
828: {
829: // どちらかのオペランドが負でも例外らしい。符号付きとは一体…。
830: if (x < 0 || y <= 0) {
831: *exp_ex = true;
832: *exp_rd = 0; // なくていいはずだけどコンパイラに怒られるので
833: } else {
834: *exp_ex = false;
835: *exp_rd = (uint32)(x / y);
836: }
837: }
838:
839: static void
840: gen_div()
841: {
842: for (const auto& t : test_arith_reg) {
843: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
844: uint32 exp_rd;
845: bool exp_ex;
846: calc_div(&exp_rd, &exp_ex, vs1, vs2);
847: if (rd == 0) {
848: exp_rd = 0;
849: }
850: gen_div_test("div", rd, rs1, rs2, vs1, vs2, exp_rd, exp_ex);
851: }
852: }
853:
854: static void
855: gen_div_imm()
856: {
857: for (const auto& t : test_arith_imm) {
858: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
859: uint32 exp_rd;
860: bool exp_ex;
861: calc_div(&exp_rd, &exp_ex, vs1, imm);
862: if (rd == 0) {
863: exp_rd = 0;
864: }
865: gen_div_test("div", rd, rs1, IMM, vs1, imm, exp_rd, exp_ex);
866: }
867: }
868:
869: // 符号無しで x / y の期待値を計算する。
870: // 計算可能な場合は *exp_rd に結果を書き戻し *exp_ex に false を書き戻す。
871: // DivByZero を期待する場合は *exp_ex に true を書き戻す。
872: static void
873: calc_divu(uint32 *exp_rd, bool *exp_ex, uint32 x, uint32 y)
874: {
875: if (y == 0) {
876: *exp_ex = true;
877: *exp_rd = 0; // なくていいはずだけどコンパイラに怒られるので
878: } else {
879: *exp_ex = false;
880: *exp_rd = x / y;
881: }
882: }
883:
884: static void
885: gen_divu()
886: {
887: for (const auto& t : test_arith_reg) {
888: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
889: uint32 exp_rd;
890: bool exp_ex;
891: calc_divu(&exp_rd, &exp_ex, vs1, vs2);
892: if (rd == 0) {
893: exp_rd = 0;
894: }
895: gen_div_test("divu", rd, rs1, rs2, vs1, vs2, exp_rd, exp_ex);
896: }
897: }
898:
899: static void
900: gen_divu_imm()
901: {
902: for (const auto& t : test_arith_imm) {
903: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
904: uint32 exp_rd;
905: bool exp_ex;
906: calc_divu(&exp_rd, &exp_ex, vs1, imm);
907: if (rd == 0) {
908: exp_rd = 0;
909: }
910: gen_div_test("divu", rd, rs1, IMM, vs1, imm, exp_rd, exp_ex);
911: }
912: }
913:
914: static uint32
915: calc_ext(uint32 src, uint32 wo)
916: {
917: uint32 w = ((wo >> 5) & 0x1f) ?: 32;
918: uint32 o = wo & 0x1f;
919: uint32 mask = (uint32)(((1ULL << w) - 1) << o);
920:
921: src &= mask;
922:
923: int shift = 0;
924: if (o + w < 32) {
925: shift = 32 - (o + w);
926: src <<= shift;
927: }
928: src = (int32)src >> (o + shift);
929: return src;
930: }
931:
932: static void
933: gen_ext_imm()
934: {
935: for (const auto& t : test_bitfield_imm) {
936: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
937: uint32 exp_rd = calc_ext(vs1, imm);
938: if (rd == 0) {
939: exp_rd = 0;
940: }
941: gen_bitfield_test("ext", rd, rs1, vs1, imm, exp_rd);
942: }
943: }
944:
945: static void
946: gen_ext_reg()
947: {
948: for (const auto& t : test_bitfield_reg) {
949: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
950: uint32 exp_rd = calc_ext(vs1, vs2);
951: if (rd == 0) {
952: exp_rd = 0;
953: }
954: gen_generic_test("ext", rd, rs1, rs2, vs1, vs2, exp_rd);
955: }
956: }
957:
958: static uint32
959: calc_extu(uint32 src, uint32 wo)
960: {
961: uint32 w = ((wo >> 5) & 0x1f) ?: 32;
962: uint32 o = wo & 0x1f;
963: uint32 mask = (uint32)(((1ULL << w) - 1) << o);
964:
965: return (src & mask) >> o;
966: }
967:
968: static void
969: gen_extu_imm()
970: {
971: for (const auto& t : test_bitfield_imm) {
972: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
973: uint32 exp_rd = calc_extu(vs1, imm);
974: if (rd == 0) {
975: exp_rd = 0;
976: }
977: gen_bitfield_test("extu", rd, rs1, vs1, imm, exp_rd);
978: }
979: }
980:
981: static void
982: gen_extu_reg()
983: {
984: for (const auto& t : test_bitfield_reg) {
985: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
986: uint32 exp_rd = calc_extu(vs1, vs2);
987: if (rd == 0) {
988: exp_rd = 0;
989: }
990: gen_generic_test("extu", rd, rs1, rs2, vs1, vs2, exp_rd);
991: }
992: }
993:
994: static void
995: gen_ff0()
996: {
997: for (const auto& t : test_ff01) {
998: VAR_DIADIC(t, rd, rs2, vs2);
999: // 最も MSB 側にある %0 のビット位置(LSBを0とする)を返す
1000: // %0 がなければ 32 を返す
1001: uint32 exp_rd = 32;
1002: if (vs2 != 0xffffffff) {
1003: exp_rd = 31 - __builtin_clz(~vs2);
1004: }
1005: if (rd == 0) {
1006: exp_rd = 0;
1007: }
1008: gen_ff01_test("ff0", rd, rs2, vs2, exp_rd);
1009: }
1010: }
1011:
1012: static void
1013: gen_ff1()
1014: {
1015: for (const auto& t : test_ff01) {
1016: VAR_DIADIC(t, rd, rs2, vs2);
1017: // 最も MSB 側にある %1 のビット位置(LSBを0とする)を返す
1018: // %0 がなければ 32 を返す
1019: uint32 exp_rd = 32;
1020: if (vs2 != 0x00000000) {
1021: exp_rd = 31 - __builtin_clz(vs2);
1022: }
1023: if (rd == 0) {
1024: exp_rd = 0;
1025: }
1026: gen_ff01_test("ff1", rd, rs2, vs2, exp_rd);
1027: }
1028: }
1029:
1030: // lda.* rD, rS1, #imm は addu rD, rS1, #imm と同じ
1031: static void
1032: gen_lda_imm()
1033: {
1034: gen_addu_lda_imm("lda");
1035: }
1036: static void
1037: gen_lda_b_imm()
1038: {
1039: gen_addu_lda_imm("lda.b");
1040: }
1041: static void
1042: gen_lda_h_imm()
1043: {
1044: gen_addu_lda_imm("lda.h");
1045: }
1046: static void
1047: gen_lda_d_imm()
1048: {
1049: gen_addu_lda_imm("lda.d");
1050: }
1051:
1052: // lda.* rD, rS1, rS2 は addu rD, rS1, rS2 と同じ
1053: static void
1054: gen_lda_reg()
1055: {
1056: gen_addu_lda("lda");
1057: }
1058: static void
1059: gen_lda_b_reg()
1060: {
1061: gen_addu_lda("lda.b");
1062: }
1063: static void
1064: gen_lda_h_reg()
1065: {
1066: gen_addu_lda("lda.h");
1067: }
1068: static void
1069: gen_lda_d_reg()
1070: {
1071: gen_addu_lda("lda.d");
1072: }
1073:
1074: static void
1075: gen_lda_scale(const char *mnemonic, uint32 scale)
1076: {
1077: for (const auto& t : test_arith_reg) {
1078: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1079:
1080: for (int cin = 0; cin <= 1; cin++) {
1081: // 期待値
1082: uint64 result = (uint64)vs1 + vs2 * scale;
1083: uint32 exp_rd = (uint32)result;
1084: uint32 exp_cy = cin;
1085: if (rd == 0) {
1086: exp_rd = 0;
1087: }
1088:
1089: bool exception = false;
1090: bool is_scale = true;
1091: gen_addsub_test(mnemonic,
1092: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy,
1093: exception, is_scale);
1094: }
1095: }
1096: }
1097: static void
1098: gen_lda_scale()
1099: {
1100: gen_lda_scale("lda", 4);
1101: }
1102: static void
1103: gen_lda_b_scale()
1104: {
1105: gen_addu_lda("lda.b");
1106: }
1107: static void
1108: gen_lda_h_scale()
1109: {
1110: gen_lda_scale("lda.h", 2);
1111: }
1112: static void
1113: gen_lda_d_scale()
1114: {
1115: gen_lda_scale("lda.d", 8);
1116: }
1117:
1118: static uint32
1119: calc_mak(uint32 src, uint32 wo)
1120: {
1121: uint32 w = ((wo >> 5) & 0x1f) ?: 32;
1122: uint32 o = wo & 0x1f;
1123: uint32 mask = (uint32)((1ULL << w) - 1);
1124:
1125: return (src & mask) << o;
1126: }
1127:
1128: static void
1129: gen_mak_imm()
1130: {
1131: for (const auto& t : test_bitfield_imm) {
1132: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1133: uint32 exp_rd = calc_mak(vs1, imm);
1134: if (rd == 0) {
1135: exp_rd = 0;
1136: }
1137: gen_bitfield_test("mak", rd, rs1, vs1, imm, exp_rd);
1138: }
1139: }
1140:
1141: static void
1142: gen_mak_reg()
1143: {
1144: for (const auto& t : test_bitfield_reg) {
1145: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1146: uint32 exp_rd = calc_mak(vs1, vs2);
1147: if (rd == 0) {
1148: exp_rd = 0;
1149: }
1150: gen_generic_test("mak", rd, rs1, rs2, vs1, vs2, exp_rd);
1151: }
1152: }
1153:
1154: static void
1155: gen_mask_imm()
1156: {
1157: for (const auto& t : test_arith_imm) {
1158: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1159: uint32 exp_rd = vs1 & imm;
1160: if (rd == 0) {
1161: exp_rd = 0;
1162: }
1163: gen_generic_test("mask", rd, rs1, IMM, vs1, imm, exp_rd);
1164: }
1165: }
1166:
1167: static void
1168: gen_mask_u()
1169: {
1170: for (const auto& t : test_arith_imm) {
1171: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1172: uint32 exp_rd = vs1 & (imm << 16);
1173: if (rd == 0) {
1174: exp_rd = 0;
1175: }
1176: gen_generic_test("mask.u", rd, rs1, IMM, vs1, imm, exp_rd);
1177: }
1178: }
1179:
1180: static void
1181: gen_mul()
1182: {
1183: for (const auto& t : test_arith_reg) {
1184: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1185: uint32 exp_rd = (uint32)((uint64)vs1 * vs2);
1186: if (rd == 0) {
1187: exp_rd = 0;
1188: }
1189: gen_generic_test("mul", rd, rs1, rs2, vs1, vs2, exp_rd);
1190: }
1191: }
1192:
1193: static void
1194: gen_mul_imm()
1195: {
1196: for (const auto& t : test_arith_imm) {
1197: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1198: uint32 exp_rd = (uint32)((uint64)vs1 * imm);
1199: if (rd == 0) {
1200: exp_rd = 0;
1201: }
1202: gen_generic_test("mul", rd, rs1, IMM, vs1, imm, exp_rd);
1203: }
1204: }
1205:
1206: static void
1207: gen_or()
1208: {
1209: for (const auto& t : test_arith_reg) {
1210: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1211: uint32 exp_rd = vs1 | vs2;
1212: if (rd == 0) {
1213: exp_rd = 0;
1214: }
1215: gen_generic_test("or", rd, rs1, rs2, vs1, vs2, exp_rd);
1216: }
1217: }
1218:
1219: static void
1220: gen_or_c()
1221: {
1222: for (const auto& t : test_arith_reg) {
1223: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1224: uint32 exp_rd = vs1 | ~vs2;
1225: if (rd == 0) {
1226: exp_rd = 0;
1227: }
1228: gen_generic_test("or.c", rd, rs1, rs2, vs1, vs2, exp_rd);
1229: }
1230: }
1231:
1232: static void
1233: gen_or_imm()
1234: {
1235: for (const auto& t : test_arith_imm) {
1236: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1237: uint32 exp_rd = vs1 | imm;
1238: if (rd == 0) {
1239: exp_rd = 0;
1240: }
1241: gen_generic_test("or", rd, rs1, IMM, vs1, imm, exp_rd);
1242: }
1243: }
1244:
1245: static void
1246: gen_or_u()
1247: {
1248: for (const auto& t : test_arith_imm) {
1249: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1250: uint32 exp_rd = vs1 | (imm << 16);
1251: if (rd == 0) {
1252: exp_rd = 0;
1253: }
1254: gen_generic_test("or.u", rd, rs1, IMM, vs1, imm, exp_rd);
1255: }
1256: }
1257:
1258: static uint32
1259: calc_rot(uint32 src, uint32 wo)
1260: {
1261: uint32 o = wo & 0x1f;
1262: return (src >> o) | (src << (32 - o));
1263: }
1264:
1265: static void
1266: gen_rot_imm()
1267: {
1268: // 手抜きで W は無視するのでパターンが重複する
1269: for (const auto& t : test_bitfield_imm) {
1270: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1271: uint32 exp_rd = calc_rot(vs1, imm);
1272: if (rd == 0) {
1273: exp_rd = 0;
1274: }
1275: gen_bitfield_test("rot", rd, rs1, vs1, imm, exp_rd);
1276: }
1277: }
1278:
1279: static void
1280: gen_rot_reg()
1281: {
1282: // 手抜きで W は無視するのでパターンが重複する
1283: for (const auto& t : test_bitfield_reg) {
1284: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1285: uint32 exp_rd = calc_rot(vs1, vs2);
1286: if (rd == 0) {
1287: exp_rd = 0;
1288: }
1289: gen_generic_test("rot", rd, rs1, rs2, vs1, vs2, exp_rd);
1290: }
1291: }
1292:
1293: static uint32
1294: calc_set(uint32 src, uint32 wo)
1295: {
1296: uint32 w = ((wo >> 5) & 0x1f) ?: 32;
1297: uint32 o = wo & 0x1f;
1298: uint32 mask = (uint32)(((1ULL << w) - 1) << o);
1299: return src | mask;
1300: }
1301:
1302: static void
1303: gen_set_imm()
1304: {
1305: for (const auto& t : test_bitfield_imm) {
1306: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1307: uint32 exp_rd = calc_set(vs1, imm);
1308: if (rd == 0) {
1309: exp_rd = 0;
1310: }
1311: gen_bitfield_test("set", rd, rs1, vs1, imm, exp_rd);
1312: }
1313: }
1314:
1315: static void
1316: gen_set_reg()
1317: {
1318: for (const auto& t : test_bitfield_reg) {
1319: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1320: uint32 exp_rd = calc_set(vs1, vs2);
1321: if (rd == 0) {
1322: exp_rd = 0;
1323: }
1324: gen_generic_test("set", rd, rs1, rs2, vs1, vs2, exp_rd);
1325: }
1326: }
1327:
1328: static void
1329: gen_sub()
1330: {
1331: for (const auto& t : test_arith_reg) {
1332: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1333:
1334: for (int cin = 0; cin <= 1; cin++) {
1335: // 期待値
1336: uint64 result = (uint64)vs1 + (~vs2) + 1;
1337: uint32 exp_rd = (uint32)result;
1338: uint32 exp_cy = cin;
1339: if (rd == 0) {
1340: exp_rd = 0;
1341: }
1342: bool exp_ex = isovf_sub(vs1, vs2, result);
1343: if (exp_ex) {
1344: exp_cy = cin;
1345: }
1346:
1347: gen_addsub_test("sub",
1348: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy, exp_ex);
1349: }
1350: }
1351: }
1352:
1353: static void
1354: gen_sub_ci()
1355: {
1356: for (const auto& t : test_arith_reg) {
1357: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1358:
1359: for (int cin = 0; cin <= 1; cin++) {
1360: // 期待値
1361: uint64 result = (uint64)vs1 + (~vs2) + cin;
1362: uint32 exp_rd = (uint32)result;
1363: uint32 exp_cy = cin;
1364: if (rd == 0) {
1365: exp_rd = 0;
1366: }
1367: bool exp_ex = isovf_sub(vs1, vs2, result);
1368: if (exp_ex) {
1369: exp_cy = cin;
1370: }
1371:
1372: gen_addsub_test("sub.ci",
1373: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy, exp_ex);
1374: }
1375: }
1376: }
1377:
1378: static void
1379: gen_sub_co()
1380: {
1381: for (const auto& t : test_arith_reg) {
1382: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1383:
1384: for (int cin = 0; cin <= 1; cin++) {
1385: // 期待値
1386: uint64 result = (uint64)vs1 + (~vs2) + 1;
1387: uint32 exp_rd = (uint32)result;
1388: uint32 exp_cy = result >> 32;
1389: if (rd == 0) {
1390: exp_rd = 0;
1391: }
1392: bool exp_ex = isovf_sub(vs1, vs2, result);
1393: if (exp_ex) {
1394: exp_cy = cin;
1395: }
1396:
1397: gen_addsub_test("sub.co",
1398: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy, exp_ex);
1399: }
1400: }
1401: }
1402:
1403: static void
1404: gen_sub_cio()
1405: {
1406: for (const auto& t : test_arith_reg) {
1407: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1408:
1409: for (int cin = 0; cin <= 1; cin++) {
1410: // 期待値
1411: uint64 result = (uint64)vs1 + (~vs2) + cin;
1412: uint32 exp_rd = (uint32)result;
1413: uint32 exp_cy = result >> 32;
1414: if (rd == 0) {
1415: exp_rd = 0;
1416: }
1417: bool exp_ex = isovf_sub(vs1, vs2, result);
1418: if (exp_ex) {
1419: exp_cy = cin;
1420: }
1421:
1422: gen_addsub_test("sub.cio",
1423: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy, exp_ex);
1424: }
1425: }
1426: }
1427:
1428: static void
1429: gen_sub_imm()
1430: {
1431: for (const auto& t : test_arith_imm) {
1432: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1433:
1434: for (int cin = 0; cin <= 1; cin++) {
1435: // 期待値
1436: uint64 result = (uint64)vs1 + (~imm) + 1;
1437: uint32 exp_rd = (uint32)result;
1438: uint32 exp_cy = cin;
1439: if (rd == 0) {
1440: exp_rd = 0;
1441: }
1442: bool exp_ex = isovf_sub(vs1, imm, result);
1443: if (exp_ex) {
1444: exp_cy = cin;
1445: }
1446:
1447: gen_addsub_test("sub",
1448: rd, rs1, IMM, vs1, imm, cin, exp_rd, exp_cy, exp_ex);
1449: }
1450: }
1451: }
1452:
1453: static void
1454: gen_subu()
1455: {
1456: for (const auto& t : test_arith_reg) {
1457: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1458:
1459: for (int cin = 0; cin <= 1; cin++) {
1460: // 期待値
1461: uint64 result = (uint64)vs1 + (~vs2) + 1;
1462: uint32 exp_rd = (uint32)result;
1463: uint32 exp_cy = cin;
1464: if (rd == 0) {
1465: exp_rd = 0;
1466: }
1467:
1468: gen_addsub_test("subu",
1469: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy);
1470: }
1471: }
1472: }
1473:
1474: static void
1475: gen_subu_ci()
1476: {
1477: for (const auto& t : test_arith_reg) {
1478: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1479:
1480: for (int cin = 0; cin <= 1; cin++) {
1481: // 期待値
1482: uint64 result = (uint64)vs1 + (~vs2) + cin;
1483: uint32 exp_rd = (uint32)result;
1484: uint32 exp_cy = cin;
1485: if (rd == 0) {
1486: exp_rd = 0;
1487: }
1488:
1489: gen_addsub_test("subu.ci",
1490: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy);
1491: }
1492: }
1493: }
1494:
1495: static void
1496: gen_subu_co()
1497: {
1498: for (const auto& t : test_arith_reg) {
1499: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1500:
1501: for (int cin = 0; cin <= 1; cin++) {
1502: // 期待値
1503: uint64 result = (uint64)vs1 + (~vs2) + 1;
1504: uint32 exp_rd = (uint32)result;
1505: uint32 exp_cy = result >> 32;
1506: if (rd == 0) {
1507: exp_rd = 0;
1508: }
1509:
1510: gen_addsub_test("subu.co",
1511: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy);
1512: }
1513: }
1514: }
1515:
1516: static void
1517: gen_subu_cio()
1518: {
1519: for (const auto& t : test_arith_reg) {
1520: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1521:
1522: for (int cin = 0; cin <= 1; cin++) {
1523: // 期待値
1524: uint64 result = (uint64)vs1 + (~vs2) + cin;
1525: uint32 exp_rd = (uint32)result;
1526: uint32 exp_cy = result >> 32;
1527: if (rd == 0) {
1528: exp_rd = 0;
1529: }
1530:
1531: gen_addsub_test("subu.cio",
1532: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy);
1533: }
1534: }
1535: }
1536:
1537: static void
1538: gen_subu_imm()
1539: {
1540: for (const auto& t : test_arith_imm) {
1541: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1542:
1543: for (int cin = 0; cin <= 1; cin++) {
1544: // 期待値
1545: uint64 result = (uint64)vs1 + (~imm) + 1;
1546: uint32 exp_rd = (uint32)result;
1547: uint32 exp_cy = cin;
1548: if (rd == 0) {
1549: exp_rd = 0;
1550: }
1551:
1552: gen_addsub_test("subu",
1553: rd, rs1, IMM, vs1, imm, cin, exp_rd, exp_cy);
1554: }
1555: }
1556: }
1557:
1558: static void
1559: gen_xor()
1560: {
1561: for (const auto& t : test_arith_reg) {
1562: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1563: uint32 exp_rd = vs1 ^ vs2;
1564: if (rd == 0) {
1565: exp_rd = 0;
1566: }
1567: gen_generic_test("xor", rd, rs1, rs2, vs1, vs2, exp_rd);
1568: }
1569: }
1570:
1571: static void
1572: gen_xor_c()
1573: {
1574: for (const auto& t : test_arith_reg) {
1575: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1576: uint32 exp_rd = vs1 ^ ~vs2;
1577: if (rd == 0) {
1578: exp_rd = 0;
1579: }
1580: gen_generic_test("xor.c", rd, rs1, rs2, vs1, vs2, exp_rd);
1581: }
1582: }
1583:
1584: static void
1585: gen_xor_imm()
1586: {
1587: for (const auto& t : test_arith_imm) {
1588: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1589: uint32 exp_rd = vs1 ^ imm;
1590: if (rd == 0) {
1591: exp_rd = 0;
1592: }
1593: gen_generic_test("xor", rd, rs1, IMM, vs1, imm, exp_rd);
1594: }
1595: }
1596:
1597: static void
1598: gen_xor_u()
1599: {
1600: for (const auto& t : test_arith_imm) {
1601: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1602: uint32 exp_rd = vs1 ^ (imm << 16);
1603: if (rd == 0) {
1604: exp_rd = 0;
1605: }
1606: gen_generic_test("xor.u", rd, rs1, IMM, vs1, imm, exp_rd);
1607: }
1608: }
1609:
1610:
1611:
1612: //
1613: // ここから出力用の処理
1614: //
1615:
1616: enum {
1617: G_ADD = 1,
1618: G_SUB,
1619: G_LOGICAL,
1620: G_BITFIELD,
1621: G_LDA,
1622: G_MULDIV,
1623: };
1624:
1625: // テスト一覧 (編集しやすいように実体は一番下に置いてある)
1626: struct testentry {
1627: int group;
1628: const char *code;
1629: void (*genfunc)();
1630: const char *name;
1631: };
1632: extern std::vector<testentry> test_table;
1633:
1634: // list の中に val がなければ追加する
1635: template <class T>
1636: static void append(std::vector<T>& list, const T& val)
1637: {
1638: if (std::find(list.begin(), list.end(), val) == list.end()) {
1639: list.emplace_back(val);
1640: }
1641: }
1642:
1643: // ファイルオープンとクローズ (副作用のあるマクロ)
1644: #define FOPEN(filename_) do { \
1645: filename = filename_; \
1646: tmpname = filename + ".tmp"; \
1647: fp = fopen(tmpname.c_str(), "w"); \
1648: if (fp == NULL) { \
1649: err(1, "%s", tmpname.c_str()); \
1650: } \
1651: out("/* This file was created by %s */\n", getprogname()); \
1652: out("\n"); \
1653: } while (0)
1654: #define FCLOSE() do { \
1655: fclose(fp); \
1656: compare_and_move(tmpname, filename); \
1657: } while (0)
1658:
1659: // テストアセンブリソースの出力共通部分
1660: static void
1661: print_test(const testentry& t)
1662: {
1663: // グローバル変数にセット
1664: testname = t.name;
1665: testnum = 0;
1666:
1667: // テストの実体を出力
1668: t.genfunc();
1669:
1670: // テーブル
1671: out(".globl list_%s\n", testname);
1672: out("list_%s:\n", testname);
1673: for (int i = 0; i < testnum; i++) {
1674: out("\t.word test_%s_%d\n", testname, i);
1675: }
1676: out("\t.word 0\n");
1677: out("\n");
1678: }
1679:
1680: static void compare_and_move(const std::string&, const std::string&);
1681:
1682: int
1683: main(int ac, char *av[])
1684: {
1685: std::string filename;
1686: std::string tmpname;
1687:
1688: // テストパターンを用意
1689: for (const auto& rlist : reglist3) {
1690: auto rd = (rlist >> 16) & 0xff;
1691: auto rs1 = (rlist >> 8) & 0xff;
1692: auto rs2 = rlist & 0xff;
1693:
1694: std::vector<uint32> *v_arith_s1 = (rs1 == 0) ? &v0 : &vlist_arith;
1695: std::vector<uint32> *v_arith_s2 = (rs2 == 0) ? &v0 : &vlist_arith;
1696:
1697: if (rs1 == rs2) {
1698: for (const auto& vs1 : *v_arith_s1) {
1699: Tuple5<uint32> val(rd, rs1, rs2, vs1, vs1);
1700: append(test_arith_reg, val);
1701: }
1702: } else {
1703: for (const auto& vs1 : *v_arith_s1) {
1704: for (const auto& vs2 : *v_arith_s2) {
1705: Tuple5<uint32> val(rd, rs1, rs2, vs1, vs2);
1706: append(test_arith_reg, val);
1707: }
1708: }
1709: }
1710: }
1711: for (const auto& rlist : reglist2) {
1712: auto rd = (rlist >> 16) & 0xff;
1713: auto rs1 = (rlist >> 8) & 0xff;
1714:
1715: std::vector<uint32> *v_arith_s1 = (rs1 == 0) ? &v0 : &vlist_arith;
1716:
1717: for (const auto& vs1 : *v_arith_s1) {
1718: for (const auto& imm : vlist_arith) {
1719: if (imm <= 0xffff) {
1720: Tuple4<uint32> val(rd, rs1, vs1, imm);
1721: append(test_arith_imm, val);
1722: }
1723: }
1724: }
1725: }
1726: for (const auto& rlist : reglist3) {
1727: auto rd = (rlist >> 16) & 0xff;
1728: auto rs1 = (rlist >> 8) & 0xff;
1729: auto rs2 = rlist & 0xff;
1730:
1731: std::vector<uint32> *v_bf = (rs1 == 0) ? &v0 : &vlist_bf;
1732: std::vector<uint32> *v_wo = (rs2 == 0) ? &v0 : &vlist_wo;
1733:
1734: if (rs1 == rs2) {
1735: for (const auto& vs1 : *v_bf) {
1736: Tuple5<uint32> val(rd, rs1, rs2, vs1, vs1);
1737: append(test_bitfield_reg, val);
1738: }
1739: for (const auto& vs2 : *v_wo) {
1740: Tuple5<uint32> val(rd, rs1, rs2, vs2, vs2);
1741: append(test_bitfield_reg, val);
1742: }
1743: } else {
1744: for (const auto& vs1 : *v_bf) {
1745: for (const auto& vs2 : *v_wo) {
1746: Tuple5<uint32> val(rd, rs1, rs2, vs1, vs2);
1747: append(test_bitfield_reg, val);
1748: }
1749: }
1750: }
1751: }
1752: for (const auto& rlist : reglist2) {
1753: auto rd = (rlist >> 16) & 0xff;
1754: auto rs1 = (rlist >> 8) & 0xff;
1755:
1756: std::vector<uint32> *v_bf = (rs1 == 0) ? &v0 : &vlist_bf;
1757:
1758: for (const auto& vs1 : *v_bf) {
1759: for (const auto& wo : vlist_wo) {
1760: Tuple4<uint32> val(rd, rs1, vs1, wo);
1761: append(test_bitfield_imm, val);
1762: }
1763: }
1764: }
1765: for (const auto& rlist : reglist2) {
1766: auto rd = (rlist >> 16) & 0xff;
1767: auto rs2 = (rlist >> 8) & 0xff;
1768:
1769: std::vector<uint32> v_ff;
1770: if (rs2 == 0) {
1771: v_ff = v0;
1772: } else {
1773: // vlist_arith とそれをビット反転したもの
1774: for (const auto v : vlist_arith) {
1775: v_ff.emplace_back(v);
1776: v_ff.emplace_back(~v);
1777: }
1778: }
1779:
1780: for (const auto& vs2 : v_ff) {
1781: Tuple3<uint32> val(rd, rs2, vs2);
1782: append(test_ff01, val);
1783: }
1784: }
1785:
1786: //
1787: // add.s を出力
1788: //
1789: FOPEN("optestm88k_add.s");
1790: for (const auto& t : test_table) {
1791: if (t.group == G_ADD) {
1792: print_test(t);
1793: }
1794: }
1795: FCLOSE();
1796:
1797: //
1798: // sub.s を出力
1799: //
1800: FOPEN("optestm88k_sub.s");
1801: for (const auto& t : test_table) {
1802: if (t.group == G_SUB) {
1803: print_test(t);
1804: }
1805: }
1806: FCLOSE();
1807:
1808: //
1809: // logical.s を出力
1810: //
1811: FOPEN("optestm88k_logical.s");
1812: for (const auto& t : test_table) {
1813: if (t.group == G_LOGICAL) {
1814: print_test(t);
1815: }
1816: }
1817: FCLOSE();
1818:
1819: //
1820: // bitfield.s を出力
1821: //
1822: FOPEN("optestm88k_bitfield.s");
1823: for (const auto& t : test_table) {
1824: if (t.group == G_BITFIELD) {
1825: print_test(t);
1826: }
1827: }
1828: FCLOSE();
1829:
1830: //
1831: // lda.s を出力
1832: //
1833: FOPEN("optestm88k_lda.s");
1834: for (const auto& t : test_table) {
1835: if (t.group == G_LDA) {
1836: print_test(t);
1837: }
1838: }
1839: FCLOSE();
1840:
1841: //
1842: // muldiv.s を出力
1843: //
1844: FOPEN("optestm88k_muldiv.s");
1845: for (const auto& t : test_table) {
1846: if (t.group == G_MULDIV) {
1847: print_test(t);
1848: }
1849: }
1850: FCLOSE();
1851:
1852: //
1853: // table.h を出力
1854: //
1855: FOPEN("optestm88k_table.h");
1856: out("#ifndef optestm88k_table_h\n");
1857: out("#define optestm88k_table_h\n");
1858: out("\n");
1859: // testcode は table_*.name を uniq したもの
1860: std::vector<std::string> test_code_list;
1861: for (const auto& t : test_table) {
1862: append(test_code_list, std::string(t.code));
1863: }
1864: for (const auto& name : test_code_list) {
1865: out("extern int test_%s(int *, int *);\n", name.c_str());
1866: }
1867: out("\n");
1868:
1869: for (const auto& t : test_table) {
1870: out("extern int *list_%s[];\n", t.name);
1871: }
1872: out("\n");
1873: out("#endif /* !optestm88k_table_h */\n");
1874: FCLOSE();
1875:
1876: //
1877: // table.c を出力
1878: //
1879: FOPEN("optestm88k_table.c");
1880: out("#include \"optestm88k_main.h\"\n");
1881: out("#include \"optestm88k_table.h\"\n");
1882: out("\n");
1883: out("struct testentry test_table[] = {\n");
1884: for (const auto& t : test_table) {
1885: out(" { test_%s,\tlist_%s,\t\"%s\" },\n", t.code, t.name, t.name);
1886: }
1887: out(" { NULL, NULL, NULL },\n");
1888: out("};\n");
1889: FCLOSE();
1890:
1891: return 0;
1892: }
1893:
1894: // src, dst のファイルが異なっていれば src を dst に rename する
1895: static void
1896: compare_and_move(const std::string& src, const std::string& dst)
1897: {
1898: struct stat st;
1899: int r;
1900: bool update;
1901:
1902: update = false;
1903: r = stat(dst.c_str(), &st);
1904: if (r < 0) {
1905: // dst not found
1906: update = true;
1907: } else {
1908: // dst exists
1909:
1910: std::string cmd = "cmp -s " + src + " " + dst;
1911: r = system(cmd.c_str());
1912: if (r < 0) {
1913: err(1, "system");
1914: }
1915: r = WEXITSTATUS(r);
1916: if (r > 1) {
1917: errx(1, "cmp failed?");
1918: }
1919:
1920: if (r == 0) {
1921: // src and dst are the same
1922: } else {
1923: update = true;
1924: }
1925: }
1926:
1927: if (update) {
1928: // 違っていれば、src を dst に移動
1929: r = rename(src.c_str(), dst.c_str());
1930: if (r < 0) {
1931: err(1, "rename: %s %s", src.c_str(), dst.c_str());
1932: }
1933: printf("Updated: %s\n", dst.c_str());
1934: } else {
1935: // 同じなら、今作った src のほうを消す
1936: r = remove(src.c_str());
1937: if (r < 0) {
1938: err(1, "remove: %s", src.c_str());
1939: }
1940: }
1941: }
1942:
1943: //
1944: // テスト一覧
1945: //
1946: #define T(group, code, name) { group, code, gen_##name, #name }
1947: std::vector<testentry> test_table = {
1948: T(G_ADD, "addsub", add),
1949: T(G_ADD, "addsub", add_ci),
1950: T(G_ADD, "addsub", add_co),
1951: T(G_ADD, "addsub", add_cio),
1952: T(G_ADD, "addsub", add_imm),
1953: T(G_ADD, "addsub", addu),
1954: T(G_ADD, "addsub", addu_ci),
1955: T(G_ADD, "addsub", addu_co),
1956: T(G_ADD, "addsub", addu_cio),
1957: T(G_ADD, "addsub", addu_imm),
1958:
1959: T(G_SUB, "addsub", sub),
1960: T(G_SUB, "addsub", sub_ci),
1961: T(G_SUB, "addsub", sub_co),
1962: T(G_SUB, "addsub", sub_cio),
1963: T(G_SUB, "addsub", sub_imm),
1964: T(G_SUB, "addsub", subu),
1965: T(G_SUB, "addsub", subu_ci),
1966: T(G_SUB, "addsub", subu_co),
1967: T(G_SUB, "addsub", subu_cio),
1968: T(G_SUB, "addsub", subu_imm),
1969: T(G_SUB, "generic", cmp),
1970: T(G_SUB, "generic", cmp_imm),
1971:
1972: T(G_LOGICAL, "generic", and),
1973: T(G_LOGICAL, "generic", and_c),
1974: T(G_LOGICAL, "generic", and_imm),
1975: T(G_LOGICAL, "generic", and_u),
1976: T(G_LOGICAL, "generic", mask_imm),
1977: T(G_LOGICAL, "generic", mask_u),
1978: T(G_LOGICAL, "generic", or),
1979: T(G_LOGICAL, "generic", or_c),
1980: T(G_LOGICAL, "generic", or_imm),
1981: T(G_LOGICAL, "generic", or_u),
1982: T(G_LOGICAL, "generic", xor),
1983: T(G_LOGICAL, "generic", xor_c),
1984: T(G_LOGICAL, "generic", xor_imm),
1985: T(G_LOGICAL, "generic", xor_u),
1986:
1987: T(G_BITFIELD, "generic", clr_imm),
1988: T(G_BITFIELD, "generic", clr_reg),
1989: T(G_BITFIELD, "generic", ext_imm),
1990: T(G_BITFIELD, "generic", ext_reg),
1991: T(G_BITFIELD, "generic", extu_imm),
1992: T(G_BITFIELD, "generic", extu_reg),
1993: T(G_BITFIELD, "generic", ff0),
1994: T(G_BITFIELD, "generic", ff1),
1995: T(G_BITFIELD, "generic", mak_imm),
1996: T(G_BITFIELD, "generic", mak_reg),
1997: T(G_BITFIELD, "generic", rot_imm),
1998: T(G_BITFIELD, "generic", rot_reg),
1999: T(G_BITFIELD, "generic", set_imm),
2000: T(G_BITFIELD, "generic", set_reg),
2001:
2002: T(G_LDA, "addsub", lda_imm),
2003: T(G_LDA, "addsub", lda_b_imm),
2004: T(G_LDA, "addsub", lda_h_imm),
2005: T(G_LDA, "addsub", lda_d_imm),
2006: T(G_LDA, "addsub", lda_reg),
2007: T(G_LDA, "addsub", lda_b_reg),
2008: T(G_LDA, "addsub", lda_h_reg),
2009: T(G_LDA, "addsub", lda_d_reg),
2010: T(G_LDA, "addsub", lda_scale),
2011: T(G_LDA, "addsub", lda_b_scale),
2012: T(G_LDA, "addsub", lda_h_scale),
2013: T(G_LDA, "addsub", lda_d_scale),
2014:
2015: T(G_MULDIV, "generic", mul),
2016: T(G_MULDIV, "generic", mul_imm),
2017: T(G_MULDIV, "div", div),
2018: T(G_MULDIV, "div", div_imm),
2019: T(G_MULDIV, "div", divu),
2020: T(G_MULDIV, "div", divu_imm),
2021: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.