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