|
|
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 ---+
1.1.1.3 ! root 19: // +--> optestm88k_fcmp.s ---+
! 20: // +--> optestm88k_flt.s ---+
1.1 root 21: // +--> optestm88k_lda.s ---+
22: // +--> optestm88k_logical.s ---+
23: // +--> optestm88k_muldiv.s ---+
24: // +--> optestm88k_sub.s ---+
25: // +--> optestm88k_table.c ---+
26: // +--> optestm88k_table.h ---+
27: // |
28: // optestm88k_main.[ch] ---+
29: // optestm88k_code.s ---+
30: // | compile and link on m88k
31: // v
32: // optestm88k
33:
34: // XXX mul/div/divu 命令の FPU disabled のケースは未検査
35:
36: #include "header.h"
1.1.1.3 ! root 37: #include "mystring.h"
1.1.1.2 root 38: #include <assert.h>
1.1 root 39: #include <sys/stat.h>
40: #include <sys/wait.h>
41: #include <algorithm>
1.1.1.3 ! root 42: #include <cfenv>
! 43: #include <cmath>
1.1 root 44: #include <map>
45: #include <tuple>
46: #include <vector>
47:
1.1.1.2 root 48: struct fpi
49: {
50: union {
51: double d {};
52: uint64 q;
53: // float は h の位置に置く
54: #if _BYTE_ORDER == _LITTLE_ENDIAN
55: struct { uint32 l, h; };
56: struct { float dummy_f, f; };
57: struct { uint32 dummy_i, i; };
58: #else
59: struct { uint32 h, l; };
60: struct { float f, dummy_f; };
61: struct { uint32 i, dummy_i; };
62: #endif
63: };
64:
65: enum {
66: NONE,
67: FLOAT,
68: DOUBLE,
1.1.1.3 ! root 69: INT,
1.1.1.2 root 70: } type {};
71: bool IsFloat() const { return (type == FLOAT); }
72: bool IsDouble() const { return (type == DOUBLE); }
1.1.1.3 ! root 73: bool IsInt() const { return (type == INT); }
1.1.1.2 root 74:
1.1.1.3 ! root 75: // コンストラクタ
! 76: fpi() {
! 77: }
! 78: fpi(float f_) {
! 79: Set(f_);
! 80: }
! 81: fpi(double d_) {
! 82: Set(d_);
! 83: }
! 84: fpi(uint32 i_) {
! 85: SetInt(i_);
! 86: }
! 87:
! 88: // どの値を保持しているか覚えておく
1.1.1.2 root 89: void Set(float f_) {
90: f = f_;
91: type = FLOAT;
92: }
93: void Set(double d_) {
94: d = d_;
95: type = DOUBLE;
96: }
97: void Set(uint32 i_) {
98: i = i_;
99: type = FLOAT;
100: }
101: void Set(uint64 q_) {
102: q = q_;
103: type = DOUBLE;
104: }
1.1.1.3 ! root 105: void SetInt(uint32 i_) {
! 106: i = i_;
! 107: type = INT;
1.1.1.2 root 108: }
1.1.1.3 ! root 109:
! 110: // どっちであっても double 値を返す (printf 用)
! 111: double AsDouble() const {
! 112: if (IsFloat()) {
! 113: return (double)f;
! 114: } else {
! 115: return d;
! 116: }
1.1.1.2 root 117: }
1.1.1.3 ! root 118:
! 119: std::string ToString() const {
! 120: switch (type) {
! 121: case FLOAT:
! 122: return string_format("%9.8g", f);
! 123: case DOUBLE:
! 124: return string_format("%19.18g", d);
! 125: case INT:
! 126: return string_format("$%08x", i);
! 127: default:
! 128: return "NONE";
! 129: }
1.1.1.2 root 130: }
131: };
132:
1.1 root 133: // テスト情報 (グローバル)
134: static const char *testname;
135: static int testnum;
136: // 出力先 (グローバル)
137: static FILE *fp;
138:
139: #define IMM (0xff)
140:
1.1.1.2 root 141: // 理解しやすさのため 1, 2, 3 で表現しているが実際は r8, r10, r12 を使う
142: static constexpr uint32 ntor(uint32 n) {
143: assert(n < 4);
144: if (n == 0) return 0;
145: if (n == 1) return 8;
146: if (n == 2) return 10;
147: if (n == 3) return 12;
148: }
1.1 root 149: static constexpr uint32 R3(uint32 d, uint32 s1, uint32 s2) {
1.1.1.2 root 150: d = ntor(d);
151: s1 = ntor(s1);
152: s2 = ntor(s2);
1.1 root 153: return (d << 16) | (s1 << 8) | s2;
154: }
155: // 3オペランドの場合のレジスタの組み合わせ
156: static std::vector<uint32> reglist3 = {
157: R3(0, 0, 0),
158: R3(0, 0, 1),
159: R3(0, 1, 0),
160: R3(0, 1, 1),
161: R3(0, 1, 2),
162:
163: R3(1, 0, 0),
164: R3(1, 0, 1),
165: R3(1, 1, 0),
166: R3(1, 1, 1),
167: R3(1, 0, 2),
168: R3(1, 2, 0),
169: R3(1, 2, 2),
170: R3(1, 1, 2),
171: R3(1, 2, 1),
172: R3(1, 2, 3),
173: };
174:
175: // 2オペランド(+IMM)の場合のレジスタの組み合わせ
176: #define R2(d, s1) R3(d, s1, 0)
177: static std::vector<uint32> reglist2 = {
178: R2(0, 0),
179: R2(0, 1),
180: R2(1, 0),
181: R2(1, 1),
182: R2(1, 2),
183: };
184:
185: // r0 用の値リスト
186: static std::vector<uint32> v0 = {
187: 0,
188: };
1.1.1.2 root 189:
1.1 root 190: // 数値演算用の入力値リスト
191: static std::vector<uint32> vlist_arith = {
192: 0,
193: 1,
194: 2,
195: 0x7f,
196: 0x80,
197: 0xff,
198: 0x7fff,
199: 0x8000,
200: 0xffff,
201: 0x7fffffff,
202: 0x80000000,
203: 0xffffffff,
204: };
205: // ビットフィールド用の入力値リスト
206: // XXX どのパターンで試せばいいか
207: static std::vector<uint32> vlist_bf = {
208: 0x00000000,
209: 0x87654321,
210: 0xffffffff,
211: };
212: // ビットフィールド用の入力 W,O リスト
213: // XXX どのパターンで試せばいいか
214: #define WO(w, o) (((w) << 5) | (o))
215: static std::vector<uint32> vlist_wo = {
216: WO( 0, 0),
217: WO( 0, 1),
218: WO( 0, 2),
219: WO( 0, 31),
220: WO( 1, 0),
221: WO( 1, 1),
222: WO( 1, 31),
223: WO(16, 0),
224: WO(16, 15),
225: WO(16, 16),
226: WO(16, 17),
227: WO(16, 31),
228: WO(31, 0),
229: WO(31, 1),
230: WO(31, 31),
231: };
232: // ff0/ff1 用の入力値リスト
233: static std::vector<uint32> vlist_ff = {
234: 0x00000000,
235: 0x00000001,
236: 0x00000020,
237: 0x00000480,
238: 0x00009000,
239: 0x00010000,
240: 0x00200000,
241: 0x06000000,
242: 0xf0000000,
243: };
1.1.1.3 ! root 244: // r0 用
! 245: static std::vector<double> vf0 = {
! 246: 0.0,
! 247: };
! 248: // 浮動小数点数の入力値リスト
! 249: static std::vector<double> vlist_double = {
! 250: 0.0,
! 251: 1.0,
! 252: 2.0,
! 253: 16777215.0, // float → int で正確に表現できる最大値?
! 254: 16777215.5,
! 255: 16777217.0, // 16777216 は 1.0*2^24 で表現できるため省略
! 256: 1000000000.0, // 2^29 以上 2^30 以下
! 257: 2147483646.0, // INT32_MAX と区別可能な最大値
! 258: 2147483647.0, // INT32_MAX
! 259: 2147483647.5,
! 260: 2147483649.0,
! 261: 4294967295.0, // double → uint32 で正確に表現できる最大値?
! 262: 4294967295.5,
! 263: 4294967297.0,
! 264:
! 265: -0.0,
! 266: -1.0,
! 267: -2.0,
! 268: -16777215.0,
! 269: -16777215.5,
! 270: -16777217.0,
! 271: -1000000000.0,
! 272: -2000000000.0,
! 273: -2147483648.0,
! 274: -2147483648.5,
! 275: -2147483649.0,
! 276:
! 277: std::numeric_limits<double>::infinity(),
! 278: -std::numeric_limits<double>::infinity(),
! 279: std::nan(""),
! 280: };
! 281:
! 282: #define RM_NEAR (0)
! 283: #define RM_ZERO (1)
! 284: #define RM_MINUS (2)
! 285: #define RM_PLUS (3)
! 286:
! 287: static const char *rmstr[] = {
! 288: "RN",
! 289: "RZ",
! 290: "RM",
! 291: "RP",
! 292: };
1.1 root 293:
294: template <class T>
1.1.1.2 root 295: using Tuple2_1 = std::tuple<uint32, uint32, T>;
1.1 root 296: template <class T>
1.1.1.2 root 297: using Tuple2_2 = std::tuple<uint32, uint32, T, T>;
1.1 root 298: template <class T>
1.1.1.2 root 299: using Tuple3_2 = std::tuple<uint32, uint32, uint32, T, T>;
1.1 root 300:
1.1.1.3 ! root 301: static std::vector<Tuple3_2<uint32>> param_arith_reg;
! 302: static std::vector<Tuple2_2<uint32>> param_arith_imm;
! 303: static std::vector<Tuple3_2<uint32>> param_bitfield_reg;
! 304: static std::vector<Tuple2_2<uint32>> param_bitfield_imm;
! 305: static std::vector<Tuple2_1<uint32>> param_ff01;
! 306: static std::vector<Tuple2_1<uint32>> param_flt;
! 307: static std::vector<Tuple2_1<double>> param_trnc;
! 308: static std::vector<Tuple3_2<double>> param_fcmp;
1.1 root 309:
310: // 2オペランドテストの要素を変数に取り出す部分 (副作用のあるマクロ)
311: #define VAR_DIADIC(t, rd, rs2, vs2) \
312: uint32 rd = std::get<0>(t); \
313: uint32 rs2 = std::get<1>(t); \
1.1.1.2 root 314: auto vs2 = std::get<2>(t)
1.1 root 315:
316: // 3オペランドテストの要素を変数に取り出す部分 (副作用のあるマクロ)
317: #define VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2) \
318: uint32 rd = std::get<0>(t); \
319: uint32 rs1 = std::get<1>(t); \
320: uint32 rs2 = std::get<2>(t); \
1.1.1.2 root 321: auto vs1 = std::get<3>(t); \
322: auto vs2 = std::get<4>(t)
1.1 root 323:
324: // 3オペランド(IMM)テストの要素を変数に取り出す部分 (副作用のあるマクロ)
325: #define VAR_TRI_IMM(t, rd, rs1, vs1, imm) \
326: uint32 rd = std::get<0>(t); \
327: uint32 rs1 = std::get<1>(t); \
1.1.1.2 root 328: auto vs1 = std::get<2>(t); \
329: auto imm = std::get<3>(t)
1.1 root 330:
331:
1.1.1.3 ! root 332: // 自前の Round Mode 定数でシステムの丸めモードを設定する。
! 333: static void
! 334: setround(uint32 rm)
! 335: {
! 336: int mode;
! 337: switch (rm) {
! 338: case RM_NEAR:
! 339: mode = FE_TONEAREST;
! 340: break;
! 341: case RM_ZERO:
! 342: mode = FE_TOWARDZERO;
! 343: break;
! 344: case RM_MINUS:
! 345: mode = FE_DOWNWARD;
! 346: break;
! 347: case RM_PLUS:
! 348: mode = FE_UPWARD;
! 349: break;
! 350: default:
! 351: __unreachable();
! 352: }
! 353: std::fesetround(mode);
! 354: }
! 355:
! 356: // d が float でも同じ値として表現可能なら true を返す
! 357: static bool
! 358: can_float(double d)
! 359: {
! 360: float f = (float)d;
! 361:
! 362: // NAN 同士の == 比較は false になるため
! 363: if (std::isnan(d) && std::isnan(f))
! 364: return true;
! 365: if (d == f)
! 366: return true;
! 367: return false;
! 368: }
! 369:
1.1 root 370: // fp に出力
371: static void out(const char *fmt, ...)
372: {
373: va_list ap;
374:
375: va_start(ap, fmt);
376: vfprintf(fp, fmt, ap);
377: va_end(ap);
378: }
379:
380: // レジスタ regno に即値 imm をセットする
381: static void
382: MOV_imm(int regno, uint32 imm)
383: {
384: if (regno == 0) {
385: // nop
386: } else if (imm == 0) {
387: out(" xor %%r%d, %%r%d, %%r%d\n", regno, regno, regno);
388: } else if (imm < 0x10000) {
389: out(" or %%r%d, %%r0, 0x%04x\n", regno, imm);
390: } else if (imm == 0xffffffff) {
391: out(" or.c %%r%d, %%r0, %%r0 | MOV %%r%d, 0xffffffff\n",
392: regno, regno);
393: } else {
394: out(" or.u %%r%d, %%r0, 0x%04x | MOV %%r%d, 0x%08x\n",
395: regno, (imm >> 16), regno, imm);
1.1.1.3 ! root 396: if ((imm & 0xffff) != 0) {
! 397: out(" or %%r%d, %%r%d, 0x%04x\n",
! 398: regno, regno, imm & 0xffff);
! 399: }
1.1 root 400: }
401: }
402:
403:
404: //
405: // ここからテストコード
406: //
407:
408: // r2: 引数1: グローバル変数の先頭
409: // r2[0] = &exception_occurred
410: // r2[1] = &exception_expected
411: // r3: 引数2: 今回のテストのパラメータの先頭。内容は code ごとに異なる。
412: //
1.1.1.2 root 413: // r5: r1 のバックアップ
414: // r6(,r7): 期待 rD
415: // r8(,r9): rD (テストで使う)、結果の rD をここに入れて返す
416: // r10(,r11): rS1 (テストで使う)
417: // r12(,r13): rS2 (テストで使う)
418: //
419: // 規約では r10-13 がサブルーチンが破壊してよいレジスタで、
420: // r2-r9 は呼び出し側が引数を置くレジスタだがここもサブルーチンが破壊してよい
421: // ので使ってしまう。
422:
423: #define Rexp (6) // 期待値を格納するレジスタ
424: #define Rres (8) // 結果を格納するレジスタ
1.1 root 425:
426: // add でのオーバーフロー条件
427: static inline bool
428: isovf_add(uint32 s1, uint32 s2, uint32 res)
429: {
430: return (int32)((s1 ^ res) & (s2 ^ res)) < 0;
431: }
432:
433: // sub でのオーバーフロー条件
434: static inline bool
435: isovf_sub(uint32 s1, uint32 s2, uint32 res)
436: {
437: return (int32)((s1 ^ s2) & (s1 ^ res)) < 0;
438: }
439:
440: // 汎用演算命令共通のテストパターン出力部分
441: static void
1.1.1.3 ! root 442: outtest_generic(const char *mnemonic,
1.1 root 443: uint32 rd, uint32 rs1, uint32 rs2, uint32 vs1, uint32 vs2, uint32 exp_rd)
444: {
445: // rs2 が IMM なら #imm
446: bool is_imm = (rs2 == IMM);
447: uint32& imm = vs2;
448:
449: out("test_%s_%d:\n", testname, testnum);
450: if (is_imm) {
451: out(" /* %s r%d, r%d, #0x%04x (S1=$%08x) */\n",
452: mnemonic, rd, rs1, imm, vs1);
453: } else {
454: out(" /* %s r%d, r%d, r%d (S1=$%08x, S2=$%08x) */\n",
455: mnemonic, rd, rs1, rs2, vs1, vs2);
456: }
457:
458: out(" .word 0x%08x | exp_rd\n", exp_rd);
459: // ここからコード
460: MOV_imm(rs1, vs1);
461: if (!is_imm && rs1 != rs2) {
462: MOV_imm(rs2, vs2);
463: }
464:
465: if (is_imm) {
466: out(" %s %%r%d, %%r%d, 0x%04x | test\n", mnemonic, rd, rs1, imm);
467: } else {
468: out(" %s %%r%d, %%r%d, %%r%d | test\n", mnemonic, rd, rs1, rs2);
469: }
470:
1.1.1.2 root 471: if (rd != Rres) {
472: out(" or %%r%d, %%r0, %%r%d\n", Rres, rd);
1.1 root 473: }
474: out(" jmp %%r1\n");
475: out("\n");
476:
477: testnum++;
478: }
479:
480: // 2項ビットフィールド命令共通のテストパターン出力部分
1.1.1.3 ! root 481: // (outtest_generic と似てるけど微妙に違う)
1.1 root 482: static void
1.1.1.3 ! root 483: outtest_bitfield(const char *mnemonic,
1.1 root 484: uint32 rd, uint32 rs1, uint32 vs1, uint32 wo, uint32 exp_rd)
485: {
486: uint32 w = (wo >> 5) & 0x1f; // XXX 表記上は 0 なのか 32 なのか
487: uint32 o = wo & 0x1f;
488:
489: out("test_%s_%d:\n", testname, testnum);
490: out(" /* %s r%d, r%d, %d<%d> (S1=$%08x) */\n",
491: mnemonic, rd, rs1, w, o, vs1);
492:
493: out(" .word 0x%08x | exp_rd\n", exp_rd);
494: // ここからコード
495: MOV_imm(rs1, vs1);
496:
497: out(" %s %%r%d, %%r%d, %d<%d> | test\n", mnemonic, rd, rs1, w, o);
498:
1.1.1.2 root 499: if (rd != Rres) {
500: out(" or %%r%d, %%r0, %%r%d\n", Rres, rd);
1.1 root 501: }
502: out(" jmp %%r1\n");
503: out("\n");
504:
505: testnum++;
506: }
507:
508: // ff0/ff1 命令共通のテストパターン出力部分
1.1.1.3 ! root 509: // (outtest_generic と似てるけど微妙に違う)
1.1 root 510: static void
1.1.1.3 ! root 511: outtest_ff01(const char *mnemonic,
1.1 root 512: uint32 rd, uint32 rs2, uint32 vs2, uint32 exp_rd)
513: {
514: out("test_%s_%d:\n", testname, testnum);
515: out(" /* %s r%d, r%d (S2=$%08x) */\n",
516: mnemonic, rd, rs2, vs2);
517:
518: out(" .word 0x%08x | exp_rd\n", exp_rd);
519: // ここからコード
520: MOV_imm(rs2, vs2);
521:
522: out(" %s %%r%d, %%r%d | test\n", mnemonic, rd, rs2);
523:
1.1.1.2 root 524: if (rd != Rres) {
525: out(" or %%r%d, %%r0, %%r%d\n", Rres, rd);
1.1 root 526: }
527: out(" jmp %%r1\n");
528: out("\n");
529:
530: testnum++;
531: }
532:
533: // add/sub 命令共通のテストパターン出力部分
534: // rs2 == IMM なら即値指定。
535: // scale == true なら lda rD, rS1[rS2] 形式。
536: static void
1.1.1.3 ! root 537: outtest_addsub(const char *mnemonic,
1.1 root 538: uint32 rd, uint32 rs1, uint32 rs2, uint32 vs1, uint32 vs2, int cin,
539: uint32 exp_rd, uint32 exp_cy, bool exception = false, bool is_scale = false)
540: {
541: // rs2 が IMM なら #imm
542: bool is_imm = (rs2 == IMM);
543: uint32& imm = vs2;
544:
545: out("test_%s_%d:\n", testname, testnum);
546: if (is_imm) {
547: out(" /* %s r%d, r%d, #0x%04x (S1=$%08x, Cin=%d) */\n",
548: mnemonic, rd, rs1, imm, vs1, cin);
549: } else if (is_scale) {
550: out(" /* %s r%d, r%d[r%d] (S1=$%08x, S2=$%08x) */\n",
551: mnemonic, rd, rs1, rs2, vs1, vs2);
552: } else {
553: out(" /* %s r%d, r%d, r%d (S1=$%08x, S2=$%08x, Cin=%d) */\n",
554: mnemonic, rd, rs1, rs2, vs1, vs2, cin);
555: }
556:
557: out(" .word 0x%08x | exp_rd\n", exp_rd);
558: out(" .word 0x%08x | Cin|ExpCy|Exception|0\n",
559: (cin << 24) | (exp_cy << 16) | (exception << 8));
560: // ここからテストコード
561: // ソースレジスタをセット、実行、結果を保存
562: MOV_imm(rs1, vs1);
563: if (!is_imm && rs1 != rs2) {
564: MOV_imm(rs2, vs2);
565: }
566: if (exception) {
567: // 例外期待なら、rD (と Cy)の期待値は命令実行前の値 (p.6-19, 6.6)
1.1.1.2 root 568: out(" or %%r%d, %%r0, %%r%d\n", Rexp, rd);
1.1 root 569: } else {
1.1.1.2 root 570: MOV_imm(Rexp, exp_rd);
1.1 root 571: }
572:
573: if (exception) {
574: out(" | exception is expected\n");
575: }
576: if (is_imm) {
577: out(" %s %%r%d, %%r%d, 0x%04x | test\n", mnemonic, rd, rs1, imm);
578: } else if (is_scale) {
579: out(" %s %%r%d, %%r%d[%%r%d] | test\n", mnemonic, rd, rs1, rs2);
580: } else {
581: out(" %s %%r%d, %%r%d, %%r%d | test\n", mnemonic, rd, rs1, rs2);
582: }
583:
1.1.1.2 root 584: if (rd != Rres) {
585: out(" or %%r%d, %%r0, %%r%d\n", Rres, rd);
1.1 root 586: }
587: out(" jmp %%r1\n");
588: out("\n");
589:
590: testnum++;
591: }
592:
593: // div 命令共通のテストパターン出力部分
594: static void
1.1.1.3 ! root 595: outtest_div(const char *mnemonic,
1.1 root 596: uint32 rd, uint32 rs1, uint32 rs2, uint32 vs1, uint32 vs2,
597: uint32 exp_rd, bool exception = false)
598: {
599: // rs2 が IMM なら #imm
600: bool is_imm = (rs2 == IMM);
601: uint32& imm = vs2;
602:
603: out("test_%s_%d:\n", testname, testnum);
604: if (is_imm) {
605: out(" /* %s r%d, r%d, #0x%04x (S1=$%08x) */\n",
606: mnemonic, rd, rs1, imm, vs1);
607: } else {
608: out(" /* %s r%d, r%d, r%d (S1=$%08x, S2=$%08x) */\n",
609: mnemonic, rd, rs1, rs2, vs1, vs2);
610: }
611:
612: out(" .word 0x%08x | exp_ex\n", exception ? 2 : 0);
613: // ここからテストコード
614: // ソースレジスタをセット、実行、結果を保存
615: MOV_imm(rs1, vs1);
616: if (!is_imm && rs1 != rs2) {
617: MOV_imm(rs2, vs2);
618: }
619: if (exception) {
620: // 例外期待なら、rD の期待値は命令実行前の値 (p.6-40, 6.8.3)
1.1.1.2 root 621: out(" or %%r%d, %%r0, %%r%d\n", Rexp, rd);
1.1 root 622: } else {
1.1.1.2 root 623: MOV_imm(Rexp, exp_rd);
1.1 root 624: }
625:
626: if (exception) {
627: out(" | exception is expected\n");
628: }
629: if (is_imm) {
630: out(" %s %%r%d, %%r%d, 0x%04x | test\n", mnemonic, rd, rs1, imm);
631: } else {
632: out(" %s %%r%d, %%r%d, %%r%d | test\n", mnemonic, rd, rs1, rs2);
633: }
634:
1.1.1.2 root 635: if (rd != Rres) {
636: out(" or %%r%d, %%r0, %%r%d\n", Rres, rd);
637: }
638: out(" jmp %%r1\n");
639: out("\n");
640:
641: testnum++;
642: }
643:
1.1.1.3 ! root 644: // FP 命令共通のテストパターン出力部分。
! 645: // ソースレジスタが1つの場合 (rs1 を使わない場合) は fsz1 = '\0'、rs1 = -1 に
! 646: // すること(vs1 は不定でよい)。
! 647: static void
! 648: outtest_fop(const char *mnemonic, char fsz0, char fsz1, char fsz2,
! 649: uint32 rd, uint32 rs1, uint32 rs2, fpi vs1, fpi vs2,
! 650: uint32 rm, fpi expected, uint32 exception)
1.1.1.2 root 651: {
1.1.1.3 ! root 652: bool r4_backup = false;
! 653:
1.1.1.2 root 654: out("test_%s_%d:\n", testname, testnum);
1.1.1.3 ! root 655: if (fsz1 == '\0') {
! 656: out(" /* %s.%c%c r%d, r%d (S2=%s; %s) */\n",
! 657: mnemonic, fsz0, fsz2, rd, rs2,
! 658: vs2.ToString().c_str(), rmstr[rm]);
! 659: } else {
! 660: out(" /* %s.%c%c%c r%d, r%d, r%d (S1=%s, S2=%s; %s) */\n",
! 661: mnemonic, fsz0, fsz1, fsz2, rd, rs1, rs2,
! 662: vs1.ToString().c_str(), vs2.ToString().c_str(), rmstr[rm]);
! 663: }
1.1.1.2 root 664:
1.1.1.3 ! root 665: out(" .word 0x%08x | RndMode | exp_ex\n",
! 666: exception | (rm << (16 + 14)));
1.1.1.2 root 667: // ここからテストコード
1.1.1.3 ! root 668: if (fsz1 != '\0') {
! 669: MOV_imm(rs1, vs1.h);
! 670: if (fsz1 == 'd') {
! 671: if (rs1 == 0) {
! 672: // ソースが r0,r1 になるので r1 を(さらに)退避
! 673: out(" or %%r4, %%r0, %%r1\n");
! 674: r4_backup = true;
! 675: }
! 676: MOV_imm(rs1 + 1, vs1.l);
! 677: }
! 678: }
! 679: MOV_imm(rs2, vs2.h);
! 680: if (fsz2 == 'd') {
! 681: if (r4_backup == false && rs2 == 0) {
! 682: // ソースが r0,r1 になるので r1 を(さらに)退避
! 683: out(" or %%r4, %%r0, %%r1\n");
! 684: r4_backup = true;
! 685: }
! 686: MOV_imm(rs2 + 1, vs2.l);
! 687: }
1.1.1.2 root 688:
1.1.1.3 ! root 689: if (exception != 0) {
1.1.1.2 root 690: // 例外期待なら rD の期待値は命令実行前の値
691: out(" or %%r%d, %%r0, %%r%d\n", Rexp, rd);
1.1.1.3 ! root 692: if (fsz0 == 'd') {
! 693: out(" or %%r%d, %%r0, %%r%d\n", Rexp + 1, rd + 1);
1.1.1.2 root 694: }
1.1.1.3 ! root 695: } else {
1.1.1.2 root 696: // 例外が起きないことを期待する
1.1.1.3 ! root 697: MOV_imm(Rexp, expected.h);
! 698: if (fsz0 == 'd') {
! 699: MOV_imm(Rexp + 1, expected.l);
! 700: }
1.1.1.2 root 701: }
702:
1.1.1.3 ! root 703: if (fsz1 == '\0') {
! 704: out(" %s.%c%c %%r%d, %%r%d | test\n",
! 705: mnemonic, fsz0, fsz2, rd, rs2);
! 706: } else {
! 707: out(" %s.%c%c%c %%r%d, %%r%d, %%r%d | test\n",
! 708: mnemonic, fsz0, fsz1, fsz2, rd, rs1, rs2);
! 709: }
1.1.1.2 root 710:
1.1.1.3 ! root 711: if (r4_backup) {
! 712: out(" or %%r1, %%r0, %%r4\n");
! 713: }
1.1.1.2 root 714: if (rd != Rres) {
1.1.1.3 ! root 715: out(" or %%r%d, %%r0, %%r%d\n", Rres, rd);
! 716: if (fsz0 == 'd') {
! 717: out(" or %%r%d, %%r0, %%r%d\n", Rres + 1, rd + 1);
! 718: }
1.1 root 719: }
720: out(" jmp %%r1\n");
721: out("\n");
722:
723: testnum++;
724: }
725:
1.1.1.3 ! root 726: // FP 命令共通 (ソースレジスタが1つの形式)
! 727: static void
! 728: outtest_fop(const char *mnemonic, char fsz0, char fsz2,
! 729: uint32 rd, uint32 rs2, fpi vs2,
! 730: uint32 rm, fpi expected, uint32 exception)
! 731: {
! 732: fpi dummy_vs1;
! 733:
! 734: outtest_fop(mnemonic, fsz0, '\0', fsz2,
! 735: rd, (uint32)-1, rs2, dummy_vs1, vs2,
! 736: rm, expected, exception);
! 737: }
! 738:
! 739: // int, nint, trnc 命令共通のテストパターン出力部分。
! 740: // rm はテスト環境内の FPCR に設定する丸めモード (入力パラメータ)。
! 741: static void
! 742: outtest_toint(const char *mnemonic, uint32 rd, uint32 rs2, fpi vs2,
! 743: uint32 rm, uint64 exp)
! 744: {
! 745: uint32 exception = exp >> 32;
! 746: uint32 expected = exp;
! 747:
! 748: outtest_fop(mnemonic, 's', (vs2.IsFloat() ? 's' : 'd'),
! 749: rd, rs2, vs2, rm, expected, exception);
! 750: }
! 751:
! 752:
! 753: //
! 754: // ここからテストの出力
! 755: //
! 756:
1.1 root 757: static void
758: gen_add()
759: {
1.1.1.3 ! root 760: for (const auto& t : param_arith_reg) {
1.1 root 761: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
762:
763: for (int cin = 0; cin <= 1; cin++) {
764: // 期待値
765: uint64 result = (uint64)vs1 + vs2;
766: uint32 exp_rd = (uint32)result;
767: uint32 exp_cy = cin;
768: if (rd == 0) {
769: exp_rd = 0;
770: }
771: bool exp_ex = isovf_add(vs1, vs2, result);
772: if (exp_ex) {
773: exp_cy = cin;
774: }
775:
1.1.1.3 ! root 776: outtest_addsub("add",
1.1 root 777: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy, exp_ex);
778: }
779: }
780: }
781:
782: static void
783: gen_add_ci()
784: {
1.1.1.3 ! root 785: for (const auto& t : param_arith_reg) {
1.1 root 786: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
787:
788: for (int cin = 0; cin <= 1; cin++) {
789: // 期待値
790: uint64 result = (uint64)vs1 + vs2 + cin;
791: uint32 exp_rd = (uint32)result;
792: uint32 exp_cy = cin;
793: if (rd == 0) {
794: exp_rd = 0;
795: }
796: bool exp_ex = isovf_add(vs1, vs2, result);
797: if (exp_ex) {
798: exp_cy = cin;
799: }
800:
1.1.1.3 ! root 801: outtest_addsub("add.ci",
1.1 root 802: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy, exp_ex);
803: }
804: }
805: }
806:
807: static void
808: gen_add_co()
809: {
1.1.1.3 ! root 810: for (const auto& t : param_arith_reg) {
1.1 root 811: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
812:
813: for (int cin = 0; cin <= 1; cin++) {
814: // 期待値
815: uint64 result = (uint64)vs1 + vs2;
816: uint32 exp_rd = (uint32)result;
817: uint32 exp_cy = result >> 32;
818: if (rd == 0) {
819: exp_rd = 0;
820: }
821: bool exp_ex = isovf_add(vs1, vs2, result);
822: if (exp_ex) {
823: exp_cy = cin;
824: }
825:
1.1.1.3 ! root 826: outtest_addsub("add.co",
1.1 root 827: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy, exp_ex);
828: }
829: }
830: }
831:
832: static void
833: gen_add_cio()
834: {
1.1.1.3 ! root 835: for (const auto& t : param_arith_reg) {
1.1 root 836: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
837:
838: for (int cin = 0; cin <= 1; cin++) {
839: // 期待値
840: uint64 result = (uint64)vs1 + vs2 + cin;
841: uint32 exp_rd = (uint32)result;
842: uint32 exp_cy = result >> 32;
843: if (rd == 0) {
844: exp_rd = 0;
845: }
846: bool exp_ex = isovf_add(vs1, vs2, result);
847: if (exp_ex) {
848: exp_cy = cin;
849: }
850:
1.1.1.3 ! root 851: outtest_addsub("add.cio",
1.1 root 852: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy, exp_ex);
853: }
854: }
855: }
856:
857: static void
858: gen_add_imm()
859: {
1.1.1.3 ! root 860: for (const auto& t : param_arith_imm) {
1.1 root 861: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
862:
863: for (int cin = 0; cin <= 1; cin++) {
864: // 期待値
865: uint64 result = (uint64)vs1 + imm;
866: uint32 exp_rd = (uint32)result;
867: uint32 exp_cy = cin;
868: if (rd == 0) {
869: exp_rd = 0;
870: }
871: bool exp_ex = isovf_add(vs1, imm, result);
872: if (exp_ex) {
873: exp_cy = cin;
874: }
875:
1.1.1.3 ! root 876: outtest_addsub("add",
1.1 root 877: rd, rs1, IMM, vs1, imm, cin, exp_rd, exp_cy, exp_ex);
878: }
879: }
880: }
881:
882: // addu rD, rS1, rS2 と lda rD, rS1, rS2 は名前が違うだけで同じ…
883: static void
884: gen_addu_lda(const char *mnemonic)
885: {
1.1.1.3 ! root 886: for (const auto& t : param_arith_reg) {
1.1 root 887: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
888:
889: for (int cin = 0; cin <= 1; cin++) {
890: // 期待値
891: uint64 result = (uint64)vs1 + vs2;
892: uint32 exp_rd = (uint32)result;
893: uint32 exp_cy = cin;
894: if (rd == 0) {
895: exp_rd = 0;
896: }
897:
1.1.1.3 ! root 898: outtest_addsub(mnemonic,
1.1 root 899: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy);
900: }
901: }
902: }
903:
904: static void
905: gen_addu()
906: {
907: gen_addu_lda("addu");
908: }
909:
910: static void
911: gen_addu_ci()
912: {
1.1.1.3 ! root 913: for (const auto& t : param_arith_reg) {
1.1 root 914: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
915:
916: for (int cin = 0; cin <= 1; cin++) {
917: // 期待値
918: uint64 result = (uint64)vs1 + vs2 + cin;
919: uint32 exp_rd = (uint32)result;
920: uint32 exp_cy = cin;
921: if (rd == 0) {
922: exp_rd = 0;
923: }
924:
1.1.1.3 ! root 925: outtest_addsub("addu.ci",
1.1 root 926: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy);
927: }
928: }
929: }
930:
931: static void
932: gen_addu_co()
933: {
1.1.1.3 ! root 934: for (const auto& t : param_arith_reg) {
1.1 root 935: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
936:
937: for (int cin = 0; cin <= 1; cin++) {
938: // 期待値
939: uint64 result = (uint64)vs1 + vs2;
940: uint32 exp_rd = (uint32)result;
941: uint32 exp_cy = result >> 32;
942: if (rd == 0) {
943: exp_rd = 0;
944: }
945:
1.1.1.3 ! root 946: outtest_addsub("addu.co",
1.1 root 947: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy);
948: }
949: }
950: }
951:
952: static void
953: gen_addu_cio()
954: {
1.1.1.3 ! root 955: for (const auto& t : param_arith_reg) {
1.1 root 956: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
957:
958: for (int cin = 0; cin <= 1; cin++) {
959: // 期待値
960: uint64 result = (uint64)vs1 + vs2 + cin;
961: uint32 exp_rd = (uint32)result;
962: uint32 exp_cy = result >> 32;
963: if (rd == 0) {
964: exp_rd = 0;
965: }
966:
1.1.1.3 ! root 967: outtest_addsub("addu.cio",
1.1 root 968: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy);
969: }
970: }
971: }
972:
973: // addu rD, rS1, #imm と lda rD, rS1, #imm は名前が違うだけで同じ…
974: static void
975: gen_addu_lda_imm(const char *mnemonic)
976: {
1.1.1.3 ! root 977: for (const auto& t : param_arith_imm) {
1.1 root 978: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
979:
980: for (int cin = 0; cin <= 1; cin++) {
981: // 期待値
982: uint64 result = (uint64)vs1 + imm;
983: uint32 exp_rd = (uint32)result;
984: uint32 exp_cy = cin;
985: if (rd == 0) {
986: exp_rd = 0;
987: }
988:
1.1.1.3 ! root 989: outtest_addsub(mnemonic,
1.1 root 990: rd, rs1, IMM, vs1, imm, cin, exp_rd, exp_cy);
991: }
992: }
993: }
994:
995: static void
996: gen_addu_imm()
997: {
998: gen_addu_lda_imm("addu");
999: }
1000:
1001: static void
1002: gen_and()
1003: {
1.1.1.3 ! root 1004: for (const auto& t : param_arith_reg) {
1.1 root 1005: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1006: uint32 exp_rd = vs1 & vs2;
1007: if (rd == 0) {
1008: exp_rd = 0;
1009: }
1.1.1.3 ! root 1010: outtest_generic("and", rd, rs1, rs2, vs1, vs2, exp_rd);
1.1 root 1011: }
1012: }
1013:
1014: static void
1015: gen_and_c()
1016: {
1.1.1.3 ! root 1017: for (const auto& t : param_arith_reg) {
1.1 root 1018: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1019: uint32 exp_rd = vs1 & ~vs2;
1020: if (rd == 0) {
1021: exp_rd = 0;
1022: }
1.1.1.3 ! root 1023: outtest_generic("and.c", rd, rs1, rs2, vs1, vs2, exp_rd);
1.1 root 1024: }
1025: }
1026:
1027: static void
1028: gen_and_imm()
1029: {
1.1.1.3 ! root 1030: for (const auto& t : param_arith_imm) {
1.1 root 1031: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1032: uint32 exp_rd = vs1 & (imm | 0xffff0000);
1033: if (rd == 0) {
1034: exp_rd = 0;
1035: }
1.1.1.3 ! root 1036: outtest_generic("and", rd, rs1, IMM, vs1, imm, exp_rd);
1.1 root 1037: }
1038: }
1039:
1040: static void
1041: gen_and_u()
1042: {
1.1.1.3 ! root 1043: for (const auto& t : param_arith_imm) {
1.1 root 1044: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1045: uint32 exp_rd = vs1 & ((imm << 16) | 0xffff);
1046: if (rd == 0) {
1047: exp_rd = 0;
1048: }
1.1.1.3 ! root 1049: outtest_generic("and.u", rd, rs1, IMM, vs1, imm, exp_rd);
1.1 root 1050: }
1051: }
1052:
1053: static uint32
1054: calc_clr(uint32 src, uint32 wo)
1055: {
1056: uint32 w = ((wo >> 5) & 0x1f) ?: 32;
1057: uint32 o = wo & 0x1f;
1058: uint32 mask = (uint32)(((1ULL << w) - 1) << o);
1059: return src & ~mask;
1060: }
1061:
1062: static void
1063: gen_clr_imm()
1064: {
1.1.1.3 ! root 1065: for (const auto& t : param_bitfield_imm) {
1.1 root 1066: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1067: uint32 exp_rd = calc_clr(vs1, imm);
1068: if (rd == 0) {
1069: exp_rd = 0;
1070: }
1.1.1.3 ! root 1071: outtest_bitfield("clr", rd, rs1, vs1, imm, exp_rd);
1.1 root 1072: }
1073: }
1074:
1075: static void
1076: gen_clr_reg()
1077: {
1.1.1.3 ! root 1078: for (const auto& t : param_bitfield_reg) {
1.1 root 1079: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1080: uint32 exp_rd = calc_clr(vs1, vs2);
1081: if (rd == 0) {
1082: exp_rd = 0;
1083: }
1.1.1.3 ! root 1084: outtest_generic("clr", rd, rs1, rs2, vs1, vs2, exp_rd);
1.1 root 1085: }
1086: }
1087:
1088: static uint32
1089: calc_cmp(uint32 vs1, uint32 vs2)
1090: {
1091: // 期待値
1092: uint32 exp_rd = 0;
1093:
1094: exp_rd |= (vs1 >= vs2) ? 0x0800 : 0;
1095: exp_rd |= (vs1 < vs2) ? 0x0400 : 0;
1096: exp_rd |= (vs1 <= vs2) ? 0x0200 : 0;
1097: exp_rd |= (vs1 > vs2) ? 0x0100 : 0;
1098: exp_rd |= ((int32)vs1 >= (int32)vs2) ? 0x0080 : 0;
1099: exp_rd |= ((int32)vs1 < (int32)vs2) ? 0x0040 : 0;
1100: exp_rd |= ((int32)vs1 <= (int32)vs2) ? 0x0020 : 0;
1101: exp_rd |= ((int32)vs1 > (int32)vs2) ? 0x0010 : 0;
1102: exp_rd |= (vs1 != vs2) ? 0x0008 : 0;
1103: exp_rd |= (vs1 == vs2) ? 0x0004 : 0;
1104:
1105: return exp_rd;
1106: }
1107:
1108: static void
1109: gen_cmp()
1110: {
1.1.1.3 ! root 1111: for (const auto& t : param_arith_reg) {
1.1 root 1112: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1113: uint32 exp_rd = calc_cmp(vs1, vs2);
1114: if (rd == 0) {
1115: exp_rd = 0;
1116: }
1.1.1.3 ! root 1117: outtest_generic("cmp", rd, rs1, rs2, vs1, vs2, exp_rd);
1.1 root 1118: }
1119: }
1120:
1121: static void
1122: gen_cmp_imm()
1123: {
1.1.1.3 ! root 1124: for (const auto& t : param_arith_imm) {
1.1 root 1125: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1126: uint32 exp_rd = calc_cmp(vs1, imm);
1127: if (rd == 0) {
1128: exp_rd = 0;
1129: }
1.1.1.3 ! root 1130: outtest_generic("cmp", rd, rs1, IMM, vs1, imm, exp_rd);
1.1 root 1131: }
1132: }
1133:
1134: // 符号付きで x / y の期待値を計算する。
1135: // 計算可能な場合は *exp_rd に結果を書き戻し *exp_ex に false を書き戻す。
1136: // 例外を期待する場合は *exp_ex に true を書き戻す。
1137: static void
1138: calc_div(uint32 *exp_rd, bool *exp_ex, int32 x, int32 y)
1139: {
1140: // どちらかのオペランドが負でも例外らしい。符号付きとは一体…。
1141: if (x < 0 || y <= 0) {
1142: *exp_ex = true;
1143: *exp_rd = 0; // なくていいはずだけどコンパイラに怒られるので
1144: } else {
1145: *exp_ex = false;
1146: *exp_rd = (uint32)(x / y);
1147: }
1148: }
1149:
1150: static void
1151: gen_div()
1152: {
1.1.1.3 ! root 1153: for (const auto& t : param_arith_reg) {
1.1 root 1154: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1155: uint32 exp_rd;
1156: bool exp_ex;
1157: calc_div(&exp_rd, &exp_ex, vs1, vs2);
1158: if (rd == 0) {
1159: exp_rd = 0;
1160: }
1.1.1.3 ! root 1161: outtest_div("div", rd, rs1, rs2, vs1, vs2, exp_rd, exp_ex);
1.1 root 1162: }
1163: }
1164:
1165: static void
1166: gen_div_imm()
1167: {
1.1.1.3 ! root 1168: for (const auto& t : param_arith_imm) {
1.1 root 1169: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1170: uint32 exp_rd;
1171: bool exp_ex;
1172: calc_div(&exp_rd, &exp_ex, vs1, imm);
1173: if (rd == 0) {
1174: exp_rd = 0;
1175: }
1.1.1.3 ! root 1176: outtest_div("div", rd, rs1, IMM, vs1, imm, exp_rd, exp_ex);
1.1 root 1177: }
1178: }
1179:
1180: // 符号無しで x / y の期待値を計算する。
1181: // 計算可能な場合は *exp_rd に結果を書き戻し *exp_ex に false を書き戻す。
1182: // DivByZero を期待する場合は *exp_ex に true を書き戻す。
1183: static void
1184: calc_divu(uint32 *exp_rd, bool *exp_ex, uint32 x, uint32 y)
1185: {
1186: if (y == 0) {
1187: *exp_ex = true;
1188: *exp_rd = 0; // なくていいはずだけどコンパイラに怒られるので
1189: } else {
1190: *exp_ex = false;
1191: *exp_rd = x / y;
1192: }
1193: }
1194:
1195: static void
1196: gen_divu()
1197: {
1.1.1.3 ! root 1198: for (const auto& t : param_arith_reg) {
1.1 root 1199: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1200: uint32 exp_rd;
1201: bool exp_ex;
1202: calc_divu(&exp_rd, &exp_ex, vs1, vs2);
1203: if (rd == 0) {
1204: exp_rd = 0;
1205: }
1.1.1.3 ! root 1206: outtest_div("divu", rd, rs1, rs2, vs1, vs2, exp_rd, exp_ex);
1.1 root 1207: }
1208: }
1209:
1210: static void
1211: gen_divu_imm()
1212: {
1.1.1.3 ! root 1213: for (const auto& t : param_arith_imm) {
1.1 root 1214: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1215: uint32 exp_rd;
1216: bool exp_ex;
1217: calc_divu(&exp_rd, &exp_ex, vs1, imm);
1218: if (rd == 0) {
1219: exp_rd = 0;
1220: }
1.1.1.3 ! root 1221: outtest_div("divu", rd, rs1, IMM, vs1, imm, exp_rd, exp_ex);
1.1 root 1222: }
1223: }
1224:
1225: static uint32
1226: calc_ext(uint32 src, uint32 wo)
1227: {
1228: uint32 w = ((wo >> 5) & 0x1f) ?: 32;
1229: uint32 o = wo & 0x1f;
1230: uint32 mask = (uint32)(((1ULL << w) - 1) << o);
1231:
1232: src &= mask;
1233:
1234: int shift = 0;
1235: if (o + w < 32) {
1236: shift = 32 - (o + w);
1237: src <<= shift;
1238: }
1239: src = (int32)src >> (o + shift);
1240: return src;
1241: }
1242:
1243: static void
1244: gen_ext_imm()
1245: {
1.1.1.3 ! root 1246: for (const auto& t : param_bitfield_imm) {
1.1 root 1247: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1248: uint32 exp_rd = calc_ext(vs1, imm);
1249: if (rd == 0) {
1250: exp_rd = 0;
1251: }
1.1.1.3 ! root 1252: outtest_bitfield("ext", rd, rs1, vs1, imm, exp_rd);
1.1 root 1253: }
1254: }
1255:
1256: static void
1257: gen_ext_reg()
1258: {
1.1.1.3 ! root 1259: for (const auto& t : param_bitfield_reg) {
1.1 root 1260: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1261: uint32 exp_rd = calc_ext(vs1, vs2);
1262: if (rd == 0) {
1263: exp_rd = 0;
1264: }
1.1.1.3 ! root 1265: outtest_generic("ext", rd, rs1, rs2, vs1, vs2, exp_rd);
1.1 root 1266: }
1267: }
1268:
1269: static uint32
1270: calc_extu(uint32 src, uint32 wo)
1271: {
1272: uint32 w = ((wo >> 5) & 0x1f) ?: 32;
1273: uint32 o = wo & 0x1f;
1274: uint32 mask = (uint32)(((1ULL << w) - 1) << o);
1275:
1276: return (src & mask) >> o;
1277: }
1278:
1279: static void
1280: gen_extu_imm()
1281: {
1.1.1.3 ! root 1282: for (const auto& t : param_bitfield_imm) {
1.1 root 1283: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1284: uint32 exp_rd = calc_extu(vs1, imm);
1285: if (rd == 0) {
1286: exp_rd = 0;
1287: }
1.1.1.3 ! root 1288: outtest_bitfield("extu", rd, rs1, vs1, imm, exp_rd);
1.1 root 1289: }
1290: }
1291:
1292: static void
1293: gen_extu_reg()
1294: {
1.1.1.3 ! root 1295: for (const auto& t : param_bitfield_reg) {
1.1 root 1296: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1297: uint32 exp_rd = calc_extu(vs1, vs2);
1298: if (rd == 0) {
1299: exp_rd = 0;
1300: }
1.1.1.3 ! root 1301: outtest_generic("extu", rd, rs1, rs2, vs1, vs2, exp_rd);
! 1302: }
! 1303: }
! 1304:
! 1305: // fcmp.sXX の計算部分のみ
! 1306: static uint32
! 1307: calc_fcmp(double vs1, double vs2)
! 1308: {
! 1309: uint32 res = 0;
! 1310:
! 1311: if (vs2 >= 0) {
! 1312: res |= (vs1 <= 0 || vs1 >= vs2) ? 0x0800 : 0; // ob
! 1313: res |= (0 < vs1 && vs1 < vs2) ? 0x0400 : 0; // in
! 1314: res |= (0 <= vs1 && vs1 <= vs2) ? 0x0200 : 0; // ib
! 1315: res |= (vs1 < 0 || vs1 > vs2) ? 0x0100 : 0; // ou
! 1316: }
! 1317: res |= (vs1 >= vs2) ? 0x0080 : 0; // ge
! 1318: res |= (vs1 < vs2) ? 0x0040 : 0; // lt
! 1319: res |= (vs1 <= vs2) ? 0x0020 : 0; // le
! 1320: res |= (vs1 > vs2) ? 0x0010 : 0; // gt
! 1321: res |= (vs1 != vs2) ? 0x0008 : 0; // ne
! 1322: res |= (vs1 == vs2) ? 0x0004 : 0; // eq
! 1323: // cp; if and only if the two operands are comparable
! 1324: if (!std::isnan(vs1) && !std::isnan(vs2)) {
! 1325: res |= 0x0002;
1.1 root 1326: }
1.1.1.3 ! root 1327: // nc; if, and only if, the two operands are not comparable
! 1328: if (std::isnan(vs1) || std::isnan(vs2)) {
! 1329: res |= 0x0001;
! 1330: }
! 1331:
! 1332: return res;
1.1 root 1333: }
1334:
1.1.1.3 ! root 1335: // fcmp.sXX の共通部分
! 1336: static void
! 1337: gen_fcmp(char fsz1, const char fsz2)
! 1338: {
! 1339: for (uint32 rm = 0; rm < 4; rm++) {
! 1340: for (const auto& t : param_fcmp) {
! 1341: VAR_TRI_REG(t, rd, rs1, rs2, v1, v2);
! 1342: uint32 exception = 0;
! 1343: uint32 exp_rd = 0;
! 1344: fpi fpi1;
! 1345: fpi fpi2;
! 1346:
! 1347: // rS1, rS2 が同じで幅が違うのは(ゼロ以外は)意味がないので飛ばす
! 1348: if (rs1 == rs2 && fsz1 != fsz2 && (v1 != 0 && v2 != 0)) {
! 1349: continue;
! 1350: }
! 1351: // double で r0 を指すのは実質意味がないので飛ばす
! 1352: // (ゼロの場合は飛ばさなくてもいいけど面倒なので飛ばす)
! 1353: if (fsz1 == 'd' && rs1 == 0)
! 1354: continue;
! 1355: if (fsz2 == 'd' && rs2 == 0)
! 1356: continue;
! 1357:
! 1358: // ソースサイズが s なら float で表現できない値は飛ばす
! 1359: if (fsz1 == 's' && can_float(v1) == false)
! 1360: continue;
! 1361: if (fsz2 == 's' && can_float(v2) == false)
! 1362: continue;
! 1363:
! 1364: // r0 なら値も 0 としておかないといけない
! 1365: if (rs1 == 0) {
! 1366: v1 = 0;
! 1367: }
! 1368: if (rs2 == 0) {
! 1369: v2 = 0;
! 1370: }
! 1371:
! 1372: // rd ==0 の場合もソースに出力するコメントのために必要
! 1373: if (fsz1 == 's') {
! 1374: fpi1.Set((float)v1);
! 1375: } else {
! 1376: fpi1.Set(v1);
! 1377: }
! 1378: if (fsz2 == 's') {
! 1379: fpi2.Set((float)v2);
! 1380: } else {
! 1381: fpi2.Set(v2);
! 1382: }
! 1383:
! 1384: if (rd == 0) {
! 1385: exception = 0x1000;
! 1386: } else {
! 1387: exp_rd = calc_fcmp(fpi1.AsDouble(), fpi2.AsDouble());
! 1388: }
! 1389:
! 1390: outtest_fop("fcmp", 's', fsz1, fsz2,
! 1391: rd, rs1, rs2, fpi1, fpi2, rm, exp_rd, exception);
! 1392: }
! 1393: }
! 1394: }
! 1395: static void gen_fcmp_sss() { gen_fcmp('s', 's'); }
! 1396: static void gen_fcmp_ssd() { gen_fcmp('s', 'd'); }
! 1397: static void gen_fcmp_sds() { gen_fcmp('d', 's'); }
! 1398: static void gen_fcmp_sdd() { gen_fcmp('d', 'd'); }
! 1399:
1.1 root 1400: static void
1401: gen_ff0()
1402: {
1.1.1.3 ! root 1403: for (const auto& t : param_ff01) {
1.1 root 1404: VAR_DIADIC(t, rd, rs2, vs2);
1405: // 最も MSB 側にある %0 のビット位置(LSBを0とする)を返す
1406: // %0 がなければ 32 を返す
1407: uint32 exp_rd = 32;
1408: if (vs2 != 0xffffffff) {
1409: exp_rd = 31 - __builtin_clz(~vs2);
1410: }
1411: if (rd == 0) {
1412: exp_rd = 0;
1413: }
1.1.1.3 ! root 1414: outtest_ff01("ff0", rd, rs2, vs2, exp_rd);
1.1 root 1415: }
1416: }
1417:
1418: static void
1419: gen_ff1()
1420: {
1.1.1.3 ! root 1421: for (const auto& t : param_ff01) {
1.1 root 1422: VAR_DIADIC(t, rd, rs2, vs2);
1423: // 最も MSB 側にある %1 のビット位置(LSBを0とする)を返す
1424: // %0 がなければ 32 を返す
1425: uint32 exp_rd = 32;
1426: if (vs2 != 0x00000000) {
1427: exp_rd = 31 - __builtin_clz(vs2);
1428: }
1429: if (rd == 0) {
1430: exp_rd = 0;
1431: }
1.1.1.3 ! root 1432: outtest_ff01("ff1", rd, rs2, vs2, exp_rd);
1.1 root 1433: }
1434: }
1435:
1.1.1.2 root 1436: static void
1.1.1.3 ! root 1437: gen_flt_ss()
1.1.1.2 root 1438: {
1.1.1.3 ! root 1439: for (uint32 rm = 0; rm < 4; rm++) {
! 1440: setround(rm);
! 1441: for (const auto& t : param_flt) {
! 1442: VAR_DIADIC(t, rd, rs2, vs2);
! 1443: fpi fpi((float)(int32)vs2);
1.1.1.2 root 1444:
1.1.1.3 ! root 1445: outtest_fop("flt", 's', 's',
! 1446: rd, rs2, vs2, rm, fpi, (rd == 0 ? 0x1000 : 0));
! 1447: }
1.1.1.2 root 1448: }
1449: }
1450:
1451: static void
1452: gen_flt_ds()
1453: {
1.1.1.3 ! root 1454: for (uint32 rm = 0; rm < 4; rm++) {
! 1455: setround(rm);
! 1456: for (const auto& t : param_flt) {
! 1457: VAR_DIADIC(t, rd, rs2, vs2);
! 1458: fpi fpi((double)(int32)vs2);
! 1459:
! 1460: outtest_fop("flt", 'd', 's',
! 1461: rd, rs2, vs2, rm, fpi, (rd == 0 ? 0x1000 : 0));
! 1462: }
! 1463: }
! 1464: }
! 1465:
! 1466: // int, nint, trnc 命令共通の期待値計算。
! 1467: // 期待値を計算するための丸めモードはあらかじめ setround() で設定しておくこと。
! 1468: // 戻り値は上位 32bit が例外、下位 32bit が期待値。
! 1469: // 例外が出ることを期待する時は、上位が例外コード(非0)、下位は無視。
! 1470: // 例外が出ないことを期待する場合は、上位が 0、下位が期待値。
! 1471: static uint64
! 1472: calc_toint(uint32 rd, fpi vs2)
! 1473: {
! 1474: uint32 expected = 0;
! 1475: uint32 exception = 0;
! 1476:
! 1477: if (rd == 0) {
! 1478: exception = 0x1000;
! 1479: } else {
! 1480: double src = vs2.AsDouble();
! 1481: double result = std::nearbyint(src);
! 1482:
! 1483: int exponent = 0;
! 1484: std::frexp(result, &exponent);
! 1485:
! 1486: // 実際には trnc 命令は 30ビット以上で例外を出すが、
! 1487: // そこから先は (OpenBSD の) ソフトウェアハンドラが処理して
! 1488: // 実際に収まらなかった時は最大値を返す。
! 1489: if (std::isinf(result) || std::isnan(result) || exponent >= 32) {
! 1490: if (std::signbit(result)) {
! 1491: expected = 0x80000000;
! 1492: } else {
! 1493: expected = 0x7fffffff;
! 1494: }
! 1495: } else {
! 1496: expected = (int32)result;
! 1497: }
! 1498: }
! 1499:
! 1500: return ((uint64)exception << 32) | expected;
! 1501: }
! 1502:
! 1503: static void
! 1504: gen_int_ss()
! 1505: {
! 1506: for (uint32 rm = 0; rm < 4; rm++) {
! 1507: setround(rm);
! 1508: for (const auto& t : param_trnc) {
! 1509: VAR_DIADIC(t, rd, rs2, vs2);
! 1510: // float で表現できない値は飛ばす
! 1511: if (can_float(vs2))
! 1512: continue;
! 1513: fpi fpi((float)vs2);
! 1514: uint64 exp = calc_toint(rd, fpi);
! 1515: outtest_toint("int", rd, rs2, fpi, rm, exp);
! 1516: }
! 1517: }
1.1.1.2 root 1518: }
1519:
1520: static void
1.1.1.3 ! root 1521: gen_int_sd()
1.1.1.2 root 1522: {
1.1.1.3 ! root 1523: for (uint32 rm = 0; rm < 4; rm++) {
! 1524: setround(rm);
! 1525: for (const auto& t : param_trnc) {
! 1526: VAR_DIADIC(t, rd, rs2, vs2);
! 1527: fpi fpi(vs2);
! 1528: uint64 exp = calc_toint(rd, fpi);
! 1529: outtest_toint("int", rd, rs2, fpi, rm, exp);
! 1530: }
! 1531: }
1.1.1.2 root 1532: }
1533:
1.1 root 1534: // lda.* rD, rS1, #imm は addu rD, rS1, #imm と同じ
1535: static void
1536: gen_lda_imm()
1537: {
1538: gen_addu_lda_imm("lda");
1539: }
1540: static void
1541: gen_lda_b_imm()
1542: {
1543: gen_addu_lda_imm("lda.b");
1544: }
1545: static void
1546: gen_lda_h_imm()
1547: {
1548: gen_addu_lda_imm("lda.h");
1549: }
1550: static void
1551: gen_lda_d_imm()
1552: {
1553: gen_addu_lda_imm("lda.d");
1554: }
1555:
1556: // lda.* rD, rS1, rS2 は addu rD, rS1, rS2 と同じ
1557: static void
1558: gen_lda_reg()
1559: {
1560: gen_addu_lda("lda");
1561: }
1562: static void
1563: gen_lda_b_reg()
1564: {
1565: gen_addu_lda("lda.b");
1566: }
1567: static void
1568: gen_lda_h_reg()
1569: {
1570: gen_addu_lda("lda.h");
1571: }
1572: static void
1573: gen_lda_d_reg()
1574: {
1575: gen_addu_lda("lda.d");
1576: }
1577:
1578: static void
1579: gen_lda_scale(const char *mnemonic, uint32 scale)
1580: {
1.1.1.3 ! root 1581: for (const auto& t : param_arith_reg) {
1.1 root 1582: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1583:
1584: for (int cin = 0; cin <= 1; cin++) {
1585: // 期待値
1586: uint64 result = (uint64)vs1 + vs2 * scale;
1587: uint32 exp_rd = (uint32)result;
1588: uint32 exp_cy = cin;
1589: if (rd == 0) {
1590: exp_rd = 0;
1591: }
1592:
1593: bool exception = false;
1594: bool is_scale = true;
1.1.1.3 ! root 1595: outtest_addsub(mnemonic,
1.1 root 1596: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy,
1597: exception, is_scale);
1598: }
1599: }
1600: }
1601: static void
1602: gen_lda_scale()
1603: {
1604: gen_lda_scale("lda", 4);
1605: }
1606: static void
1607: gen_lda_b_scale()
1608: {
1609: gen_addu_lda("lda.b");
1610: }
1611: static void
1612: gen_lda_h_scale()
1613: {
1614: gen_lda_scale("lda.h", 2);
1615: }
1616: static void
1617: gen_lda_d_scale()
1618: {
1619: gen_lda_scale("lda.d", 8);
1620: }
1621:
1622: static uint32
1623: calc_mak(uint32 src, uint32 wo)
1624: {
1625: uint32 w = ((wo >> 5) & 0x1f) ?: 32;
1626: uint32 o = wo & 0x1f;
1627: uint32 mask = (uint32)((1ULL << w) - 1);
1628:
1629: return (src & mask) << o;
1630: }
1631:
1632: static void
1633: gen_mak_imm()
1634: {
1.1.1.3 ! root 1635: for (const auto& t : param_bitfield_imm) {
1.1 root 1636: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1637: uint32 exp_rd = calc_mak(vs1, imm);
1638: if (rd == 0) {
1639: exp_rd = 0;
1640: }
1.1.1.3 ! root 1641: outtest_bitfield("mak", rd, rs1, vs1, imm, exp_rd);
1.1 root 1642: }
1643: }
1644:
1645: static void
1646: gen_mak_reg()
1647: {
1.1.1.3 ! root 1648: for (const auto& t : param_bitfield_reg) {
1.1 root 1649: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1650: uint32 exp_rd = calc_mak(vs1, vs2);
1651: if (rd == 0) {
1652: exp_rd = 0;
1653: }
1.1.1.3 ! root 1654: outtest_generic("mak", rd, rs1, rs2, vs1, vs2, exp_rd);
1.1 root 1655: }
1656: }
1657:
1658: static void
1659: gen_mask_imm()
1660: {
1.1.1.3 ! root 1661: for (const auto& t : param_arith_imm) {
1.1 root 1662: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1663: uint32 exp_rd = vs1 & imm;
1664: if (rd == 0) {
1665: exp_rd = 0;
1666: }
1.1.1.3 ! root 1667: outtest_generic("mask", rd, rs1, IMM, vs1, imm, exp_rd);
1.1 root 1668: }
1669: }
1670:
1671: static void
1672: gen_mask_u()
1673: {
1.1.1.3 ! root 1674: for (const auto& t : param_arith_imm) {
1.1 root 1675: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1676: uint32 exp_rd = vs1 & (imm << 16);
1677: if (rd == 0) {
1678: exp_rd = 0;
1679: }
1.1.1.3 ! root 1680: outtest_generic("mask.u", rd, rs1, IMM, vs1, imm, exp_rd);
1.1 root 1681: }
1682: }
1683:
1684: static void
1685: gen_mul()
1686: {
1.1.1.3 ! root 1687: for (const auto& t : param_arith_reg) {
1.1 root 1688: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1689: uint32 exp_rd = (uint32)((uint64)vs1 * vs2);
1690: if (rd == 0) {
1691: exp_rd = 0;
1692: }
1.1.1.3 ! root 1693: outtest_generic("mul", rd, rs1, rs2, vs1, vs2, exp_rd);
1.1 root 1694: }
1695: }
1696:
1697: static void
1698: gen_mul_imm()
1699: {
1.1.1.3 ! root 1700: for (const auto& t : param_arith_imm) {
1.1 root 1701: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1702: uint32 exp_rd = (uint32)((uint64)vs1 * imm);
1703: if (rd == 0) {
1704: exp_rd = 0;
1705: }
1.1.1.3 ! root 1706: outtest_generic("mul", rd, rs1, IMM, vs1, imm, exp_rd);
! 1707: }
! 1708: }
! 1709:
! 1710: static void
! 1711: gen_nint_ss()
! 1712: {
! 1713: // 期待値は NEAR で計算
! 1714: setround(RM_NEAR);
! 1715:
! 1716: for (uint32 rm = 0; rm < 4; rm++) {
! 1717: for (const auto& t : param_trnc) {
! 1718: VAR_DIADIC(t, rd, rs2, vs2);
! 1719: // float で表現できない値は飛ばす
! 1720: if (can_float(vs2))
! 1721: continue;
! 1722: fpi fpi((float)vs2);
! 1723: uint64 exp = calc_toint(rd, fpi);
! 1724: outtest_toint("nint", rd, rs2, fpi, rm, exp);
! 1725: }
! 1726: }
! 1727: }
! 1728:
! 1729: static void
! 1730: gen_nint_sd()
! 1731: {
! 1732: // 期待値は NEAR で計算
! 1733: setround(RM_NEAR);
! 1734:
! 1735: for (uint32 rm = 0; rm < 4; rm++) {
! 1736: for (const auto& t : param_trnc) {
! 1737: VAR_DIADIC(t, rd, rs2, vs2);
! 1738: fpi fpi(vs2);
! 1739: uint64 exp = calc_toint(rd, fpi);
! 1740: outtest_toint("nint", rd, rs2, fpi, rm, exp);
! 1741: }
1.1 root 1742: }
1743: }
1744:
1745: static void
1746: gen_or()
1747: {
1.1.1.3 ! root 1748: for (const auto& t : param_arith_reg) {
1.1 root 1749: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1750: uint32 exp_rd = vs1 | vs2;
1751: if (rd == 0) {
1752: exp_rd = 0;
1753: }
1.1.1.3 ! root 1754: outtest_generic("or", rd, rs1, rs2, vs1, vs2, exp_rd);
1.1 root 1755: }
1756: }
1757:
1758: static void
1759: gen_or_c()
1760: {
1.1.1.3 ! root 1761: for (const auto& t : param_arith_reg) {
1.1 root 1762: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1763: uint32 exp_rd = vs1 | ~vs2;
1764: if (rd == 0) {
1765: exp_rd = 0;
1766: }
1.1.1.3 ! root 1767: outtest_generic("or.c", rd, rs1, rs2, vs1, vs2, exp_rd);
1.1 root 1768: }
1769: }
1770:
1771: static void
1772: gen_or_imm()
1773: {
1.1.1.3 ! root 1774: for (const auto& t : param_arith_imm) {
1.1 root 1775: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1776: uint32 exp_rd = vs1 | imm;
1777: if (rd == 0) {
1778: exp_rd = 0;
1779: }
1.1.1.3 ! root 1780: outtest_generic("or", rd, rs1, IMM, vs1, imm, exp_rd);
1.1 root 1781: }
1782: }
1783:
1784: static void
1785: gen_or_u()
1786: {
1.1.1.3 ! root 1787: for (const auto& t : param_arith_imm) {
1.1 root 1788: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1789: uint32 exp_rd = vs1 | (imm << 16);
1790: if (rd == 0) {
1791: exp_rd = 0;
1792: }
1.1.1.3 ! root 1793: outtest_generic("or.u", rd, rs1, IMM, vs1, imm, exp_rd);
1.1 root 1794: }
1795: }
1796:
1797: static uint32
1798: calc_rot(uint32 src, uint32 wo)
1799: {
1800: uint32 o = wo & 0x1f;
1801: return (src >> o) | (src << (32 - o));
1802: }
1803:
1804: static void
1805: gen_rot_imm()
1806: {
1807: // 手抜きで W は無視するのでパターンが重複する
1.1.1.3 ! root 1808: for (const auto& t : param_bitfield_imm) {
1.1 root 1809: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1810: uint32 exp_rd = calc_rot(vs1, imm);
1811: if (rd == 0) {
1812: exp_rd = 0;
1813: }
1.1.1.3 ! root 1814: outtest_bitfield("rot", rd, rs1, vs1, imm, exp_rd);
1.1 root 1815: }
1816: }
1817:
1818: static void
1819: gen_rot_reg()
1820: {
1821: // 手抜きで W は無視するのでパターンが重複する
1.1.1.3 ! root 1822: for (const auto& t : param_bitfield_reg) {
1.1 root 1823: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1824: uint32 exp_rd = calc_rot(vs1, vs2);
1825: if (rd == 0) {
1826: exp_rd = 0;
1827: }
1.1.1.3 ! root 1828: outtest_generic("rot", rd, rs1, rs2, vs1, vs2, exp_rd);
1.1 root 1829: }
1830: }
1831:
1832: static uint32
1833: calc_set(uint32 src, uint32 wo)
1834: {
1835: uint32 w = ((wo >> 5) & 0x1f) ?: 32;
1836: uint32 o = wo & 0x1f;
1837: uint32 mask = (uint32)(((1ULL << w) - 1) << o);
1838: return src | mask;
1839: }
1840:
1841: static void
1842: gen_set_imm()
1843: {
1.1.1.3 ! root 1844: for (const auto& t : param_bitfield_imm) {
1.1 root 1845: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1846: uint32 exp_rd = calc_set(vs1, imm);
1847: if (rd == 0) {
1848: exp_rd = 0;
1849: }
1.1.1.3 ! root 1850: outtest_bitfield("set", rd, rs1, vs1, imm, exp_rd);
1.1 root 1851: }
1852: }
1853:
1854: static void
1855: gen_set_reg()
1856: {
1.1.1.3 ! root 1857: for (const auto& t : param_bitfield_reg) {
1.1 root 1858: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1859: uint32 exp_rd = calc_set(vs1, vs2);
1860: if (rd == 0) {
1861: exp_rd = 0;
1862: }
1.1.1.3 ! root 1863: outtest_generic("set", rd, rs1, rs2, vs1, vs2, exp_rd);
1.1 root 1864: }
1865: }
1866:
1867: static void
1868: gen_sub()
1869: {
1.1.1.3 ! root 1870: for (const auto& t : param_arith_reg) {
1.1 root 1871: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1872:
1873: for (int cin = 0; cin <= 1; cin++) {
1874: // 期待値
1875: uint64 result = (uint64)vs1 + (~vs2) + 1;
1876: uint32 exp_rd = (uint32)result;
1877: uint32 exp_cy = cin;
1878: if (rd == 0) {
1879: exp_rd = 0;
1880: }
1881: bool exp_ex = isovf_sub(vs1, vs2, result);
1882: if (exp_ex) {
1883: exp_cy = cin;
1884: }
1885:
1.1.1.3 ! root 1886: outtest_addsub("sub",
1.1 root 1887: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy, exp_ex);
1888: }
1889: }
1890: }
1891:
1892: static void
1893: gen_sub_ci()
1894: {
1.1.1.3 ! root 1895: for (const auto& t : param_arith_reg) {
1.1 root 1896: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1897:
1898: for (int cin = 0; cin <= 1; cin++) {
1899: // 期待値
1900: uint64 result = (uint64)vs1 + (~vs2) + cin;
1901: uint32 exp_rd = (uint32)result;
1902: uint32 exp_cy = cin;
1903: if (rd == 0) {
1904: exp_rd = 0;
1905: }
1906: bool exp_ex = isovf_sub(vs1, vs2, result);
1907: if (exp_ex) {
1908: exp_cy = cin;
1909: }
1910:
1.1.1.3 ! root 1911: outtest_addsub("sub.ci",
1.1 root 1912: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy, exp_ex);
1913: }
1914: }
1915: }
1916:
1917: static void
1918: gen_sub_co()
1919: {
1.1.1.3 ! root 1920: for (const auto& t : param_arith_reg) {
1.1 root 1921: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1922:
1923: for (int cin = 0; cin <= 1; cin++) {
1924: // 期待値
1925: uint64 result = (uint64)vs1 + (~vs2) + 1;
1926: uint32 exp_rd = (uint32)result;
1927: uint32 exp_cy = result >> 32;
1928: if (rd == 0) {
1929: exp_rd = 0;
1930: }
1931: bool exp_ex = isovf_sub(vs1, vs2, result);
1932: if (exp_ex) {
1933: exp_cy = cin;
1934: }
1935:
1.1.1.3 ! root 1936: outtest_addsub("sub.co",
1.1 root 1937: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy, exp_ex);
1938: }
1939: }
1940: }
1941:
1942: static void
1943: gen_sub_cio()
1944: {
1.1.1.3 ! root 1945: for (const auto& t : param_arith_reg) {
1.1 root 1946: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1947:
1948: for (int cin = 0; cin <= 1; cin++) {
1949: // 期待値
1950: uint64 result = (uint64)vs1 + (~vs2) + cin;
1951: uint32 exp_rd = (uint32)result;
1952: uint32 exp_cy = result >> 32;
1953: if (rd == 0) {
1954: exp_rd = 0;
1955: }
1956: bool exp_ex = isovf_sub(vs1, vs2, result);
1957: if (exp_ex) {
1958: exp_cy = cin;
1959: }
1960:
1.1.1.3 ! root 1961: outtest_addsub("sub.cio",
1.1 root 1962: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy, exp_ex);
1963: }
1964: }
1965: }
1966:
1967: static void
1968: gen_sub_imm()
1969: {
1.1.1.3 ! root 1970: for (const auto& t : param_arith_imm) {
1.1 root 1971: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
1972:
1973: for (int cin = 0; cin <= 1; cin++) {
1974: // 期待値
1975: uint64 result = (uint64)vs1 + (~imm) + 1;
1976: uint32 exp_rd = (uint32)result;
1977: uint32 exp_cy = cin;
1978: if (rd == 0) {
1979: exp_rd = 0;
1980: }
1981: bool exp_ex = isovf_sub(vs1, imm, result);
1982: if (exp_ex) {
1983: exp_cy = cin;
1984: }
1985:
1.1.1.3 ! root 1986: outtest_addsub("sub",
1.1 root 1987: rd, rs1, IMM, vs1, imm, cin, exp_rd, exp_cy, exp_ex);
1988: }
1989: }
1990: }
1991:
1992: static void
1993: gen_subu()
1994: {
1.1.1.3 ! root 1995: for (const auto& t : param_arith_reg) {
1.1 root 1996: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
1997:
1998: for (int cin = 0; cin <= 1; cin++) {
1999: // 期待値
2000: uint64 result = (uint64)vs1 + (~vs2) + 1;
2001: uint32 exp_rd = (uint32)result;
2002: uint32 exp_cy = cin;
2003: if (rd == 0) {
2004: exp_rd = 0;
2005: }
2006:
1.1.1.3 ! root 2007: outtest_addsub("subu",
1.1 root 2008: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy);
2009: }
2010: }
2011: }
2012:
2013: static void
2014: gen_subu_ci()
2015: {
1.1.1.3 ! root 2016: for (const auto& t : param_arith_reg) {
1.1 root 2017: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
2018:
2019: for (int cin = 0; cin <= 1; cin++) {
2020: // 期待値
2021: uint64 result = (uint64)vs1 + (~vs2) + cin;
2022: uint32 exp_rd = (uint32)result;
2023: uint32 exp_cy = cin;
2024: if (rd == 0) {
2025: exp_rd = 0;
2026: }
2027:
1.1.1.3 ! root 2028: outtest_addsub("subu.ci",
1.1 root 2029: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy);
2030: }
2031: }
2032: }
2033:
2034: static void
2035: gen_subu_co()
2036: {
1.1.1.3 ! root 2037: for (const auto& t : param_arith_reg) {
1.1 root 2038: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
2039:
2040: for (int cin = 0; cin <= 1; cin++) {
2041: // 期待値
2042: uint64 result = (uint64)vs1 + (~vs2) + 1;
2043: uint32 exp_rd = (uint32)result;
2044: uint32 exp_cy = result >> 32;
2045: if (rd == 0) {
2046: exp_rd = 0;
2047: }
2048:
1.1.1.3 ! root 2049: outtest_addsub("subu.co",
1.1 root 2050: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy);
2051: }
2052: }
2053: }
2054:
2055: static void
2056: gen_subu_cio()
2057: {
1.1.1.3 ! root 2058: for (const auto& t : param_arith_reg) {
1.1 root 2059: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
2060:
2061: for (int cin = 0; cin <= 1; cin++) {
2062: // 期待値
2063: uint64 result = (uint64)vs1 + (~vs2) + cin;
2064: uint32 exp_rd = (uint32)result;
2065: uint32 exp_cy = result >> 32;
2066: if (rd == 0) {
2067: exp_rd = 0;
2068: }
2069:
1.1.1.3 ! root 2070: outtest_addsub("subu.cio",
1.1 root 2071: rd, rs1, rs2, vs1, vs2, cin, exp_rd, exp_cy);
2072: }
2073: }
2074: }
2075:
2076: static void
2077: gen_subu_imm()
2078: {
1.1.1.3 ! root 2079: for (const auto& t : param_arith_imm) {
1.1 root 2080: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
2081:
2082: for (int cin = 0; cin <= 1; cin++) {
2083: // 期待値
2084: uint64 result = (uint64)vs1 + (~imm) + 1;
2085: uint32 exp_rd = (uint32)result;
2086: uint32 exp_cy = cin;
2087: if (rd == 0) {
2088: exp_rd = 0;
2089: }
2090:
1.1.1.3 ! root 2091: outtest_addsub("subu",
1.1 root 2092: rd, rs1, IMM, vs1, imm, cin, exp_rd, exp_cy);
2093: }
2094: }
2095: }
2096:
2097: static void
1.1.1.3 ! root 2098: gen_trnc_ss()
! 2099: {
! 2100: // 期待値は ZERO で計算
! 2101: setround(RM_ZERO);
! 2102:
! 2103: for (uint32 rm = 0; rm < 4; rm++) {
! 2104: for (const auto& t : param_trnc) {
! 2105: VAR_DIADIC(t, rd, rs2, vs2);
! 2106: // float で表現できない値は飛ばす
! 2107: if (can_float(vs2))
! 2108: continue;
! 2109: fpi fpi((float)vs2);
! 2110: uint64 exp = calc_toint(rd, fpi);
! 2111: outtest_toint("trnc", rd, rs2, fpi, rm, exp);
! 2112: }
! 2113: }
! 2114: }
! 2115:
! 2116: static void
! 2117: gen_trnc_sd()
! 2118: {
! 2119: // 期待値は ZERO で計算
! 2120: setround(RM_ZERO);
! 2121:
! 2122: for (uint32 rm = 0; rm < 4; rm++) {
! 2123: for (const auto& t : param_trnc) {
! 2124: VAR_DIADIC(t, rd, rs2, vs2);
! 2125: fpi fpi(vs2);
! 2126: uint64 exp = calc_toint(rd, fpi);
! 2127: outtest_toint("trnc", rd, rs2, fpi, rm, exp);
! 2128: }
! 2129: }
! 2130: }
! 2131:
! 2132: static void
1.1 root 2133: gen_xor()
2134: {
1.1.1.3 ! root 2135: for (const auto& t : param_arith_reg) {
1.1 root 2136: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
2137: uint32 exp_rd = vs1 ^ vs2;
2138: if (rd == 0) {
2139: exp_rd = 0;
2140: }
1.1.1.3 ! root 2141: outtest_generic("xor", rd, rs1, rs2, vs1, vs2, exp_rd);
1.1 root 2142: }
2143: }
2144:
2145: static void
2146: gen_xor_c()
2147: {
1.1.1.3 ! root 2148: for (const auto& t : param_arith_reg) {
1.1 root 2149: VAR_TRI_REG(t, rd, rs1, rs2, vs1, vs2);
2150: uint32 exp_rd = vs1 ^ ~vs2;
2151: if (rd == 0) {
2152: exp_rd = 0;
2153: }
1.1.1.3 ! root 2154: outtest_generic("xor.c", rd, rs1, rs2, vs1, vs2, exp_rd);
1.1 root 2155: }
2156: }
2157:
2158: static void
2159: gen_xor_imm()
2160: {
1.1.1.3 ! root 2161: for (const auto& t : param_arith_imm) {
1.1 root 2162: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
2163: uint32 exp_rd = vs1 ^ imm;
2164: if (rd == 0) {
2165: exp_rd = 0;
2166: }
1.1.1.3 ! root 2167: outtest_generic("xor", rd, rs1, IMM, vs1, imm, exp_rd);
1.1 root 2168: }
2169: }
2170:
2171: static void
2172: gen_xor_u()
2173: {
1.1.1.3 ! root 2174: for (const auto& t : param_arith_imm) {
1.1 root 2175: VAR_TRI_IMM(t, rd, rs1, vs1, imm);
2176: uint32 exp_rd = vs1 ^ (imm << 16);
2177: if (rd == 0) {
2178: exp_rd = 0;
2179: }
1.1.1.3 ! root 2180: outtest_generic("xor.u", rd, rs1, IMM, vs1, imm, exp_rd);
1.1 root 2181: }
2182: }
2183:
2184:
2185:
2186: //
2187: // ここから出力用の処理
2188: //
2189:
2190: enum {
2191: G_ADD = 1,
2192: G_SUB,
2193: G_LOGICAL,
2194: G_BITFIELD,
2195: G_LDA,
2196: G_MULDIV,
1.1.1.2 root 2197: G_FLT,
1.1.1.3 ! root 2198: G_FCMP,
1.1 root 2199: };
2200:
2201: // テスト一覧 (編集しやすいように実体は一番下に置いてある)
2202: struct testentry {
2203: int group;
2204: const char *code;
2205: void (*genfunc)();
1.1.1.3 ! root 2206: int quad; // 結果が 64bit なら 1
1.1 root 2207: const char *name;
2208: };
2209: extern std::vector<testentry> test_table;
2210:
2211: // list の中に val がなければ追加する
2212: template <class T>
2213: static void append(std::vector<T>& list, const T& val)
2214: {
2215: if (std::find(list.begin(), list.end(), val) == list.end()) {
2216: list.emplace_back(val);
2217: }
2218: }
2219:
2220: // ファイルオープンとクローズ (副作用のあるマクロ)
2221: #define FOPEN(filename_) do { \
2222: filename = filename_; \
2223: tmpname = filename + ".tmp"; \
2224: fp = fopen(tmpname.c_str(), "w"); \
2225: if (fp == NULL) { \
2226: err(1, "%s", tmpname.c_str()); \
2227: } \
2228: out("/* This file was created by %s */\n", getprogname()); \
2229: out("\n"); \
2230: } while (0)
2231: #define FCLOSE() do { \
2232: fclose(fp); \
2233: compare_and_move(tmpname, filename); \
2234: } while (0)
2235:
1.1.1.3 ! root 2236: // src, dst のファイルが異なっていれば src を dst に rename する
! 2237: static void
! 2238: compare_and_move(const std::string& src, const std::string& dst)
! 2239: {
! 2240: struct stat st;
! 2241: int r;
! 2242: bool update;
! 2243:
! 2244: update = false;
! 2245: r = stat(dst.c_str(), &st);
! 2246: if (r < 0) {
! 2247: // dst not found
! 2248: update = true;
! 2249: } else {
! 2250: // dst exists
! 2251:
! 2252: std::string cmd = "cmp -s " + src + " " + dst;
! 2253: r = system(cmd.c_str());
! 2254: if (r < 0) {
! 2255: err(1, "system");
! 2256: }
! 2257: r = WEXITSTATUS(r);
! 2258: if (r > 1) {
! 2259: errx(1, "cmp failed?");
! 2260: }
! 2261:
! 2262: if (r == 0) {
! 2263: // src and dst are the same
! 2264: } else {
! 2265: update = true;
! 2266: }
! 2267: }
! 2268:
! 2269: if (update) {
! 2270: // 違っていれば、src を dst に移動
! 2271: r = rename(src.c_str(), dst.c_str());
! 2272: if (r < 0) {
! 2273: err(1, "rename: %s %s", src.c_str(), dst.c_str());
! 2274: }
! 2275: printf("Updated: %s\n", dst.c_str());
! 2276: } else {
! 2277: // 同じなら、今作った src のほうを消す
! 2278: r = remove(src.c_str());
! 2279: if (r < 0) {
! 2280: err(1, "remove: %s", src.c_str());
! 2281: }
! 2282: }
! 2283: }
1.1 root 2284: // テストアセンブリソースの出力共通部分
2285: static void
2286: print_test(const testentry& t)
2287: {
2288: // グローバル変数にセット
2289: testname = t.name;
2290: testnum = 0;
2291:
2292: // テストの実体を出力
2293: t.genfunc();
2294:
2295: // テーブル
2296: out(".globl list_%s\n", testname);
2297: out("list_%s:\n", testname);
2298: for (int i = 0; i < testnum; i++) {
2299: out("\t.word test_%s_%d\n", testname, i);
2300: }
2301: out("\t.word 0\n");
2302: out("\n");
2303: }
2304:
1.1.1.3 ! root 2305: // ソースファイルを作成
! 2306: static void
! 2307: create_file(const std::string& filename_, int group)
! 2308: {
! 2309: std::string filename;
! 2310: std::string tmpname;
! 2311:
! 2312: FOPEN(filename_);
! 2313: for (const auto& t : test_table) {
! 2314: if (t.group == group) {
! 2315: print_test(t);
! 2316: }
! 2317: }
! 2318: FCLOSE();
! 2319: }
! 2320:
1.1 root 2321: static void compare_and_move(const std::string&, const std::string&);
2322:
2323: int
2324: main(int ac, char *av[])
2325: {
2326: std::string filename;
2327: std::string tmpname;
2328:
2329: // テストパターンを用意
2330: for (const auto& rlist : reglist3) {
2331: auto rd = (rlist >> 16) & 0xff;
2332: auto rs1 = (rlist >> 8) & 0xff;
2333: auto rs2 = rlist & 0xff;
2334:
2335: std::vector<uint32> *v_arith_s1 = (rs1 == 0) ? &v0 : &vlist_arith;
2336: std::vector<uint32> *v_arith_s2 = (rs2 == 0) ? &v0 : &vlist_arith;
2337:
2338: if (rs1 == rs2) {
2339: for (const auto& vs1 : *v_arith_s1) {
1.1.1.2 root 2340: Tuple3_2<uint32> val(rd, rs1, rs2, vs1, vs1);
1.1.1.3 ! root 2341: append(param_arith_reg, val);
1.1 root 2342: }
2343: } else {
2344: for (const auto& vs1 : *v_arith_s1) {
2345: for (const auto& vs2 : *v_arith_s2) {
1.1.1.2 root 2346: Tuple3_2<uint32> val(rd, rs1, rs2, vs1, vs2);
1.1.1.3 ! root 2347: append(param_arith_reg, val);
1.1 root 2348: }
2349: }
2350: }
2351: }
2352: for (const auto& rlist : reglist2) {
2353: auto rd = (rlist >> 16) & 0xff;
2354: auto rs1 = (rlist >> 8) & 0xff;
2355:
2356: std::vector<uint32> *v_arith_s1 = (rs1 == 0) ? &v0 : &vlist_arith;
2357:
2358: for (const auto& vs1 : *v_arith_s1) {
2359: for (const auto& imm : vlist_arith) {
2360: if (imm <= 0xffff) {
1.1.1.2 root 2361: Tuple2_2<uint32> val(rd, rs1, vs1, imm);
1.1.1.3 ! root 2362: append(param_arith_imm, val);
1.1 root 2363: }
2364: }
2365: }
2366: }
2367: for (const auto& rlist : reglist3) {
2368: auto rd = (rlist >> 16) & 0xff;
2369: auto rs1 = (rlist >> 8) & 0xff;
2370: auto rs2 = rlist & 0xff;
2371:
2372: std::vector<uint32> *v_bf = (rs1 == 0) ? &v0 : &vlist_bf;
2373: std::vector<uint32> *v_wo = (rs2 == 0) ? &v0 : &vlist_wo;
2374:
2375: if (rs1 == rs2) {
2376: for (const auto& vs1 : *v_bf) {
1.1.1.2 root 2377: Tuple3_2<uint32> val(rd, rs1, rs2, vs1, vs1);
1.1.1.3 ! root 2378: append(param_bitfield_reg, val);
1.1 root 2379: }
2380: for (const auto& vs2 : *v_wo) {
1.1.1.2 root 2381: Tuple3_2<uint32> val(rd, rs1, rs2, vs2, vs2);
1.1.1.3 ! root 2382: append(param_bitfield_reg, val);
1.1 root 2383: }
2384: } else {
2385: for (const auto& vs1 : *v_bf) {
2386: for (const auto& vs2 : *v_wo) {
1.1.1.2 root 2387: Tuple3_2<uint32> val(rd, rs1, rs2, vs1, vs2);
1.1.1.3 ! root 2388: append(param_bitfield_reg, val);
1.1 root 2389: }
2390: }
2391: }
2392: }
2393: for (const auto& rlist : reglist2) {
2394: auto rd = (rlist >> 16) & 0xff;
2395: auto rs1 = (rlist >> 8) & 0xff;
2396:
2397: std::vector<uint32> *v_bf = (rs1 == 0) ? &v0 : &vlist_bf;
2398:
2399: for (const auto& vs1 : *v_bf) {
2400: for (const auto& wo : vlist_wo) {
1.1.1.2 root 2401: Tuple2_2<uint32> val(rd, rs1, vs1, wo);
1.1.1.3 ! root 2402: append(param_bitfield_imm, val);
1.1 root 2403: }
2404: }
2405: }
2406: for (const auto& rlist : reglist2) {
2407: auto rd = (rlist >> 16) & 0xff;
2408: auto rs2 = (rlist >> 8) & 0xff;
2409:
2410: std::vector<uint32> v_ff;
2411: if (rs2 == 0) {
2412: v_ff = v0;
2413: } else {
2414: // vlist_arith とそれをビット反転したもの
2415: for (const auto v : vlist_arith) {
2416: v_ff.emplace_back(v);
2417: v_ff.emplace_back(~v);
2418: }
2419: }
2420:
2421: for (const auto& vs2 : v_ff) {
1.1.1.2 root 2422: Tuple2_1<uint32> val(rd, rs2, vs2);
1.1.1.3 ! root 2423: append(param_ff01, val);
1.1 root 2424: }
2425: }
1.1.1.2 root 2426: for (const auto& rlist : reglist2) {
2427: auto rd = (rlist >> 16) & 0xff;
2428: auto rs2 = (rlist >> 8) & 0xff;
2429:
2430: std::vector<uint32> *v_arith_s2 = (rs2 == 0) ? &v0 : &vlist_arith;
2431:
2432: for (const auto& vs2 : *v_arith_s2) {
2433: Tuple2_1<uint32> val(rd, rs2, vs2);
1.1.1.3 ! root 2434: append(param_flt, val);
1.1 root 2435: }
2436: }
1.1.1.3 ! root 2437: for (const auto& rlist : reglist2) {
! 2438: auto rd = (rlist >> 16) & 0xff;
! 2439: auto rs2 = (rlist >> 8) & 0xff;
1.1 root 2440:
1.1.1.3 ! root 2441: if (rs2 == 0) {
! 2442: Tuple2_1<double> val(rd, rs2, 0.0);
! 2443: append(param_trnc, val);
! 2444: } else {
! 2445: for (const auto& vs2 : vlist_double) {
! 2446: Tuple2_1<double> val(rd, rs2, vs2);
! 2447: append(param_trnc, val);
! 2448: }
1.1 root 2449: }
2450: }
2451:
1.1.1.3 ! root 2452: for (const auto& rlist : reglist3) {
! 2453: auto rd = (rlist >> 16) & 0xff;
! 2454: auto rs1 = (rlist >> 8) & 0xff;
! 2455: auto rs2 = rlist & 0xff;
1.1 root 2456:
1.1.1.3 ! root 2457: std::vector<double> *vlist1 = (rs1 == 0) ? &vf0 : &vlist_double;
! 2458: std::vector<double> *vlist2 = (rs2 == 0) ? &vf0 : &vlist_double;
1.1 root 2459:
1.1.1.3 ! root 2460: if (rs1 == rs2) {
! 2461: for (const auto& vs1 : *vlist1) {
! 2462: Tuple3_2<double> val(rd, rs1, rs2, vs1, vs1);
! 2463: append(param_fcmp, val);
! 2464: }
! 2465: } else {
! 2466: for (const auto& vs1 : *vlist1) {
! 2467: for (const auto& vs2 : *vlist2) {
! 2468: Tuple3_2<double> val(rd, rs1, rs2, vs1, vs2);
! 2469: append(param_fcmp, val);
! 2470: }
! 2471: }
1.1 root 2472: }
2473: }
2474:
1.1.1.3 ! root 2475: // ソースファイルを出力
! 2476: create_file("optestm88k_add.s", G_ADD);
! 2477: create_file("optestm88k_sub.s", G_SUB);
! 2478: create_file("optestm88k_logical.s", G_LOGICAL);
! 2479: create_file("optestm88k_bitfield.s",G_BITFIELD);
! 2480: create_file("optestm88k_lda.s", G_LDA);
! 2481: create_file("optestm88k_muldiv.s", G_MULDIV);
! 2482: create_file("optestm88k_flt.s", G_FLT);
! 2483: create_file("optestm88k_fcmp.s", G_FCMP);
1.1.1.2 root 2484:
2485: //
1.1 root 2486: // table.h を出力
2487: //
2488: FOPEN("optestm88k_table.h");
2489: out("#ifndef optestm88k_table_h\n");
2490: out("#define optestm88k_table_h\n");
2491: out("\n");
2492: // testcode は table_*.name を uniq したもの
2493: std::vector<std::string> test_code_list;
2494: for (const auto& t : test_table) {
2495: append(test_code_list, std::string(t.code));
2496: }
2497: for (const auto& name : test_code_list) {
2498: out("extern int test_%s(int *, int *);\n", name.c_str());
2499: }
2500: out("\n");
2501:
2502: for (const auto& t : test_table) {
2503: out("extern int *list_%s[];\n", t.name);
2504: }
2505: out("\n");
2506: out("#endif /* !optestm88k_table_h */\n");
2507: FCLOSE();
2508:
2509: //
2510: // table.c を出力
2511: //
2512: FOPEN("optestm88k_table.c");
2513: out("#include \"optestm88k_main.h\"\n");
2514: out("#include \"optestm88k_table.h\"\n");
2515: out("\n");
2516: out("struct testentry test_table[] = {\n");
2517: for (const auto& t : test_table) {
1.1.1.3 ! root 2518: out(" { test_%s,\tlist_%s,\t%d, \"%s\" },\n",
! 2519: t.code, t.name, t.quad, t.name);
1.1 root 2520: }
1.1.1.3 ! root 2521: out(" { NULL },\n");
1.1 root 2522: out("};\n");
2523: FCLOSE();
2524:
2525: return 0;
2526: }
2527:
2528: //
2529: // テスト一覧
2530: //
1.1.1.3 ! root 2531: #define T(group, code, quad, name) { group, code, gen_##name, quad, #name }
1.1 root 2532: std::vector<testentry> test_table = {
1.1.1.3 ! root 2533: T(G_ADD, "addsub", 0, add),
! 2534: T(G_ADD, "addsub", 0, add_ci),
! 2535: T(G_ADD, "addsub", 0, add_co),
! 2536: T(G_ADD, "addsub", 0, add_cio),
! 2537: T(G_ADD, "addsub", 0, add_imm),
! 2538: T(G_ADD, "addsub", 0, addu),
! 2539: T(G_ADD, "addsub", 0, addu_ci),
! 2540: T(G_ADD, "addsub", 0, addu_co),
! 2541: T(G_ADD, "addsub", 0, addu_cio),
! 2542: T(G_ADD, "addsub", 0, addu_imm),
! 2543:
! 2544: T(G_SUB, "addsub", 0, sub),
! 2545: T(G_SUB, "addsub", 0, sub_ci),
! 2546: T(G_SUB, "addsub", 0, sub_co),
! 2547: T(G_SUB, "addsub", 0, sub_cio),
! 2548: T(G_SUB, "addsub", 0, sub_imm),
! 2549: T(G_SUB, "addsub", 0, subu),
! 2550: T(G_SUB, "addsub", 0, subu_ci),
! 2551: T(G_SUB, "addsub", 0, subu_co),
! 2552: T(G_SUB, "addsub", 0, subu_cio),
! 2553: T(G_SUB, "addsub", 0, subu_imm),
! 2554: T(G_SUB, "generic", 0, cmp),
! 2555: T(G_SUB, "generic", 0, cmp_imm),
! 2556:
! 2557: T(G_LOGICAL, "generic", 0, and),
! 2558: T(G_LOGICAL, "generic", 0, and_c),
! 2559: T(G_LOGICAL, "generic", 0, and_imm),
! 2560: T(G_LOGICAL, "generic", 0, and_u),
! 2561: T(G_LOGICAL, "generic", 0, mask_imm),
! 2562: T(G_LOGICAL, "generic", 0, mask_u),
! 2563: T(G_LOGICAL, "generic", 0, or),
! 2564: T(G_LOGICAL, "generic", 0, or_c),
! 2565: T(G_LOGICAL, "generic", 0, or_imm),
! 2566: T(G_LOGICAL, "generic", 0, or_u),
! 2567: T(G_LOGICAL, "generic", 0, xor),
! 2568: T(G_LOGICAL, "generic", 0, xor_c),
! 2569: T(G_LOGICAL, "generic", 0, xor_imm),
! 2570: T(G_LOGICAL, "generic", 0, xor_u),
! 2571:
! 2572: T(G_BITFIELD, "generic", 0, clr_imm),
! 2573: T(G_BITFIELD, "generic", 0, clr_reg),
! 2574: T(G_BITFIELD, "generic", 0, ext_imm),
! 2575: T(G_BITFIELD, "generic", 0, ext_reg),
! 2576: T(G_BITFIELD, "generic", 0, extu_imm),
! 2577: T(G_BITFIELD, "generic", 0, extu_reg),
! 2578: T(G_BITFIELD, "generic", 0, ff0),
! 2579: T(G_BITFIELD, "generic", 0, ff1),
! 2580: T(G_BITFIELD, "generic", 0, mak_imm),
! 2581: T(G_BITFIELD, "generic", 0, mak_reg),
! 2582: T(G_BITFIELD, "generic", 0, rot_imm),
! 2583: T(G_BITFIELD, "generic", 0, rot_reg),
! 2584: T(G_BITFIELD, "generic", 0, set_imm),
! 2585: T(G_BITFIELD, "generic", 0, set_reg),
! 2586:
! 2587: T(G_LDA, "addsub", 0, lda_imm),
! 2588: T(G_LDA, "addsub", 0, lda_b_imm),
! 2589: T(G_LDA, "addsub", 0, lda_h_imm),
! 2590: T(G_LDA, "addsub", 0, lda_d_imm),
! 2591: T(G_LDA, "addsub", 0, lda_reg),
! 2592: T(G_LDA, "addsub", 0, lda_b_reg),
! 2593: T(G_LDA, "addsub", 0, lda_h_reg),
! 2594: T(G_LDA, "addsub", 0, lda_d_reg),
! 2595: T(G_LDA, "addsub", 0, lda_scale),
! 2596: T(G_LDA, "addsub", 0, lda_b_scale),
! 2597: T(G_LDA, "addsub", 0, lda_h_scale),
! 2598: T(G_LDA, "addsub", 0, lda_d_scale),
! 2599:
! 2600: T(G_MULDIV, "generic", 0, mul),
! 2601: T(G_MULDIV, "generic", 0, mul_imm),
! 2602: T(G_MULDIV, "div", 0, div),
! 2603: T(G_MULDIV, "div", 0, div_imm),
! 2604: T(G_MULDIV, "div", 0, divu),
! 2605: T(G_MULDIV, "div", 0, divu_imm),
! 2606:
! 2607: T(G_FLT, "fop_s", 0, flt_ss),
! 2608: T(G_FLT, "fop_d", 1, flt_ds),
! 2609: T(G_FLT, "fop_s", 0, trnc_ss),
! 2610: T(G_FLT, "fop_s", 0, trnc_sd),
! 2611: T(G_FLT, "fop_s", 0, nint_ss),
! 2612: T(G_FLT, "fop_s", 0, nint_sd),
! 2613: T(G_FLT, "fop_s", 0, int_ss),
! 2614: T(G_FLT, "fop_s", 0, int_sd),
! 2615:
! 2616: T(G_FCMP, "fop_s", 0, fcmp_sss),
! 2617: T(G_FCMP, "fop_s", 0, fcmp_ssd),
! 2618: T(G_FCMP, "fop_s", 0, fcmp_sds),
! 2619: T(G_FCMP, "fop_s", 0, fcmp_sdd),
1.1 root 2620: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.