Annotation of nono/exp/optestm88k/optestm88k_gen.cpp, revision 1.1.1.3

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: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.