Annotation of nono/m680x0/m680x0fpu.cpp, revision 1.1.1.4

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //     +------ 030(without FPU)
                      8: //     |       +-- 030(+6888x)
                      9: //     |       |       040     LC040
                     10: //     S       o       o       4       : FSAVE/FRESTORE (有効なEA)
                     11: //     F       F       F               : FSAVE/FRESTORE (無効なEA)
                     12: //     F       o       o       4       : 040 でも実装してある命令 (有効なEA)
                     13: //     F       F       F               : 040 でも実装してある命令 (無効なEA)
                     14: //     F       o       2       4       : 6888x 命令 (有効なEA)
                     15: //     F       F       F?              : 6888x 命令 (無効なEA)
                     16: //     F       F       F       F       : 無効な命令ビットパターン
                     17: //
                     18: //     (厳密に言えばFPU命令ではないが)
                     19: //     S       S       F?      F?      : cpSAVE/cpRESTORE (有効なEA)
                     20: //     F       F       F?      F?      : cpSAVE/cpRESTORE (無効なEA)
                     21: //     …     XEiJ の flineprivilege.x によると、無効な EA のパターンは
                     22: //             68030 では F ライン例外になる。
                     23: //             040 ではコプロセッサプロトコル自体が廃止されているので
                     24: //             ここはいずれも F ライン例外になるだろうか。
                     25: //
                     26: // o: 有効な命令処理
                     27: // F: F ライン例外 (Format$0)
                     28: // 2: 浮動小数点未実装例外(Format$2)
                     29: // 4: 浮動小数点未実装例外(Format$4)
                     30: // S: 特権違反例外
                     31: 
                     32: // 68040:
                     33: //                     Int     .S      .D      .X      .P
                     34: // ノーマル数             o       o       o       o       x
                     35: // Zero                                o       o       o       o       x
                     36: // Inf                         -       o       o       o       x
                     37: // NAN                         -       o       o       o       x
                     38: // 非正規化数             -       x       x       x       x
                     39: // アンノーマル数       -       -       -       x       x
                     40: //
                     41: // o: ハードウェアサポート
                     42: // x: ソフトウェアサポート
                     43: 
1.1.1.4 ! root       44: // 68040 の BUSY フレーム:
        !            45: // MC68040UM.pdf (p.9-40)、fpsp/fpsp.h より。
        !            46: //
        !            47: //           1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
        !            48: //          +---------------+---------------+---------------+---------------+
        !            49: //$00       |  VERSION=$41  |     $60       |                               |
        !            50: //          +---------------+---------------+---------------+---------------+
        !            51: //$04       |                                                               |
        !            52: //          +---------------+---------------+---------------+---------------+
        !            53: //$08(LV-92)|   CU_SAVEPC : |(FPR_DIRTY_BITS)                               |
        !            54: //          +---------------+---------------+---------------+---------------+
        !            55: //$0c(LV-88)|                                                               |
        !            56: //$10(LV-84)|                                                               |
        !            57: //$14(LV-80)|                                                               |
        !            58: //          +---------------+---------------+---------------+---------------+
        !            59: //$18(LV-76)| |<- WBTS   WBTE[14:0]         |  (WBTEMP_SGN) |               |
        !            60: //          +---------------+---------------+---------------+---------------+
        !            61: //           (WBTEMP_SGN) のバイトは fpsp がワークとして使っているようだ。
        !            62: //          +---------------+---------------+---------------+---------------+
        !            63: //$1c(LV-72)|       WBTM[63-32]   (資料によって [65-34][33-02] 表記もあるが |
        !            64: //$20(LV-68)|       WBTM[31-00]    ここでは仮数部のビット位置で数える)      |
        !            65: //          +---------------+---------------+---------------+---------------+
        !            66: //$24(LV-64)|                         (FPSR_SHADOW)                         |
        !            67: //          +---------------+---------------+---------------+---------------+
        !            68: //$28(LV-60)|                            FPIARCU                            |
        !            69: //          +---------------+---------------+---------------+---------------+
        !            70: //$2c(LV-56)|                                                               |
        !            71: //          +---------------+---------------+---------------+---------------+
        !            72: //$30(LV-52)|          (CMDREG2B.W?/.L?)                                    |
        !            73: //          +---------+-----+---------------+---------------+---------------+
        !            74: //$34(LV-48)|         |       CMDREG3B      |                               |
        !            75: //          +---------+-----+---------------+---------------+---------------+
        !            76: //$38(LV-44)|    (NMNEXC)   |    (NMCEXC)   |                               |
        !            77: //          |            N N|N N N C C C C C|                               |
        !            78: //          |            U N|O V D U S O V D|                               |
        !            79: //          +---------------+---------------+---------------+---------------+
        !            80: //     NMN Unsupported --+ | | | | | | | | +-- NMC Underflow
        !            81: //     NMN SNAN        ----+ | | | | | | +---- NMC Overflow
        !            82: //     NMN OPErr       ------+ | | | | +------ NMC OPErr
        !            83: //     NMN Overflow    --------+ | | +-------- NMC SNAN
        !            84: //     NMN Underflow   ----------+ +---------- NMC Unsupported
        !            85: //          +---------------+---------------+---------------+---------------+
        !            86: //$3c(LV-40)|STAG |E| |V|G|R|S|             |                               |
        !            87: //          +---------------+---------------+---------------+---------------+
        !            88: //     (ETEMP15) --+   | | | +-- SBIT   (WBTEMP Sticky)
        !            89: //                     | | +---- WBTM0  (WBTEMP Round)
        !            90: //                     | +------ WBTM1  (WBTEMP Guard)
        !            91: //                     +-------- WBTM66 (WBTEMP Overflow)
        !            92: //          +---------------+---------------+---------------+---------------+
        !            93: //$40(LV-36)|          CMDREG1B             |                               |
        !            94: //          +-------+-------+-------+-------+---------------+---------------+
        !            95: //$44(LV-32)|DTAG |F|. . . .:. . .|W|. . . .|                               |
        !            96: //          +-------+-------+-------+-------+---------------+---------------+
        !            97: //                 +-- (FPTEMP15)  +-- (WBTEMP15)
        !            98: //          +---------------+---------------+---------------+---------------+
        !            99: //$48(LV-28)|. . . . .|E|E|S|X|.|U|T|. . . .|                               |
        !           100: //          |         |1|3|F|F| |F|F|       |                               |
        !           101: //          +---------------+---------------+---------------+---------------+
        !           102: //               (SFLAG) --+ |   | +--  TFLAG
        !           103: //               (XFLAG) ----+   +---- (UFLAG)
        !           104: //          +---------------+---------------+---------------+---------------+
        !           105: //$4c(LV-24)| |<-FPTS      FPTE             |                               |
        !           106: //          +---------------+---------------+---------------+---------------+
        !           107: //$50(LV-20)|                         FPTM[63-32]                           |
        !           108: //$54(LV-16)|                         FPTM[31-00]                           |
        !           109: //          +---------------+---------------+---------------+---------------+
        !           110: //$58(LV-12)| |<-ETS       ETE              |                               |
        !           111: //          +---------------+---------------+---------------+---------------+
        !           112: //$5c(LV-8) |                         ETM[63-32]                            |
        !           113: //$60(LV-4) |                         ETM[31-00]                            |
        !           114: //          +---------------+---------------+---------------+---------------+
        !           115: //$64(LV-0)
        !           116: 
1.1       root      117: #include "mpu680x0.h"
                    118: #include "m680x0disasm.h"
1.1.1.3   root      119: #include "m680x0cycle.h"
1.1       root      120: #include "textscreen.h"
                    121: 
                    122: #define SIZE_L (0)
                    123: #define SIZE_S (1)
                    124: #define SIZE_X (2)
                    125: #define SIZE_P (3)
                    126: #define SIZE_W (4)
                    127: #define SIZE_D (5)
                    128: #define SIZE_B (6)
                    129: 
                    130: // val が単精度で非正規化数なら true を返す。
                    131: static inline bool
                    132: is_denormal_s(uint32 val)
                    133: {
                    134:        uint32 e = (val >> 23) & 0xff;
                    135:        uint32 m = val & 0x7f'ffff;
                    136:        if (e == 0 && m != 0) {
                    137:                return true;
                    138:        }
                    139:        return false;
                    140: }
                    141: 
                    142: // data[0..1] が倍精度で非正規化数なら true を返す。
                    143: static inline bool
                    144: is_denormal_d(const uint32 *data)
                    145: {
                    146:        uint32 e = (data[0] >> 20) & 0x7ff;
                    147:        uint64 m = ((uint64)(data[0] & 0x000f'ffff) << 32) | data[1];
                    148:        if (e == 0 && m != 0) {
                    149:                return true;
                    150:        }
                    151:        return false;
                    152: }
                    153: 
                    154: // data[0..2] が拡張精度で非正規化数なら true を返す。
                    155: static inline bool
                    156: is_denormal_x(const uint32 *data)
                    157: {
                    158:        uint32 e = (data[0] >> 16) & 0x7fff;
                    159:        uint32 i = (data[1] >> 31) & 1;
                    160:        uint64 m = (((uint64)(data[1] & 0x7fff'ffff)) << 32) | data[2];
                    161:        if (e == 0 && i == 0 && m != 0) {
                    162:                return true;
                    163:        }
                    164:        return false;
                    165: }
                    166: 
                    167: // data[0..2] が拡張精度でアンノーマル数なら true を返す。
                    168: static inline bool
                    169: is_unnormal_x(const uint32 *data)
                    170: {
                    171:        uint32 e = (data[0] >> 16) & 0x7fff;
                    172:        uint32 i = (data[1] >> 31) & 1;
                    173:        uint64 m = (((uint64)(data[1] & 0x7fff'ffff)) << 32) | data[2];
                    174:        if (e != 0 && e != 0x7fff && i == 0 && m != 0) {
                    175:                return true;
                    176:        }
                    177:        // XXX Unnormal zero はハード処理かソフト処理か分からない。
                    178:        if (e != 0 && e != 0x7fff && i == 0 && m == 0) {
                    179:                return true;
                    180:        }
                    181:        return false;
                    182: }
                    183: 
                    184: // リセット用のレジスタ初期値
                    185: /*static*/ struct fpframe
                    186: MPU680x0Device::initial_fpframe;
                    187: 
                    188: // 初期化
                    189: void
                    190: MPU680x0Device::fpu_init()
                    191: {
                    192:        int i;
                    193:        uint32_t *p;
                    194: 
                    195:        // XXX cpu の初期化のところと見直してマージするとか
                    196:        memset(&fe, 0, sizeof(fe));
                    197:        memset(&reg.fpframe, 0, sizeof(reg.fpframe));
                    198:        fe.fe_fpframe = &reg.fpframe;
                    199: 
                    200:        // FRESTORE によるリセット用に FP レジスタの初期値を用意しておく。
                    201:        // FPn は NAN に。FPSR, FPCR, FPIAR はゼロクリアされる。
                    202:        memset(&initial_fpframe, 0, sizeof(initial_fpframe));
                    203:        p = initial_fpframe.fpf_regs;
                    204:        for (i = 0; i < 8; i++) {
                    205:                *p++ = 0x7fff0000;
                    206:                *p++ = 0xffffffff;
                    207:                *p++ = 0xffffffff;
                    208:        }
                    209: }
                    210: 
                    211: // FPU をリセットする。
                    212: // MPU リセット時(true)と、NULL フレームのリストア時(false)に呼ばれる。
                    213: void
                    214: MPU680x0Device::ResetFPU(bool hard)
                    215: {
                    216:        // 高速化のため、あらかじめ用意しておいたイメージをコピーする
                    217:        memcpy(&reg.fpframe, &initial_fpframe, sizeof(initial_fpframe));
                    218: 
                    219:        fpu_state = FPU_STATE_NULL;
                    220: 
                    221:        if (__predict_false(hard)) {
                    222:                // この内部情報は NULL フレームのリストア (頻繁に起きる) のたびに
                    223:                // モニタから消えるよりは、直近の1つが見え続けていてほしい。
                    224:                // ただしハードリセット前の状態は引き継がない。
                    225:                memset(&fpu40, 0, sizeof(fpu40));
                    226:                fpu40.reg1b = 0xffff;
                    227:                fpu40.stag = FPU40::TAG_NONE;
                    228:                fpu40.dtag = FPU40::TAG_NONE;
                    229:        }
                    230:        fpu40.enable = false;
                    231: }
                    232: 
                    233: // FPU からの呼び出し用。
                    234: //
                    235: // (An)+, -(An) は、サイズが増えているのとクロックが増加している(2->6)。
                    236: // それ以外のアドレッシングモードでもクロック数は微妙に違うのだが、
                    237: // 大きくは違わないのでそっちは本体の cea と同じということにする。
                    238: //
                    239: // このルーチンは Dn、An、#imm には対応していないので(自明)、呼び出し側で
                    240: // 事前に弾くこと。いずれも消費クロック数は 0 なので問題ない。
                    241: // またそれ以外のすべてのアドレッシングモードで反応するため、命令ごとに
                    242: // 対応していないアドレッシングモードは事前に弾くこと。
1.1.1.2   root      243: uint32
1.1       root      244: MPU680x0Device::cea_fpu(int bytes)
                    245: {
                    246:        int n;
                    247: 
                    248:        switch (eamode(ir)) {
                    249:         case 0:        // Dn
                    250:         case 1:        // An
                    251:                break;
                    252:         case 2:        // (An)
                    253:                return cea_anin(eanum(ir));
                    254:         case 3:        // (An)+
1.1.1.3   root      255:                CYCLE3(cea_fpu_anpi);
1.1       root      256:                n = eanum(ir);
                    257:                save_reg_pi(n);
                    258:                if (bytes == 1) {
                    259:                        return internal_ea_anpi_1(n);
                    260:                } else {
                    261:                        // _anpi_{2,4} のマクロは用意されてるけど、これと同じなので
                    262:                        reg.A[n] += bytes;
                    263:                        return reg.A[n] - bytes;
                    264:                }
                    265:                break;
                    266:         case 4:        // -(An)
1.1.1.3   root      267:                CYCLE3(cea_fpu_anpd);
1.1       root      268:                n = eanum(ir);
                    269:                save_reg_pd(n);
                    270:                if (bytes == 1) {
                    271:                        return internal_ea_anpd_1(n);
                    272:                } else {
                    273:                        // _anpd_{2,4} のマクロは用意されてるけど、これと同じなので
                    274:                        reg.A[n] -= bytes;
                    275:                        return reg.A[n];
                    276:                }
                    277:                break;
                    278:         case 5:        // d16(An)
                    279:                return cea_andi(eanum(ir));
                    280:         case 6:        // (An,IX)
                    281:                return cea_anix(eanum(ir));
                    282:         case 7:
                    283:                switch (eanum(ir)) {
                    284:                 case 0:        // Abs.W
                    285:                        return cea_absw();
                    286:                 case 1:        // Abs.L
                    287:                        return cea_absl();
                    288:                 case 2:        // d16(PC)
                    289:                        return cea_pcdi();
                    290:                 case 3:        // (PC,IX)
                    291:                        return cea_pcix();
                    292:                 case 4:        // #imm
                    293:                        break;
                    294:                 default:
                    295:                        break;
                    296:                }
                    297:                break;
                    298:        }
                    299:        // 不当命令
                    300:        throw M68K::EXCEP_ILLEGAL;
                    301: }
                    302: 
1.1.1.2   root      303: // こっちは LC040 用。
                    304: //
                    305: // Dn、An、#imm に対しては 0 を返す (MC68040UM.pdf, p.A-6)。
                    306: // それ以外のすべてのアドレッシングモードで反応するため、命令ごとに
                    307: // 対応していないアドレッシングモードは事前に弾くこと。
                    308: // 不当パターンなら EXCEP_ILLEGAL をスローする。
                    309: uint32
                    310: MPU680x0Device::cea_fpulc(int bytes)
                    311: {
                    312:        uint mr = ir & 077;
                    313: 
                    314:        if (__predict_false(mr < 16 || mr == 074)) {
                    315:                return 0;
                    316:        } else {
                    317:                return cea_fpu(bytes);
                    318:        }
                    319: }
                    320: 
1.1       root      321: // メモリから 64ビット値を読み込む
                    322: void
                    323: MPU680x0Device::read_8(uint32 addr, uint32 *data)
                    324: {
                    325:        data[0] = read_4(addr);
                    326:        data[1] = read_4(addr + 4);
                    327: }
                    328: 
                    329: // メモリから 96ビット値を読み込む
                    330: void
                    331: MPU680x0Device::read_12(uint32 addr, uint32 *data)
                    332: {
                    333:        data[0] = read_4(addr);
                    334:        data[1] = read_4(addr + 4);
                    335:        data[2] = read_4(addr + 8);
                    336: }
                    337: 
                    338: // 64ビット値をメモリに書き込む
                    339: void
                    340: MPU680x0Device::write_8(uint32 addr, const uint32 *data)
                    341: {
                    342:        write_4(addr,     data[0]);
                    343:        write_4(addr + 4, data[1]);
                    344: }
                    345: 
                    346: // 96ビット値をメモリに書き込む
                    347: void
                    348: MPU680x0Device::write_12(uint32 addr, const uint32 *data)
                    349: {
                    350:        write_4(addr,     data[0]);
                    351:        write_4(addr + 4, data[1]);
                    352:        write_4(addr + 8, data[2]);
                    353: }
                    354: 
1.1.1.2   root      355: // FPU 不当命令 (1ワード目で確定)
                    356: void
                    357: MPU680x0Device::fpu_op_illg()
                    358: {
                    359:        putlog(1, "FPU illegal instruction %04X", ir);
                    360:        Exception(M68K::EXCEP_FLINE);
                    361: }
                    362: 
                    363: // FPU 不当命令 (2ワード目で確定)
                    364: void
                    365: MPU680x0Device::fpu_op_illg2()
                    366: {
                    367:        putlog(1, "FPU illegal instruction %04X %04X", ir, ir2);
                    368:        Exception(M68K::EXCEP_FLINE);
                    369: }
                    370: 
                    371: // R/M=0 (レジスタ-レジスタ演算)、opclass=%000
                    372: void
                    373: MPU680x0Device::fpu_op_fgen_reg()
                    374: {
                    375:        uint srcnum = (ir2 >> 10) & 7;
                    376: 
                    377:        fgen(&RegFP(srcnum), SIZE_X);
                    378: }
                    379: 
                    380: // R/M=1 (メモリ-レジスタ演算)、opclass=%010
                    381: void
                    382: MPU680x0Device::fpu_op_fgen_mem()
1.1       root      383: {
                    384:        uint mr = ir & 0x3f;
1.1.1.2   root      385:        uint size_id = (ir2 >> 10) & 7;
                    386:        uint32 ea = 0;
                    387:        uint32 data[3];
                    388: 
                    389:        // source specifier はオペランドサイズ
                    390:        if (size_id == 7) {
                    391:                // こんなところに FMOVECR
                    392:                fpu_op_fmovecr();
                    393:                return;
                    394:        }
                    395: 
                    396:        if ((mr >> 3) == 1) {   // An
                    397:                fpu_op_illg2();
                    398:                return;
                    399:        }
                    400: 
                    401:        uint bytes;
                    402:        switch (size_id) {
                    403:         case SIZE_B:
                    404:                bytes = 1;
                    405:                break;
                    406:         case SIZE_W:
                    407:                bytes = 2;
                    408:                break;
                    409:         case SIZE_L:
                    410:         case SIZE_S:
                    411:                bytes = 4;
                    412:                break;
                    413:         case SIZE_D:
                    414:                bytes = 8;
                    415:                break;
                    416:         case SIZE_X:
                    417:         case SIZE_P:
                    418:                bytes = 12;
                    419:                break;
                    420:         default:
                    421:                __unreachable();
                    422:        }
                    423: 
                    424:        if (__predict_false(GetFPUType().Is4060LC())) {
                    425:                ea = cea_fpulc(bytes);
                    426:                ExceptionFPLC(ea);
                    427:                return;
                    428:        }
1.1       root      429: 
                    430:        // 68881 本(p6-13) にはクロック数はこう書いてあるので
                    431:        // Inst | src=FPn       | memory source or dst operand format
                    432:        //      |                       | Int   Sgl             Dbl             Ext             Pakced
                    433:        // ---- +----------     +------ ------- ------- ------- -------
                    434:        // FABS | 35            | 62    54              60              58              872
                    435:        //            (差分)  +27     +19             +25             +23             +837
                    436:        // FADD | 51            | 80    72              78              76              888
                    437:        //            (差分)  +29     +21             +27             +25             +837
                    438:        //
                    439:        // FABS.X FPn,FPm は 35 としてこれは fgen() 内で加算。
                    440:        // FABS.L <ea>,FPm は 62 クロックなので、ここでは差分の 27 を加算。
                    441:        // FABS.L Dn,FPm  の場合 src がレジスタなので 62 から 5 引く。
                    442:        // FABS.P <ea>,FPm は 872 クロックなので、ここでは差分の  837 を加算。
                    443:        //
                    444:        // XXX 多くの命令が FABS と同じだけの差分だが、
                    445:        // FADD などいくつかは .P 以外に +2 クロックの追加があるようだ。
                    446:        // どうしたもんか。
                    447: 
                    448:        if (mr < 8) {   // Dn
1.1.1.2   root      449:                switch (bytes) {
                    450:                 case 1:
1.1       root      451:                        data[0] = (int32)(int8)reg.D[mr];
                    452:                        break;
1.1.1.2   root      453:                 case 2:
1.1       root      454:                        data[0] = (int32)(int16)reg.D[mr];
                    455:                        break;
1.1.1.2   root      456:                 case 4:
1.1       root      457:                        data[0] = reg.D[mr];
                    458:                        break;
                    459:                 default:
1.1.1.2   root      460:                        fpu_op_illg2();
                    461:                        return;
1.1       root      462:                }
1.1.1.2   root      463:                // 参照されない EA がどうなるか分からないが、LC040 からの類推。
                    464:                fpu40.ea = 0;
1.1       root      465: 
                    466:                // ソースが Dn の場合は 5クロック減
1.1.1.3   root      467:                CYCLE3(fpu_src_dn);
1.1.1.2   root      468:        } else if (mr == 074) {         // #imm
                    469:                switch (bytes) {
                    470:                 case 1:
1.1       root      471:                        data[0] = fetch_2() & 0xff;
                    472:                        break;
1.1.1.2   root      473:                 case 2:
1.1       root      474:                        data[0] = fetch_2();
                    475:                        break;
1.1.1.2   root      476:                 case 4:
1.1       root      477:                        data[0] = fetch_4();
                    478:                        break;
1.1.1.2   root      479:                 case 8:
1.1       root      480:                        data[0] = fetch_4();
                    481:                        data[1] = fetch_4();
                    482:                        break;
1.1.1.2   root      483:                 case 12:
1.1       root      484:                        data[0] = fetch_4();
                    485:                        data[1] = fetch_4();
                    486:                        data[2] = fetch_4();
                    487:                        break;
                    488:                 default:
1.1.1.2   root      489:                        __unreachable();
1.1       root      490:                }
1.1.1.2   root      491:                // 参照されない EA がどうなるか分からないが、LC040 からの類推。
                    492:                fpu40.ea = 0;
1.1       root      493:        } else {
1.1.1.2   root      494:                // それ以外は EA を求めてからメモリから読み込む。
                    495:                ea = cea_fpu(bytes);
                    496: 
                    497:                switch (bytes) {
                    498:                 case 1:
1.1       root      499:                        data[0] = (int32)(int8)read_1(ea);
                    500:                        break;
1.1.1.2   root      501:                 case 2:
1.1       root      502:                        data[0] = (int32)(int16)read_2(ea);
                    503:                        break;
1.1.1.2   root      504:                 case 4:
1.1       root      505:                        data[0] = read_4(ea);
                    506:                        break;
1.1.1.2   root      507:                 case 8:
1.1       root      508:                        read_8(ea, data);
                    509:                        break;
1.1.1.2   root      510:                 case 12:
1.1       root      511:                        read_12(ea, data);
                    512:                        break;
                    513:                 default:
1.1.1.2   root      514:                        __unreachable();
1.1       root      515:                }
                    516:                fpu40.ea = ea;
                    517:        }
                    518: 
                    519:        fgen(data, size_id);
                    520: }
                    521: 
                    522: // 一般算術演算。
                    523: // srcdata, srcsize_id がソースの生データとサイズ識別子。
                    524: // デスティネーション(FPn) は ir2 から求まる。
                    525: void
                    526: MPU680x0Device::fgen(const uint32 *srcdata, uint srcsize_id)
                    527: {
                    528:        uint opmode = ir2 & 0x3f;
                    529:        uint dstnum = (ir2 >> 7) & 7;
                    530:        bool discard_result = false;
                    531:        struct fpn *res = NULL; // shutup gcc
                    532: 
                    533:        // 機種別の前処理。
                    534:        if (GetFPUType().Is4060FPU()) {
                    535:                // 未実装命令と未実装データ型の検出など。
                    536:                if (fgen040pre(opmode, dstnum, srcdata, srcsize_id) == false) {
                    537:                        return;
                    538:                }
                    539:        } else {
                    540:                // fe_f1, fe_f2 にロードするだけ。
                    541:                fgen881pre(dstnum, srcdata, srcsize_id);
                    542:        }
                    543: 
                    544:        switch (opmode) {
                    545:         case 0x00:             // FMOVE
                    546:         fmove:
1.1.1.3   root      547:                CYCLE3(fmove);
1.1       root      548:                res = &fe.fe_f2;
                    549:                fpu_round_prec(&fe, res);
                    550:                break;
                    551:         case 0x01:             // FINT
                    552:                CYCLE(55);
                    553:                res = fpu_int(&fe);
                    554:                break;
                    555:         case 0x02:             // FSINH
                    556:                CYCLE(687);
                    557:                res = fpu_sinh(&fe);
                    558:                fpu_round_prec(&fe, res);
                    559:                break;
                    560:         case 0x03:             // FINTRZ
                    561:                CYCLE(55);
                    562:                res = fpu_intrz(&fe);
                    563:                break;
                    564:         case 0x04:             // FSQRT
                    565:         fsqrt:
1.1.1.3   root      566:                CYCLE3(fsqrt);
1.1       root      567:                res = fpu_sqrt(&fe);
                    568:                fpu_round_prec(&fe, res);
                    569:                break;
                    570:         case 0x06:             // FLOGNP1
                    571:                CYCLE(571);
                    572:                res = fpu_lognp1(&fe);
                    573:                fpu_round_prec(&fe, res);
                    574:                break;
                    575:         case 0x08:             // FETOXM1
                    576:                CYCLE(545);
                    577:                res = fpu_etoxm1(&fe);
                    578:                fpu_round_prec(&fe, res);
                    579:                break;
                    580:         case 0x09:             // FTANH
                    581:                CYCLE(661);
                    582:                res = fpu_tanh(&fe);
                    583:                fpu_round_prec(&fe, res);
                    584:                break;
                    585:         case 0x0a:             // FATAN
                    586:                CYCLE(403);
                    587:                res = fpu_atan(&fe);
                    588:                fpu_round_prec(&fe, res);
                    589:                break;
                    590:         case 0x0c:             // FASIN
                    591:                CYCLE(581);
                    592:                res = fpu_asin(&fe);
                    593:                fpu_round_prec(&fe, res);
                    594:                break;
                    595:         case 0x0d:             // FATANH
                    596:                CYCLE(693);
                    597:                res = fpu_atanh(&fe);
                    598:                fpu_round_prec(&fe, res);
                    599:                break;
                    600:         case 0x0e:             // FSIN
                    601:                CYCLE(391);
                    602:                res = fpu_sin(&fe);
                    603:                fpu_round_prec(&fe, res);
                    604:                break;
                    605:         case 0x0f:             // FTAN
                    606:                CYCLE(473);
                    607:                res = fpu_tan(&fe);
                    608:                fpu_round_prec(&fe, res);
                    609:                break;
                    610:         case 0x10:             // FETOX
                    611:                CYCLE(497);
                    612:                res = fpu_etox(&fe);
                    613:                fpu_round_prec(&fe, res);
                    614:                break;
                    615:         case 0x11:             // FTWOTOX
                    616:                CYCLE(567);
                    617:                res = fpu_twotox(&fe);
                    618:                fpu_round_prec(&fe, res);
                    619:                break;
                    620:         case 0x12:             // FTENTOX
                    621:                CYCLE(567);
                    622:                res = fpu_tentox(&fe);
                    623:                fpu_round_prec(&fe, res);
                    624:                break;
                    625:         case 0x14:             // FLOGN
                    626:                CYCLE(525);
                    627:                res = fpu_logn(&fe);
                    628:                fpu_round_prec(&fe, res);
                    629:                break;
                    630:         case 0x15:             // FLOG10
                    631:                CYCLE(581);
                    632:                res = fpu_log10(&fe);
                    633:                fpu_round_prec(&fe, res);
                    634:                break;
                    635:         case 0x16:             // FLOG2
                    636:                CYCLE(581);
                    637:                res = fpu_log2(&fe);
                    638:                fpu_round_prec(&fe, res);
                    639:                break;
                    640:         case 0x18:             // FABS
                    641:         fabs:
1.1.1.3   root      642:                CYCLE3(fabs);
1.1       root      643:                fe.fe_f2.fp_sign = 0;
                    644:                res = &fe.fe_f2;
                    645:                fpu_round_prec(&fe, res);
                    646:                break;
                    647:         case 0x19:             // FCOSH
                    648:                CYCLE(607);
                    649:                res = fpu_cosh(&fe);
                    650:                fpu_round_prec(&fe, res);
                    651:                break;
                    652:         case 0x1a:             // FNEG
                    653:         fneg:
1.1.1.3   root      654:                CYCLE3(fneg);
1.1       root      655:                res = &fe.fe_f2;
                    656:                if (!ISNAN(res)) {
                    657:                        res->fp_sign = !res->fp_sign;
                    658:                        fpu_round_prec(&fe, res);
                    659:                }
                    660:                break;
                    661:         case 0x1c:             // FACOS
                    662:                CYCLE(625);
                    663:                res = fpu_acos(&fe);
                    664:                fpu_round_prec(&fe, res);
                    665:                break;
                    666:         case 0x1d:             // FCOS
                    667:                CYCLE(391);
                    668:                res = fpu_cos(&fe);
                    669:                fpu_round_prec(&fe, res);
                    670:                break;
                    671:         case 0x1e:             // FGETEXP
                    672:                CYCLE(45);
                    673:                res = fpu_getexp(&fe);
                    674:                fpu_round_prec(&fe, res);
                    675:                break;
                    676:         case 0x1f:             // FGETMAN
                    677:                CYCLE(31);
                    678:                res = fpu_getman(&fe);
                    679:                fpu_round_prec(&fe, res);
                    680:                break;
                    681:         case 0x20:             // FDIV
                    682:         fdiv:
1.1.1.3   root      683:                CYCLE3(fdiv);
1.1       root      684:                res = fpu_div(&fe);
                    685:                fpu_round_prec(&fe, res);
                    686:                break;
                    687:         case 0x21:             // FMOD
                    688:                CYCLE(67);
                    689:                res = fpu_mod(&fe);
                    690:                fpu_round_prec(&fe, res);
                    691:                break;
                    692:         case 0x22:             // FADD
                    693:         fadd:
1.1.1.3   root      694:                CYCLE3(fadd);
1.1       root      695:                res = fpu_add(&fe);
                    696:                fpu_round_prec(&fe, res);
                    697:                break;
                    698:         case 0x23:             // FMUL
                    699:         fmul:
1.1.1.3   root      700:                CYCLE3(fmul);
1.1       root      701:                res = fpu_mul(&fe);
                    702:                fpu_round_prec(&fe, res);
                    703:                break;
                    704:         case 0x24:             // FSGLDIV
1.1.1.3   root      705:                CYCLE3(fsgldiv);
1.1       root      706:                res = fpu_sgldiv(&fe);
                    707:                break;
                    708:         case 0x25:             // FREM
                    709:                CYCLE(67);
                    710:                res = fpu_rem(&fe);
                    711:                fpu_round_prec(&fe, res);
                    712:                break;
                    713:         case 0x26:             // FSCALE
                    714:                // こいつだけ形式が違う。
                    715:                // 結果は dst に直接格納済み、FPSR も演算済み。
                    716:                CYCLE(41);
                    717:                fpu_emul_fscale(&fe, ir2);
                    718:                return;
                    719:         case 0x27:             // FSGLMUL
1.1.1.3   root      720:                CYCLE3(fsglmul);
1.1       root      721:                res = fpu_sglmul(&fe);
                    722:                break;
                    723:         case 0x28:             // FSUB
                    724:         fsub:
1.1.1.3   root      725:                CYCLE3(fsub);
1.1       root      726:                res = fpu_sub(&fe);
                    727:                fpu_round_prec(&fe, res);
                    728:                break;
                    729:         case 0x30:
                    730:         case 0x31:
                    731:         case 0x32:
                    732:         case 0x33:
                    733:         case 0x34:
                    734:         case 0x35:
                    735:         case 0x36:
                    736:         case 0x37:             // FSINCOS
                    737:                CYCLE(451);
                    738:                res = fpu_sincos(&fe, opmode & 7);
                    739:                fpu_round_prec(&fe, res);
                    740:                break;
                    741:         case 0x38:             // FCMP
1.1.1.3   root      742:                CYCLE3(fcmp);
1.1       root      743:                res = fpu_cmp(&fe);
                    744:                discard_result = 1;
                    745:                break;
                    746:         case 0x3a:             // FTST
1.1.1.3   root      747:                CYCLE3(ftst);
1.1       root      748:                res = &fe.fe_f2;
                    749:                discard_result = 1;
                    750:                break;
                    751: 
                    752: #define ONLY_40        do {    \
                    753:        if (GetFPUType().Is40FPU() == false) {  \
                    754:                goto illegal;   \
                    755:        }       \
                    756: } while (0)
                    757: // fe の精度だけ変える。
                    758: // fe_fpcr は RegFPCR (レジスタ) のほうには伝搬しないし、
                    759: // 次の命令の冒頭でまた RegFPCR から上書きされるので、
                    760: // 書き換えっぱなしでよい。
                    761: #define ROUND_FS       do {    \
                    762:        fe.fe_fpcr &= ~FPCR_PREC;       \
                    763:        fe.fe_fpcr |= FPCR_SNGL;        \
                    764: } while (0)
                    765: #define ROUND_FD       do {    \
                    766:        fe.fe_fpcr &= ~FPCR_PREC;       \
                    767:        fe.fe_fpcr |= FPCR_DBL; \
                    768: } while (0)
                    769: 
                    770:         case 0x40:     ONLY_40; ROUND_FS; goto fmove;  // FSMOVE
                    771:         case 0x44:     ONLY_40; ROUND_FD; goto fmove;  // FDMOVE
                    772:         case 0x41:     ONLY_40; ROUND_FS; goto fsqrt;  // FSSQRT
                    773:         case 0x45:     ONLY_40; ROUND_FD; goto fsqrt;  // FDSQRT
                    774:         case 0x58:     ONLY_40; ROUND_FS; goto fabs;   // FSABS
                    775:         case 0x5c:     ONLY_40; ROUND_FD; goto fabs;   // FDABS
                    776:         case 0x5a:     ONLY_40; ROUND_FS; goto fneg;   // FSNEG
                    777:         case 0x5e:     ONLY_40; ROUND_FD; goto fneg;   // FDNEG
                    778:         case 0x60:     ONLY_40; ROUND_FS; goto fdiv;   // FSDIV
                    779:         case 0x64:     ONLY_40; ROUND_FD; goto fdiv;   // FDDIV
                    780:         case 0x62:     ONLY_40; ROUND_FS; goto fadd;   // FSADD
                    781:         case 0x66:     ONLY_40; ROUND_FD; goto fadd;   // FDADD
                    782:         case 0x63:     ONLY_40; ROUND_FS; goto fmul;   // FSMUL
                    783:         case 0x67:     ONLY_40; ROUND_FD; goto fmul;   // FDMUL
                    784:         case 0x68:     ONLY_40; ROUND_FS; goto fsub;   // FSSUB
                    785:         case 0x6c:     ONLY_40; ROUND_FD; goto fsub;   // FDSUB
                    786: 
                    787:         illegal:
                    788:         default:
                    789:                // 不当命令
                    790:                fpu_op_illg2();
                    791:                return;
                    792:        }
                    793: 
                    794:        assert(res);
                    795:        if (!discard_result) {
                    796:                fpu_implode(&fe, res, FTYPE_EXT, &RegFP(dstnum));
                    797:        }
                    798:        fpu_upd_fpsr(&fe, res);
                    799:        fpu_upd_excp(&fe);
                    800: }
                    801: 
                    802: // fgen() の 68881 での前処理。
                    803: // src, dst を fe_f2, fe_f1 にそれぞれロードするだけ。
                    804: void
                    805: MPU680x0Device::fgen881pre(uint dstnum, const uint32 *srcdata, uint srcsize_id)
                    806: {
                    807:        switch (srcsize_id) {
                    808:         case SIZE_B:
                    809:         case SIZE_W:
                    810:         case SIZE_L:
                    811:                CYCLE(+27);
                    812:                fpu_explode(&fe, &fe.fe_f2, FTYPE_LNG, srcdata);
                    813:                break;
                    814:         case SIZE_S:
                    815:                CYCLE(+19);
                    816:                fpu_explode(&fe, &fe.fe_f2, FTYPE_SNG, srcdata);
                    817:                break;
                    818:         case SIZE_D:
                    819:                CYCLE(+25);
                    820:                fpu_explode(&fe, &fe.fe_f2, FTYPE_DBL, srcdata);
                    821:                break;
                    822:         case SIZE_X:
                    823:                CYCLE(+23);
                    824:                fpu_explode(&fe, &fe.fe_f2, FTYPE_EXT, srcdata);
                    825:                break;
                    826:         case SIZE_P:
                    827:                CYCLE(+837);
                    828:                fpu_explode(&fe, &fe.fe_f2, FTYPE_BCD, srcdata);
                    829:                break;
                    830:         default:
                    831:                __unreachable();
                    832:        }
                    833:        fpu_explode(&fe, &fe.fe_f1, FTYPE_EXT, &RegFP(dstnum));
                    834: }
                    835: 
                    836: // fgen() の 68040 での前処理。
                    837: // 未実装命令のチェックと該当すればその例外処理、
                    838: // 未実装データ型のチェックと該当すればその例外処理を行う。
                    839: // 例外処理を行った場合は false を返す。
                    840: bool
                    841: MPU680x0Device::fgen040pre(uint opmode, uint dstnum,
                    842:        const uint32 *srcdata, uint srcsize_id)
                    843: {
                    844:        // 未実装命令か調べる。
                    845:        bool unimpl = false;
                    846:        switch (opmode) {
                    847:         case 0x01:             // FINT
                    848:         case 0x02:             // FSINH
                    849:         case 0x03:             // FINTRZ
                    850:         case 0x06:             // FLOGNP1
                    851:         case 0x08:             // FETOXM1
                    852:         case 0x09:             // FTANH
                    853:         case 0x0a:             // FATAN
                    854:         case 0x0c:             // FASIN
                    855:         case 0x0d:             // FATANH
                    856:         case 0x0e:             // FSIN
                    857:         case 0x0f:             // FTAN
                    858:         case 0x10:             // FETOX
                    859:         case 0x11:             // FTWOTOX
                    860:         case 0x12:             // FTENTOX
                    861:         case 0x14:             // FLOGN
                    862:         case 0x15:             // FLOG10
                    863:         case 0x16:             // FLOG2
                    864:         case 0x19:             // FCOSH
                    865:         case 0x1c:             // FACOS
                    866:         case 0x1d:             // FCOS
                    867:         case 0x1e:             // FGETEXP
                    868:         case 0x1f:             // FGETMAN
                    869:         case 0x21:             // FMOD
                    870:         case 0x25:             // FREM
                    871:         case 0x26:             // FSCALE
                    872:         case 0x30:             // FSINCOS
                    873:         case 0x31:             // FSINCOS
                    874:         case 0x32:             // FSINCOS
                    875:         case 0x33:             // FSINCOS
                    876:         case 0x34:             // FSINCOS
                    877:         case 0x35:             // FSINCOS
                    878:         case 0x36:             // FSINCOS
                    879:         case 0x37:             // FSINCOS
                    880:                unimpl = true;
                    881:                break;
                    882:         default:
                    883:                break;
                    884:        }
                    885: 
                    886:        // ソースがサポートしている型なら拡張精度に変換して fe_f2 にセットし、
                    887:        // stag は NONE のままか NORMAL or ZERO をセット。
                    888:        // 未サポート型なら所定の etemp を作成して stag は DENORMAL か UNNORMAL。
                    889:        //
                    890:        //                      Int                     .S/.D           .X                      .P
                    891:        // Normal       fe_f2,NORM      fe_f2,NONE      fe_f2,NONE      etemp,UNNO
                    892:        // Zero         fe_f2,ZERO      fe_f2,NONE      fe_f2,NONE      etemp,UNNO
                    893:        // Inf          -                       fe_f2,NONE      fe_f2,NONE      etemp,UNNO
                    894:        // NAN          -                       fe_f2,NONE      fe_f2,NONE      etemp,UNNO
                    895:        // Denorm       -                       etemp,DENO      etemp,UNNO      etemp,UNNO
                    896:        // Unnorm       -                       -                       etemp,UNNO      etemp,UNNO
                    897: 
1.1.1.3   root      898:        // サイクル数は 68040UM.pdf p10-30 の表から適当に逆算。
                    899: 
1.1       root      900:        int32 stag = FPU40::TAG_NONE;
                    901:        switch (srcsize_id) {
                    902:         case SIZE_B:
                    903:         case SIZE_W:
                    904:         case SIZE_L:
1.1.1.3   root      905:                CYCLE(+0);
1.1       root      906:                if (srcdata[0] == 0) {
                    907:                        stag = FPU40::TAG_ZERO;
                    908:                } else {
                    909:                        stag = FPU40::TAG_NORMAL;
                    910:                }
                    911:                fpu_explode(&fe, &fe.fe_f2, FTYPE_LNG, srcdata);
                    912:                break;
                    913:         case SIZE_S:
1.1.1.3   root      914:                CYCLE(+0);
1.1       root      915:                if (is_denormal_s(srcdata[0])) {
                    916:                        // 68040UM.pdf, p9-24. Figure 9-9 (a)
                    917:                        uint32 s = srcdata[0] & 0x8000'0000;
                    918:                        uint32 m = srcdata[0] & 0x007f'ffff;
                    919:                        fpu40.etemp[0] = s;
                    920:                        fpu40.etemp[1] = m << 8;
                    921:                        fpu40.etemp[2] = 0;
                    922:                        stag = FPU40::TAG_DENORMAL_S;
                    923:                        break;
                    924:                }
                    925:                fpu_explode(&fe, &fe.fe_f2, FTYPE_SNG, srcdata);
                    926:                break;
                    927:         case SIZE_D:
1.1.1.3   root      928:                CYCLE(+0);
1.1       root      929:                if (is_denormal_d(srcdata)) {
                    930:                        // 68040UM.pdf, p9-24. Figure 9-9 (b)
                    931:                        uint32 s = srcdata[0] & 0x8000'0000;
                    932:                        uint64 m = ((uint64)(srcdata[0] & 0x000f'ffff) << 32) | srcdata[1];
                    933:                        m <<= 11;
                    934:                        fpu40.etemp[0] = s;
                    935:                        fpu40.etemp[1] = m >> 32;
                    936:                        fpu40.etemp[2] = m & 0xffffffff;
                    937:                        stag = FPU40::TAG_DENORMAL_D;
                    938:                        break;
                    939:                }
                    940:                fpu_explode(&fe, &fe.fe_f2, FTYPE_DBL, srcdata);
                    941:                break;
                    942:         case SIZE_X:
1.1.1.3   root      943:                CYCLE(+1);
1.1       root      944:                if (is_denormal_x(srcdata)) {
                    945:                        memcpy(fpu40.etemp, srcdata, 12);
                    946:                        stag = FPU40::TAG_DENORMAL_X;
                    947:                        break;
                    948:                } else if (is_unnormal_x(srcdata)) {
                    949:                        memcpy(fpu40.etemp, srcdata, 12);
                    950:                        stag = FPU40::TAG_UNNORMAL_X;
                    951:                        break;
                    952:                }
                    953:                fpu_explode(&fe, &fe.fe_f2, FTYPE_EXT, srcdata);
                    954:                break;
                    955:         case SIZE_P:
                    956:                // 上位32ビットを FPTM[31-00] に、
                    957:                // 下位64ビットを  ETM[31-00] に置く。(68040UM.pdf, pp.9-42〜43)
                    958:                fpu40.fptemp[2] = srcdata[0];
                    959:                fpu40.etemp[1]  = srcdata[1];
                    960:                fpu40.etemp[2]  = srcdata[2];
                    961:                // Packed の時 stag は undefined と書いてある。
                    962:                // ここではこの後の例外判定用および表示用として使う。
                    963:                stag = FPU40::TAG_PACKED;
                    964:                break;
                    965:         default:
                    966:                __unreachable();
                    967:        }
                    968: 
                    969:        // デスティネーション(レジスタ) が未サポートデータ型になるのは
                    970:        // 非正規化数の時だけのはず。
                    971:        int32 dtag = FPU40::TAG_NONE;
                    972:        if (is_denormal_x(&RegFP(dstnum))) {
                    973:                dtag = FPU40::TAG_DENORMAL_X;
                    974:        }
                    975:        fpu_explode(&fe, &fe.fe_f1, FTYPE_EXT, &RegFP(dstnum));
                    976:        if (dtag == FPU40::TAG_NONE) {
                    977:                dtag = fpu_gettag(&fe.fe_f1);
                    978:        }
                    979: 
                    980:        // 例外を起こす必要があるか。
                    981:        if (unimpl ||
                    982:                stag >= FPU40::TAG_UNNORMAL ||
                    983:                dtag >= FPU40::TAG_UNNORMAL)
                    984:        {
                    985:                // stag がまだならここで fpn から決まる。
                    986:                if (stag == FPU40::TAG_NONE) {
                    987:                        stag = fpu_gettag(&fe.fe_f2);
                    988:                }
                    989:                // stag が UNNORMAL, DENORMAL なら etemp はセット済み。
                    990:                if (stag < FPU40::TAG_UNNORMAL) {
                    991:                        fpu_implode(&fe, &fe.fe_f2, FTYPE_EXT, fpu40.etemp);
                    992:                }
                    993:                // Packed なら E1 を立てる、
                    994:                // また FPTEMP にはソースを展開済みなので dst を書き込まない。
                    995:                // XXX 68040UM.pdf p.9-44 Table 9-16 Unimplemented Instruction には
                    996:                // E1 は always 1 とあるが、p.9-42 の E1 の説明のほうが正しそう。
                    997:                if (srcsize_id == SIZE_P) {
                    998:                        fpu40.eflag = FPU40::E1;
                    999:                } else {
                   1000:                        fpu40.eflag = 0;
                   1001:                        memcpy(&fpu40.fptemp, &RegFP(dstnum), 12);
                   1002:                }
                   1003:                fpu40.stag = stag;
                   1004:                fpu40.dtag = dtag;
                   1005:                if (unimpl) {
                   1006:                        ExceptionFP(M68K::EXCEP_FP_UNIMPL);
                   1007:                } else {
                   1008:                        ExceptionFP(M68K::EXCEP_FP_UNSUPP);
                   1009:                }
                   1010:                return false;
                   1011:        }
                   1012: 
                   1013:        // ハードウェア処理可能。
                   1014: 
                   1015:        // 68040 では条件命令以外 (たぶん実質クラス0命令) を実行すると
                   1016:        // NULL -> IDLE 状態になる。68040UM.pdf, p9-39
                   1017:        fpu_state = FPU_STATE_IDLE;
                   1018: 
                   1019:        return true;
                   1020: }
                   1021: 
                   1022: // FMOVECR
                   1023: void
                   1024: MPU680x0Device::fpu_op_fmovecr()
                   1025: {
1.1.1.2   root     1026:        if (__predict_false(GetFPUType().Is6888x() == false)) {
                   1027:                if (GetFPUType().Is4060LC()) {
                   1028:                        ExceptionFPLC(0);
                   1029:                } else {
                   1030:                        ExceptionFP(M68K::EXCEP_FP_UNIMPL);
                   1031:                }
1.1       root     1032:                return;
                   1033:        }
                   1034: 
                   1035:        CYCLE(29);
                   1036: 
                   1037:        uint offset = (ir2 & 0x7f);
                   1038:        uint dstnum = (ir2 >> 7) & 7;
                   1039: 
                   1040:        fpu_const(&fe.fe_f3, offset);
                   1041:        fpu_implode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(dstnum));
                   1042:        fpu_upd_fpsr(&fe, &fe.fe_f3);
                   1043:        fpu_upd_excp(&fe);
                   1044: }
                   1045: 
                   1046: // FMOVE FPn,<ea>
                   1047: void
                   1048: MPU680x0Device::fpu_op_fmove_to_mem()
                   1049: {
                   1050:        // サイズごとに分岐
                   1051:        uint size = (ir2 >> 10) & 7;
                   1052:        switch (size) {
                   1053:         case SIZE_B:
                   1054:                fpu_op_fmove_b_mem();
                   1055:                break;
                   1056:         case SIZE_W:
                   1057:                fpu_op_fmove_w_mem();
                   1058:                break;
                   1059:         case SIZE_L:
                   1060:                fpu_op_fmove_l_mem();
                   1061:                break;
                   1062:         case SIZE_S:
                   1063:                fpu_op_fmove_s_mem();
                   1064:                break;
                   1065:         case SIZE_D:
                   1066:                fpu_op_fmove_d_mem();
                   1067:                break;
                   1068:         case SIZE_X:
                   1069:                fpu_op_fmove_x_mem();
                   1070:                break;
                   1071:         case SIZE_P:
                   1072:         case 7:
                   1073:                fpu_op_fmove_p_mem();
                   1074:                break;
                   1075:        }
                   1076: }
                   1077: 
                   1078: // FMOVE.B FPn,<ea>
                   1079: // cf. 68000PRM.pdf p378 (5-76)
                   1080: void
                   1081: MPU680x0Device::fpu_op_fmove_b_mem()
                   1082: {
                   1083:        uint mr = ir & 0x3f;
                   1084:        uint srcnum = (ir2 >> 7) & 7;
                   1085:        uint32 ea;
                   1086:        uint32 data;
                   1087: 
1.1.1.2   root     1088:        if (__predict_false((mr >> 3) == 1 || mr >= 072)) {     // An, PC, #imm
                   1089:                fpu_op_illg2();
                   1090:                return;
                   1091:        }
                   1092:        if (__predict_false(GetFPUType().Is4060LC())) {
                   1093:                ea = cea_fpulc(1);
                   1094:                ExceptionFPLC(ea);
                   1095:                return;
                   1096:        }
                   1097: 
1.1       root     1098:        fpu_explode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(srcnum));
                   1099:        fpu_implode(&fe, &fe.fe_f3, FTYPE_LNG, &data);
                   1100:        // 入力値は long か、long で表現できなければ 0x80000000 が返ってくるが、
                   1101:        // ここはバイトへの変換なので表現できなければ 0x80 にする。
                   1102:        if ((int32)data < INT8_MIN || (int32)data > INT8_MAX) {
                   1103:                data = 0x80;
                   1104:                RegFPSR |= FPSR_OPERR | FPSR_AIOP;
                   1105:        }
                   1106: 
                   1107:        if (mr < 8) {   // Dn
1.1.1.3   root     1108:                CYCLE3(fmove_i_fp_dn);
1.1       root     1109:                reg.D[mr] &= 0xffffff00;
                   1110:                reg.D[mr] |= (uint8)data;
                   1111:        } else {
1.1.1.3   root     1112:                CYCLE3(fmove_i_fp_mem);
1.1       root     1113:                ea = cea_fpu(1);
                   1114:                write_1(ea, (uint8)data);
                   1115:        }
                   1116: }
                   1117: 
                   1118: // FMOVE.W FPn,<ea>
                   1119: // cf. 68000PRM.pdf p378 (5-76)
                   1120: void
                   1121: MPU680x0Device::fpu_op_fmove_w_mem()
                   1122: {
                   1123:        uint mr = ir & 0x3f;
                   1124:        uint srcnum = (ir2 >> 7) & 7;
                   1125:        uint32 ea;
                   1126:        uint32 data;
                   1127: 
1.1.1.2   root     1128:        if (__predict_false((mr >> 3) == 1 || mr >= 072)) {     // An, PC, #imm
                   1129:                fpu_op_illg2();
                   1130:                return;
                   1131:        }
                   1132:        if (__predict_false(GetFPUType().Is4060LC())) {
                   1133:                ea = cea_fpulc(2);
                   1134:                ExceptionFPLC(ea);
                   1135:                return;
                   1136:        }
                   1137: 
1.1       root     1138:        fpu_explode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(srcnum));
                   1139:        fpu_implode(&fe, &fe.fe_f3, FTYPE_LNG, &data);
                   1140:        // 入力値は long か、long で表現できなければ 0x80000000 が返ってくるが、
                   1141:        // ここはワードへの変換なので表現できなければ 0x8000 にする。
                   1142:        if ((int32)data < INT16_MIN || (int32)data > INT16_MAX) {
                   1143:                data = 0x8000;
                   1144:                RegFPSR |= FPSR_OPERR | FPSR_AIOP;
                   1145:        }
                   1146: 
                   1147:        if (mr < 8) {   // Dn
1.1.1.3   root     1148:                CYCLE3(fmove_i_fp_dn);
1.1       root     1149:                reg.D[mr] &= 0xffff0000;
                   1150:                reg.D[mr] |= (uint16)data;
                   1151:        } else {
1.1.1.3   root     1152:                CYCLE3(fmove_i_fp_mem);
1.1       root     1153:                ea = cea_fpu(2);
                   1154:                write_2(ea, (uint16)data);
                   1155:        }
                   1156: }
                   1157: 
                   1158: // FMOVE.L FPn,<ea>
                   1159: // cf. 68000PRM.pdf p378 (5-76)
                   1160: void
                   1161: MPU680x0Device::fpu_op_fmove_l_mem()
                   1162: {
                   1163:        uint mr = ir & 0x3f;
                   1164:        uint srcnum = (ir2 >> 7) & 7;
                   1165:        uint32 ea;
                   1166:        uint32 data;
                   1167: 
1.1.1.2   root     1168:        if (__predict_false((mr >> 3) == 1 || mr >= 072)) {     // An, PC, #imm
                   1169:                fpu_op_illg2();
                   1170:                return;
                   1171:        }
                   1172:        if (__predict_false(GetFPUType().Is4060LC())) {
                   1173:                ea = cea_fpulc(4);
                   1174:                ExceptionFPLC(ea);
                   1175:                return;
                   1176:        }
                   1177: 
1.1       root     1178:        fpu_explode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(srcnum));
                   1179:        fpu_implode(&fe, &fe.fe_f3, FTYPE_LNG, &data);
                   1180:        // XXX オーバーフローチェック
                   1181: 
                   1182:        if (mr < 8) {   // Dn
1.1.1.3   root     1183:                CYCLE3(fmove_i_fp_dn);
1.1       root     1184:                reg.D[mr] = data;
                   1185:        } else {
1.1.1.3   root     1186:                CYCLE3(fmove_i_fp_mem);
1.1       root     1187:                ea = cea_fpu(4);
                   1188:                write_4(ea, data);
                   1189:        }
                   1190: }
                   1191: 
                   1192: // FMOVE.S FPn,<ea>
                   1193: // cf. 68000PRM.pdf p378 (5-76)
                   1194: void
                   1195: MPU680x0Device::fpu_op_fmove_s_mem()
                   1196: {
                   1197:        uint mr = ir & 0x3f;
                   1198:        uint srcnum = (ir2 >> 7) & 7;
                   1199:        uint32 ea;
                   1200:        uint32 data;
                   1201: 
1.1.1.2   root     1202:        if (__predict_false((mr >> 3) == 1 || mr >= 072)) {     // An, PC, #imm
                   1203:                fpu_op_illg2();
                   1204:                return;
                   1205:        }
                   1206:        if (__predict_false(GetFPUType().Is4060LC())) {
                   1207:                ea = cea_fpulc(4);
                   1208:                ExceptionFPLC(ea);
                   1209:                return;
                   1210:        }
                   1211: 
1.1       root     1212:        fpu_explode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(srcnum));
                   1213:        fpu_implode(&fe, &fe.fe_f3, FTYPE_SNG, &data);
                   1214: 
                   1215:        // 変換時に検出した UNFL, OVFL だけ外部レジスタにコピー。
                   1216:        fe.fe_fpframe->fpf_fpsr &= ~(FPSR_UNFL | FPSR_OVFL);
                   1217:        fe.fe_fpframe->fpf_fpsr |= fe.fe_fpsr & (FPSR_UNFL | FPSR_OVFL);
                   1218:        // アクルードバイトは更新。
                   1219:        fpu_upd_excp(&fe);
                   1220: 
                   1221:        if (mr < 8) {   // Dn
1.1.1.3   root     1222:                CYCLE3(fmove_s_fp_dn);
1.1       root     1223:                reg.D[mr] = data;
                   1224:        } else {
1.1.1.3   root     1225:                CYCLE3(fmove_s_fp_mem);
1.1       root     1226:                ea = cea_fpu(4);
                   1227:                write_4(ea, data);
                   1228:        }
                   1229: }
                   1230: 
                   1231: // FMOVE.D FPn,<ea>
                   1232: // cf. 68000PRM.pdf p378 (5-76)
                   1233: void
                   1234: MPU680x0Device::fpu_op_fmove_d_mem()
                   1235: {
1.1.1.2   root     1236:        uint mr = ir & 077;
1.1       root     1237:        uint srcnum = (ir2 >> 7) & 7;
                   1238:        uint32 ea;
                   1239:        uint32 data[2];
                   1240: 
1.1.1.2   root     1241:        if (__predict_false(mr <= 017 || mr >= 072)) {  // Dn, An, PC, #imm
                   1242:                fpu_op_illg2();
                   1243:                return;
                   1244:        }
                   1245:        if (__predict_false(GetFPUType().Is4060LC())) {
                   1246:                ea = cea_fpulc(8);
                   1247:                ExceptionFPLC(ea);
                   1248:                return;
                   1249:        }
                   1250: 
1.1.1.3   root     1251:        CYCLE3(fmove_d_fp_ea);
1.1.1.2   root     1252: 
1.1       root     1253:        fpu_explode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(srcnum));
                   1254:        fpu_implode(&fe, &fe.fe_f3, FTYPE_DBL, data);
                   1255: 
                   1256:        // 変換時に検出した UNFL, OVFL だけ外部レジスタにコピー。
                   1257:        fe.fe_fpframe->fpf_fpsr &= ~(FPSR_UNFL | FPSR_OVFL);
                   1258:        fe.fe_fpframe->fpf_fpsr |= fe.fe_fpsr & (FPSR_UNFL | FPSR_OVFL);
                   1259:        // アクルードバイトは更新。
                   1260:        fpu_upd_excp(&fe);
                   1261: 
                   1262:        ea = cea_fpu(8);
                   1263:        write_8(ea, data);
                   1264: }
                   1265: 
                   1266: // FMOVE.X FPn,<ea>
                   1267: // cf. 68000PRM.pdf p378 (5-76)
                   1268: void
                   1269: MPU680x0Device::fpu_op_fmove_x_mem()
                   1270: {
1.1.1.2   root     1271:        uint mr = ir & 077;
1.1       root     1272:        uint srcnum = (ir2 >> 7) & 7;
                   1273:        uint32 ea;
                   1274:        uint32 data[3];
                   1275: 
1.1.1.2   root     1276:        if (__predict_false(mr <= 017 || mr >= 072)) {  // Dn, An, PC, #imm
                   1277:                fpu_op_illg2();
                   1278:                return;
                   1279:        }
                   1280:        if (__predict_false(GetFPUType().Is4060LC())) {
                   1281:                ea = cea_fpulc(12);
                   1282:                ExceptionFPLC(ea);
                   1283:                return;
                   1284:        }
                   1285: 
1.1.1.3   root     1286:        CYCLE3(fmove_x_fp_ea);
1.1.1.2   root     1287: 
1.1       root     1288:        fpu_explode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(srcnum));
                   1289:        fpu_implode(&fe, &fe.fe_f3, FTYPE_EXT, data);
                   1290: 
                   1291:        // 変換時に検出した UNFL, OVFL だけ外部レジスタにコピー。
                   1292:        fe.fe_fpframe->fpf_fpsr &= ~(FPSR_UNFL | FPSR_OVFL);
                   1293:        fe.fe_fpframe->fpf_fpsr |= fe.fe_fpsr & (FPSR_UNFL | FPSR_OVFL);
                   1294:        // アクルードバイトは更新。
                   1295:        fpu_upd_excp(&fe);
                   1296: 
                   1297:        ea = cea_fpu(12);
                   1298:        write_12(ea, data);
                   1299: }
                   1300: 
                   1301: // FMOVE.P FPn,<ea>
                   1302: // cf. 68000PRM.pdf p378 (5-76)
                   1303: void
                   1304: MPU680x0Device::fpu_op_fmove_p_mem()
                   1305: {
1.1.1.2   root     1306:        uint mr = ir & 077;
1.1       root     1307:        uint srcnum = (ir2 >> 7) & 7;
                   1308:        uint32 ea;
                   1309:        uint32 data[3];
                   1310:        uint32 k;
                   1311: 
1.1.1.2   root     1312:        if (__predict_false(mr <= 017 || mr >= 072)) {  // Dn, An, PC, #imm
                   1313:                fpu_op_illg2();
                   1314:                return;
                   1315:        }
                   1316:        if (__predict_false(GetFPUType().Is6888x() == false)) {
                   1317:                if (GetFPUType().Is4060LC()) {
                   1318:                        ea = cea_fpulc(12);
                   1319:                        ExceptionFPLC(ea);
                   1320:                } else {
                   1321:                        ExceptionFP(M68K::EXCEP_FP_UNIMPL);
                   1322:                }
1.1       root     1323:                return;
                   1324:        }
                   1325: 
                   1326:        if ((ir2 & 0x1000)) {
                   1327:                // dynamic k-factor
                   1328:                CYCLE(1996+14);
                   1329:                k = reg.D[(ir2 >> 4) & 7];
                   1330:        } else {
                   1331:                // static k-factor
                   1332:                CYCLE(1996);
                   1333:                k = ir2;
                   1334:        }
                   1335:        // k は7ビット符号付き数
                   1336:        k &= 0x7f;
                   1337:        if ((k & 0x40)) {
                   1338:                k = (int32)(int8)(k | 0x80);
                   1339:        }
                   1340: 
                   1341:        fpu_explode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(srcnum));
                   1342:        fpu_ftop(&fe, &fe.fe_f3, data, k);
                   1343: 
                   1344:        ea = cea_fpu(12);
                   1345:        write_12(ea, data);
                   1346: }
                   1347: 
                   1348: // FMOVEM.L <ea>,<ctllist>
                   1349: // 1111 ccc 000 mmmrrr | 10D RRR 0000 000000
                   1350: //  D=0: <ea> to FPctl
                   1351: //  RRR: register list
                   1352: void
                   1353: MPU680x0Device::fpu_op_fmovem_ea2ctl()
                   1354: {
                   1355:        uint mr = ir & 0x3f;
                   1356:        uint reglist = (ir2 >> 10) & 7;
                   1357:        int count;
                   1358:        uint32 ea;
                   1359:        uint32 src[3];
                   1360:        int i;
                   1361: 
                   1362:        //                      cache case      worst case
                   1363:        // FMOVE  Rn,FPc                28                      31
                   1364:        // FMOVE  <ea>,FPc              33                      36
                   1365:        // FMOVE  #imm,FPc              30                      31
                   1366:        // FMOVEM <ea>,FPcs             27+6n           30+6n
                   1367:        // FMOVEM #imm,FPcs             25+6n           29+6n
                   1368:        //
                   1369:        // FMOVE #imm と FMOVEM #imm (n==1) は cache case が 1クロックだけ違う
                   1370:        // ようだけどもう無視する。
1.1.1.3   root     1371:        // 040 で複数レジスタのケースの記述が見当たらない。
1.1       root     1372: 
                   1373:        // 転送するレジスタ数。
                   1374:        // nofpc の場合は現在の 68881 の実装では FPIAR が選択される。
                   1375:        if (reglist == 0)
                   1376:                reglist = 1;
                   1377:        count = __builtin_popcount(reglist);
                   1378: 
                   1379:        if (mr < 8) {                           // Dn
1.1.1.3   root     1380:                CYCLE3(fmovem_rn_ctl);
1.1       root     1381:                // 対データレジスタは転送数 1 のみ有効
                   1382:                if (count > 1) {
                   1383:                        fpu_op_illg2();
                   1384:                        return;
                   1385:                }
1.1.1.2   root     1386:                if (__predict_false(GetFPUType().Is4060LC())) {
                   1387:                        ExceptionFPLC(0);
                   1388:                        return;
                   1389:                }
1.1       root     1390:                src[0] = reg.R[mr];
                   1391: 
                   1392:        } else if (mr < 16) {           // An
1.1.1.3   root     1393:                CYCLE3(fmovem_rn_ctl);
1.1       root     1394:                // 対アドレスレジスタは FPIAR のみ有効
                   1395:                if (reglist != 1) {
                   1396:                        fpu_op_illg2();
                   1397:                        return;
                   1398:                }
1.1.1.2   root     1399:                if (__predict_false(GetFPUType().Is4060LC())) {
                   1400:                        ExceptionFPLC(0);
                   1401:                        return;
                   1402:                }
1.1       root     1403:                src[0] = reg.R[mr];
                   1404: 
                   1405:        } else if (mr < 0x3c) {         // 対メモリ
1.1.1.3   root     1406:                CYCLE3(fmovem_mem_ctl);
1.1       root     1407:                CYCLE(count * 6);
                   1408: 
                   1409:                // EA を取得。
                   1410:                // -(An) の時も先にレジスタ数分一気に減算して、そこからプラス方向に
                   1411:                // 読み込んでいくので、ロジックは全部同じになる。
                   1412:                // (68000PRM.pdf p393)
                   1413:                ea = cea_fpu(count * 4);
1.1.1.2   root     1414: 
                   1415:                if (__predict_false(GetFPUType().Is4060LC())) {
                   1416:                        ExceptionFPLC(ea);
                   1417:                        return;
                   1418:                }
                   1419: 
1.1       root     1420:                for (i = 0; i < count; i++) {
                   1421:                        src[i] = read_4(ea);
                   1422:                        ea += 4;
                   1423:                }
                   1424: 
                   1425:        } else if (mr == 0x3c) {        // #imm
1.1.1.2   root     1426:                if (__predict_false(GetFPUType().Is4060LC())) {
                   1427:                        ExceptionFPLC(0);
                   1428:                        return;
                   1429:                }
                   1430: 
1.1.1.3   root     1431:                CYCLE3(fmovem_imm_ctl);
1.1       root     1432:                CYCLE(count * 6);
                   1433: 
                   1434:                for (i = 0; i < count; i++) {
                   1435:                        src[i] = fetch_4();
                   1436:                }
                   1437: 
                   1438:        } else {
                   1439:                fpu_op_illg2();
                   1440:                return;
                   1441:        }
                   1442: 
                   1443:        // 該当レジスタへ読み込み
                   1444:        i = 0;
                   1445:        if ((reglist & 4)) {
                   1446:                RegFPCR = src[i++] & M68K::FPCR_MASK;
                   1447:        }
                   1448:        if ((reglist & 2)) {
                   1449:                RegFPSR = src[i++] & M68K::FPSR_MASK;
                   1450:        }
                   1451:        if ((reglist & 1)) {
                   1452:                RegFPIAR = src[i++];
                   1453:        }
                   1454: }
                   1455: 
                   1456: // FMOVEM.L <ctllist>,<ea>
                   1457: // 1111 ccc 000 mmmrrr | 10D RRR 0000 000000
                   1458: //  D=1: FPctl to <ea>
                   1459: //  RRR: register list
                   1460: void
                   1461: MPU680x0Device::fpu_op_fmovem_ctl2ea()
                   1462: {
                   1463:        uint mr = ir & 0x3f;
                   1464:        uint reglist = (ir2 >> 10) & 7;
                   1465:        int count;
                   1466:        uint32 ea;
                   1467: 
                   1468:        //                      cache case      worst case
                   1469:        // FMOVE  FPc,Rn                31                      34
                   1470:        // FMOVE  FPc,<ea>              33                      36
                   1471:        // FMOVEM FPcs,<ea>             27+6n           30+6n
1.1.1.3   root     1472:        //
                   1473:        // 040 で複数レジスタのケースの記述が見当たらない。
1.1       root     1474: 
                   1475:        // 転送するレジスタ数。
                   1476:        // nofpc の場合は現在の 68881 の実装では FPIAR が選択される。
                   1477:        if (reglist == 0)
                   1478:                reglist = 1;
                   1479:        count = __builtin_popcount(reglist);
                   1480: 
                   1481:        if (mr < 8) {                   // Dn
1.1.1.3   root     1482:                CYCLE3(fmovem_ctl_rn);
1.1       root     1483:                // 対データレジスタは転送数は 1 のみ有効
                   1484:                if (count > 1) {
                   1485:                        fpu_op_illg2();
                   1486:                        return;
                   1487:                }
1.1.1.2   root     1488:                if (__predict_false(GetFPUType().Is4060LC())) {
                   1489:                        ExceptionFPLC(0);
                   1490:                        return;
                   1491:                }
1.1       root     1492: 
                   1493:                if ((reglist & 4)) {
                   1494:                        reg.R[mr] = RegFPCR;
                   1495:                }
                   1496:                if ((reglist & 2)) {
                   1497:                        reg.R[mr] = RegFPSR;
                   1498:                }
                   1499:                if ((reglist & 1)) {
                   1500:                        reg.R[mr] = RegFPIAR;
                   1501:                }
                   1502:                return;
                   1503:        }
                   1504:        if (mr < 16) {                  // An
1.1.1.3   root     1505:                CYCLE3(fmovem_ctl_rn);
1.1       root     1506:                // 対アドレスレジスタは FPIAR のみ有効
                   1507:                if (reglist != 1) {
                   1508:                        fpu_op_illg2();
                   1509:                        return;
                   1510:                }
1.1.1.2   root     1511:                if (__predict_false(GetFPUType().Is4060LC())) {
                   1512:                        ExceptionFPLC(0);
                   1513:                        return;
                   1514:                }
1.1       root     1515:                reg.R[mr] = RegFPIAR;
                   1516:                return;
                   1517:        }
                   1518:        if (mr >= 0x3a) {               // #imm, d16(PC), (PC,IX)
                   1519:                fpu_op_illg2();
                   1520:                return;
                   1521:        }
                   1522: 
                   1523:        // それ以外、対メモリの場合。
1.1.1.2   root     1524:        // EA を取得して...
                   1525:        ea = cea_fpu(count * 4);
                   1526:        if (__predict_false(GetFPUType().Is4060LC())) {
                   1527:                ExceptionFPLC(ea);
                   1528:                return;
                   1529:        }
                   1530: 
1.1.1.3   root     1531:        CYCLE3(fmovem_ctl_mem);
1.1       root     1532:        CYCLE(count * 6);
                   1533: 
                   1534:        // 該当レジスタをメモリへ書き出し
                   1535:        if ((reglist & 4)) {
                   1536:                write_4(ea, RegFPCR);
                   1537:                ea += 4;
                   1538:        }
                   1539:        if ((reglist & 2)) {
                   1540:                write_4(ea, RegFPSR);
                   1541:                ea += 4;
                   1542:        }
                   1543:        if ((reglist & 1)) {
                   1544:                write_4(ea, RegFPIAR);
                   1545:                ea += 4;
                   1546:        }
                   1547: }
                   1548: 
                   1549: // FMOVEM.X <ea>,<reglist>
                   1550: // FMOVEM.X <ea>,Dn
                   1551: // 1111 ccc 000 mmmrrr | 11D MM000 RRRRRRRR
                   1552: // D=0: <ea> to FPn
                   1553: void
                   1554: MPU680x0Device::fpu_op_fmovem_ea2reg()
                   1555: {
                   1556:        uint mr = ir & 0x3f;
1.1.1.2   root     1557:        bool predec = !(ir2 & 0x1000);  // 第2ワードの mode が predec か
1.1       root     1558:        bool dynamic = (ir2 & 0x0800);
                   1559:        uint8 reglist = ir2 & 0xff;
                   1560:        int i;
                   1561:        uint32 ea;
                   1562: 
                   1563:        //                      cache   worst
                   1564:        // FMOVEM.X <ea>,<list> 35+23n  38+23n
                   1565:        // FMOVEM.X <ea>,Dn             49+23n  52+23n
                   1566: 
1.1.1.2   root     1567:        // 不当パターンを弾く。
1.1       root     1568:        switch (mr) {
                   1569:         case 000 ... 007:      // Dn
                   1570:         case 010 ... 017:      // An
                   1571:         case 040 ... 047:      // -(An)
                   1572:         case 074:                      // #imm
                   1573:         case 075 ... 077:
                   1574:                fpu_op_illg2();
                   1575:                return;
                   1576:        }
                   1577: 
                   1578:        // ダイナミックモードなら reglist の %0nnn0000 にレジスタ番号が
                   1579:        // 入っているので、この Dn の下位8ビットを取り出す。レジスタ番号以外の
                   1580:        // ビットは無視、Dn の上位ビットも無視。
                   1581:        // ついでにここでベースサイクル数を加算。
                   1582:        if (dynamic) {
                   1583:                reglist = reg.D[(reglist >> 4) & 7];
1.1.1.3   root     1584:                CYCLE3(fmovem_ea2reg_dyn);
1.1       root     1585:        } else {
1.1.1.3   root     1586:                CYCLE3(fmovem_ea2reg_sta);
1.1       root     1587:        }
                   1588: 
                   1589:        // EA は最初に一度取得しておいて...
                   1590:        int count = __builtin_popcount(reglist);
                   1591:        ea = cea_fpu(12 * count);
                   1592: 
1.1.1.2   root     1593:        if (__predict_false(GetFPUType().Is4060LC())) {
                   1594:                ExceptionFPLC(ea);
                   1595:                return;
                   1596:        }
                   1597: 
1.1       root     1598:        if (predec) {
                   1599:                // predec ならビット7から FP7..FP0 で、bit7 側から順に転送。
                   1600:                for (i = 7; reglist; reglist <<=1, i--) {
                   1601:                        if ((int8)reglist < 0) {
                   1602:                                read_12(ea, &RegFP(i));
                   1603:                                ea += 12;
                   1604:                        }
                   1605:                }
                   1606:        } else {
                   1607:                // ctrl/postinc ならビット7から FP0..FP7 で、bit7 側から順に転送。
                   1608:                for (i = 0; reglist; reglist <<= 1, i++) {
                   1609:                        if ((int8)reglist < 0) {
                   1610:                                read_12(ea, &RegFP(i));
                   1611:                                ea += 12;
                   1612:                        }
                   1613:                }
                   1614:        }
1.1.1.3   root     1615:        CYCLE3(fmovem_ea2reg_n) * count;        // 副作用上等!
1.1       root     1616: }
                   1617: 
                   1618: // FMOVEM.X <reglist>,<ea>
                   1619: // FMOVEM.X Dn,<ea>
                   1620: // 1111 ccc 000 mmmrrr | 11D MM000 RRRRRRRR
                   1621: // D=1: FPn to <ea>
                   1622: void
                   1623: MPU680x0Device::fpu_op_fmovem_reg2ea()
                   1624: {
                   1625:        uint mr = ir & 0x3f;
1.1.1.2   root     1626:        bool anpd = false;                              // 第1ワード EA が -(An) か
1.1       root     1627:        bool predec = !(ir2 & 0x1000);  // 第2ワードの mode が predec か
                   1628:        bool dynamic = (ir2 & 0x0800);
                   1629:        uint8 reglist = ir2 & 0xff;
                   1630:        int i;
                   1631:        uint32 ea;
                   1632: 
                   1633:        //                      cache   worst
                   1634:        // FMOVEM.X <list>,<ea> 37+25n  40+25n
                   1635:        // FMOVEM.X Dn,<ea>             51+25n  54+25n
                   1636: 
1.1.1.2   root     1637:        // 不当パターンを弾く。
                   1638:        // ついでに -(An) だけ覚えておく。
1.1       root     1639:        switch (mr) {
                   1640:         case 000 ... 007:      // Dn
                   1641:         case 010 ... 017:      // An
                   1642:         case 030 ... 037:      // (An)+
                   1643:         case 072:                      // d16(PC)
                   1644:         case 073:                      // d8(PC,IX)
                   1645:         case 074:                      // #imm
                   1646:         case 075 ... 077:
                   1647:                fpu_op_illg2();
                   1648:                return;
                   1649:         case 040 ... 047:      // -(An)
                   1650:                anpd = true;
                   1651:                break;
                   1652:        }
                   1653: 
                   1654:        // ダイナミックモードなら reglist の %0nnn0000 にレジスタ番号が
                   1655:        // 入っているので、この Dn の下位8ビットを取り出す。レジスタ番号以外の
                   1656:        // ビットは無視、Dn の上位ビットも無視。
                   1657:        // ついでにここでベースクロックを記録
                   1658:        if (dynamic) {
                   1659:                reglist = reg.D[(reglist >> 4) & 7];
1.1.1.3   root     1660:                CYCLE3(fmovem_reg2ea_dyn);
1.1       root     1661:        } else {
1.1.1.3   root     1662:                CYCLE3(fmovem_reg2ea_sta);
1.1       root     1663:        }
                   1664: 
                   1665:        int count = __builtin_popcount(reglist);
                   1666: 
                   1667:        // -(An) の時だけ EA を別処理。
                   1668:        // 現状の cea_fpu() は -(An) の時、巻き戻し用のレジスタを保存し
                   1669:        // デクリメントしたアドレスを返すまでを一度に行う便利関数だが、
                   1670:        // FMOVEM fpn,-(An) は最初に巻き戻し用レジスタを保存し (これは命令先頭
                   1671:        // に戻るためなので最初の1回だけ)、その後レジスタ1つずつ 12バイトを
                   1672:        // プリデクリメントしながら格納していく必要がある (この順に実行しないと
                   1673:        // バスエラーの原因箇所が異なってしまう)。
                   1674:        // そのため cea_fpu() がそのまま使えないので、ここだけ独自対応する。
                   1675:        // cea_fpu() は1命令中で EA の取得が1回である前提のあくまで便利関数
                   1676:        // なので、例外的である FMOVEM は仕方がない。
                   1677:        if (anpd) {
1.1.1.3   root     1678:                CYCLE3(fmovem_reg2ea_anpd);
1.1       root     1679:                uint n = eanum(ir);
                   1680:                save_reg_pd(n);
                   1681: 
1.1.1.2   root     1682:                // XXX この場合 ea はどこを指すのか?
                   1683:                if (__predict_false(GetFPUType().Is4060LC())) {
                   1684:                        // Dn,An,#imm は弾いてあるので cea_fpu() と等価になる。
                   1685:                        ea = cea_fpu(12 * count);
                   1686:                        ExceptionFPLC(ea);
                   1687:                        return;
                   1688:                }
                   1689: 
1.1       root     1690:                if (predec) {
                   1691:                        // predec ならビット7から FP7..FP0 で、bit7 側から順に転送。
                   1692:                        for (i = 7; reglist; reglist <<= 1, i--) {
                   1693:                                if ((int8)reglist < 0) {
                   1694:                                        reg.A[n] -= 12;
                   1695:                                        write_12(reg.A[n], &RegFP(i));
                   1696:                                }
                   1697:                        }
                   1698:                } else {
                   1699:                        // ctrl/postinc ならビット7から FP0..FP7 で、bit7 側から順に転送。
                   1700:                        for (i = 0; reglist; reglist <<= 1, i++) {
                   1701:                                if ((int8)reglist < 0) {
                   1702:                                        reg.A[n] -= 12;
                   1703:                                        write_12(reg.A[n], &RegFP(i));
                   1704:                                }
                   1705:                        }
                   1706:                }
                   1707:        } else {
                   1708:                // -(An) 以外は EA を最初に一度計算しておく方法が使える
                   1709:                ea = cea_fpu(12 * count);
                   1710: 
1.1.1.2   root     1711:                if (__predict_false(GetFPUType().Is4060LC())) {
                   1712:                        ExceptionFPLC(ea);
                   1713:                        return;
                   1714:                }
                   1715: 
1.1       root     1716:                if (predec) {
                   1717:                        // predec ならビット7から FP7..FP0 で、bit7 側から順に転送。
                   1718:                        for (i = 7; reglist; reglist <<= 1, i--) {
                   1719:                                if ((int8)reglist < 0) {
                   1720:                                        write_12(ea, &RegFP(i));
                   1721:                                        ea += 12;
                   1722:                                }
                   1723:                        }
                   1724:                } else {
                   1725:                        // ctrl/postinc ならビット7から FP0..FP7 で、bit7 側から順に転送。
                   1726:                        for (i = 0; reglist; reglist <<= 1, i++) {
                   1727:                                if ((int8)reglist < 0) {
                   1728:                                        write_12(ea, &RegFP(i));
                   1729:                                        ea += 12;
                   1730:                                }
                   1731:                        }
                   1732:                }
                   1733:        }
1.1.1.3   root     1734:        CYCLE3(fmovem_reg2ea_n) * count;        // 副作用上等!
1.1       root     1735: }
                   1736: 
                   1737: // FScc.B <ea>
                   1738: // 1111 ccc 001 mmmrrr | 0000 000 000 CCCCCC
                   1739: void
                   1740: MPU680x0Device::fpu_op_fscc()
                   1741: {
                   1742:        uint mr = ir & 0x3f;
                   1743:        uint mm = eamode(ir);
                   1744:        uint rr = eanum(ir);
                   1745:        uint cond = ir2 & 0x3f;
                   1746:        uint32 data;
                   1747:        uint32 ea;
                   1748: 
1.1.1.2   root     1749:        // XXX 条件部に1ビット不当パターンがあるがどっちの判定が先か。
                   1750:        if (__predict_false(GetFPUType().Is4060LC())) {
                   1751:                ea = cea_fpulc(1);
                   1752:                ExceptionFPLC(ea);
                   1753:                return;
                   1754:        }
                   1755: 
1.1       root     1756:        //                      cache   worst
                   1757:        // FScc.B Dn                    18              21
                   1758:        // FScc.B (An)+/-(An)   22              25              ; condition is true
                   1759:        // FScc.B (An)+/-(An)   21              24              ; condition is false
                   1760:        // FScc.B <ea>                  20              23
                   1761: 
                   1762:        if (cond > 0x1f) {
                   1763:                fpu_op_illg2();
                   1764:                return;
                   1765:        }
                   1766: 
                   1767:        data = (test_cc(&fe, cond) == -1) ? 0xff : 0x00;
                   1768: 
                   1769:        switch (mm) {
                   1770:         case 0:        // Dn
1.1.1.3   root     1771:                CYCLE3(fscc_dn);
1.1       root     1772:                reg.D[rr] &= 0xffffff00;
                   1773:                reg.D[rr] |= data;
                   1774:                return;
                   1775: 
                   1776:         case 3:        // (An)+
                   1777:         case 4:        // -(An)
                   1778:                // ここだけ他のメモリ系 EA とはクロックが違うし、
                   1779:                // 条件の成立可否でも違う。
                   1780:                if (data == 0x00) {
1.1.1.3   root     1781:                        CYCLE3(fscc_anp_z);
1.1       root     1782:                } else {
1.1.1.3   root     1783:                        CYCLE3(fscc_anp_nz);
1.1       root     1784:                }
                   1785:                break;
                   1786:         case 7:
                   1787:                if (mr == 0x38 || mr == 0x39) { // Abs.W, Abs.L
                   1788:                } else {
                   1789:                        fpu_op_illg2();
                   1790:                        return;
                   1791:                }
                   1792:                FALLTHROUGH;
                   1793:         default:
1.1.1.3   root     1794:                CYCLE3(fscc_mem);
1.1       root     1795:                break;
                   1796:        }
                   1797: 
                   1798:        ea = cea_fpu(1);
                   1799:        write_1(ea, data);
                   1800: }
                   1801: 
                   1802: // FDBcc Dn,<label>
                   1803: // 1111 ccc 001 001rrr | 0000 000 000 CCCCCC | <16bit disp>
                   1804: void
                   1805: MPU680x0Device::fpu_op_fdbcc()
                   1806: {
1.1.1.2   root     1807:        // XXX 条件部に1ビット不当パターンがあるがどっちの判定が先か。
                   1808:        if (__predict_false(GetFPUType().Is4060LC())) {
                   1809:                ExceptionFPLC(0);
                   1810:                return;
                   1811:        }
                   1812: 
1.1       root     1813:        uint rr = ir & 7;
                   1814:        uint cond = ir2 & 0x3f;
                   1815: 
                   1816:        if (cond > 0x1f) {
                   1817:                fpu_op_illg2();
                   1818:                return;
                   1819:        }
                   1820: 
                   1821:        if (test_cc(&fe, cond) == -1) {
                   1822:                // 真なら何もしない。disp を読み飛ばして次へ
1.1.1.3   root     1823:                CYCLE3(fdbcc_true);
1.1       root     1824:                fetch_2();
                   1825:        } else {
                   1826:                // 偽の場合
                   1827:                uint16 data = reg.D[rr] - 1;
                   1828:                reg.D[rr] = (reg.D[rr] & 0xffff0000) | data;
                   1829: 
                   1830:                if (data == 0xffff) {
                   1831:                        // ループ終了。disp を読み飛ばす
1.1.1.3   root     1832:                        CYCLE3(fdbcc_done);
1.1       root     1833:                        fetch_2();
                   1834:                } else {
                   1835:                        // 計算に使う PC はディスプレースメントのあるアドレス。
1.1.1.3   root     1836:                        CYCLE3(fdbcc_jump);
1.1       root     1837:                        uint32 origin = reg.pc;
                   1838:                        int32 disp = (int32)(int16)fetch_2();
                   1839:                        Jump(origin + disp);
                   1840:                }
                   1841:        }
                   1842: }
                   1843: 
                   1844: // FTRAPcc.W #<data>
                   1845: void
                   1846: MPU680x0Device::fpu_op_ftrapcc_w()
                   1847: {
1.1.1.2   root     1848:        // XXX 条件部に1ビット不当パターンがあるがどっちの判定が先か。
                   1849:        if (__predict_false(GetFPUType().Is4060LC())) {
                   1850:                ExceptionFPLC(0);
                   1851:                return;
                   1852:        }
                   1853: 
1.1       root     1854:        uint cond = ir2 & 0x3f;
                   1855: 
                   1856:        if (cond > 0x1f) {
                   1857:                fpu_op_illg2();
                   1858:                return;
                   1859:        }
                   1860: 
                   1861:        // 即値はいずれにしても読み捨てる必要がある。
                   1862:        fetch_2();
                   1863: 
                   1864:        if (test_cc(&fe, cond) == -1) {
1.1.1.3   root     1865:                CYCLE3(ftrapccw_excep);
1.1       root     1866:                Exception(M68K::EXCEP_TRAPV);
                   1867:        } else {
1.1.1.3   root     1868:                CYCLE3(ftrapccw_nop);
1.1       root     1869:        }
                   1870: }
                   1871: 
                   1872: // FTRAPcc.L #<data>
                   1873: void
                   1874: MPU680x0Device::fpu_op_ftrapcc_l()
                   1875: {
1.1.1.2   root     1876:        // XXX 条件部に1ビット不当パターンがあるがどっちの判定が先か。
                   1877:        if (__predict_false(GetFPUType().Is4060LC())) {
                   1878:                ExceptionFPLC(0);
                   1879:                return;
                   1880:        }
                   1881: 
1.1       root     1882:        uint cond = ir2 & 0x3f;
                   1883: 
                   1884:        if (cond > 0x1f) {
                   1885:                fpu_op_illg2();
                   1886:                return;
                   1887:        }
                   1888: 
                   1889:        // 即値はいずれにしても読み捨てる必要がある。
                   1890:        fetch_4();
                   1891: 
                   1892:        if (test_cc(&fe, cond) == -1) {
1.1.1.3   root     1893:                CYCLE3(ftrapccl_excep);
1.1       root     1894:                Exception(M68K::EXCEP_TRAPV);
                   1895:        } else {
1.1.1.3   root     1896:                CYCLE3(ftrapccl_nop);
1.1       root     1897:        }
                   1898: }
                   1899: 
                   1900: // FTRAPcc
                   1901: void
                   1902: MPU680x0Device::fpu_op_ftrapcc()
                   1903: {
1.1.1.2   root     1904:        // XXX 条件部に1ビット不当パターンがあるがどっちの判定が先か。
                   1905:        if (__predict_false(GetFPUType().Is4060LC())) {
                   1906:                ExceptionFPLC(0);
                   1907:                return;
                   1908:        }
                   1909: 
1.1       root     1910:        uint cond = ir2 & 0x3f;
                   1911: 
                   1912:        if (cond > 0x1f) {
                   1913:                fpu_op_illg2();
                   1914:                return;
                   1915:        }
                   1916: 
                   1917:        // 即値なし。
                   1918: 
                   1919:        if (test_cc(&fe, cond) == -1) {
1.1.1.3   root     1920:                CYCLE3(ftrapcc_excep);
1.1       root     1921:                Exception(M68K::EXCEP_TRAPV);
                   1922:        } else {
1.1.1.3   root     1923:                CYCLE3(ftrapcc_nop);
1.1       root     1924:        }
                   1925: }
                   1926: 
                   1927: // FBcc.W <label>
                   1928: // 1111 ccc 01S CCCCCC | <16bit disp>
                   1929: // S=0: 16bit disp
                   1930: //
                   1931: // FNOP
                   1932: // 1111 ccc 010 000000 | 0000 0000 0000 0000
                   1933: void
                   1934: MPU680x0Device::fpu_op_fbcc_w()
                   1935: {
1.1.1.2   root     1936:        // XXX 条件部に1ビット不当パターンがあるがどっちの判定が先か。
                   1937:        if (__predict_false(GetFPUType().Is4060LC())) {
                   1938:                ExceptionFPLC(0);
                   1939:                return;
                   1940:        }
                   1941: 
1.1       root     1942:        uint cond = ir & 0x3f;
                   1943: 
                   1944:        // TODO: Illegal condition の戻り値を処理すること。他の test_cc() も同様。
                   1945:        if (test_cc(&fe, cond) == -1) {
1.1.1.3   root     1946:                CYCLE3(fbcc_jump);
1.1       root     1947:                uint32 origin = reg.pc;
                   1948:                int32 disp = (int32)(int16)fetch_2();
                   1949:                Jump(origin + disp);
                   1950:        } else {
                   1951:                // disp を読み飛ばす
1.1.1.3   root     1952:                CYCLE3(fbccw_nop);
1.1       root     1953:                fetch_2();
                   1954:        }
                   1955: }
                   1956: 
                   1957: // FBcc.L <label>
                   1958: // 1111 ccc 01S CCCCCC | <32bit disp>
                   1959: // S=1: 32bit disp
                   1960: void
                   1961: MPU680x0Device::fpu_op_fbcc_l()
                   1962: {
1.1.1.2   root     1963:        // XXX 条件部に1ビット不当パターンがあるがどっちの判定が先か。
                   1964:        if (__predict_false(GetFPUType().Is4060LC())) {
                   1965:                ExceptionFPLC(0);
                   1966:                return;
                   1967:        }
                   1968: 
1.1       root     1969:        uint cond = ir & 0x3f;
                   1970: 
                   1971:        if (test_cc(&fe, cond) == -1) {
1.1.1.3   root     1972:                CYCLE3(fbcc_jump);
1.1       root     1973:                uint32 origin = reg.pc;
                   1974:                int32 disp = (int32)fetch_4();
                   1975:                Jump(origin + disp);
                   1976:        } else {
                   1977:                // disp を読み飛ばす
1.1.1.3   root     1978:                CYCLE3(fbccl_nop);
1.1       root     1979:                fetch_4();
                   1980:        }
                   1981: }
                   1982: 
                   1983: // FSAVE の NULL フレーム (全機種共通で4バイト)
                   1984: /*static*/ const uint32
                   1985: MPU680x0Device::fsave_frame_null[] = {
                   1986:        0,
                   1987: };
                   1988: 
                   1989: // FSAVE のアイドルフレーム (68881)
                   1990: /*static*/ const uint32
                   1991: MPU680x0Device::fsave_frame_idle_68881[] = {
                   1992:        0x1f180000,
                   1993:        0x0000ffff,
                   1994:        0,
                   1995:        0,
                   1996:        0,
                   1997:        0,
                   1998:        0x70000000,
                   1999: };
                   2000: 
                   2001: // FSAVE のアイドルフレーム (68040)
                   2002: /*static*/ const uint32
                   2003: MPU680x0Device::fsave_frame_idle_68040[] = {
                   2004:        0x41000000,
                   2005: };
                   2006: 
                   2007: // FSAVE
                   2008: // スーパーバイザモードは判定済み
                   2009: void
                   2010: MPU680x0Device::fpu_op_fsave()
                   2011: {
                   2012:        uint32 ea;
                   2013:        std::array<uint32, 13> frame_noimpl;
                   2014:        const uint32 *frame;
                   2015:        int framelen;
                   2016: 
                   2017:        // フレームを選択。
                   2018:        switch (fpu_state) {
                   2019:         case FPU_STATE_NULL:
                   2020:                // NULL フレーム
1.1.1.3   root     2021:                CYCLE3(fsave_null);
1.1       root     2022:                frame = fsave_frame_null;
                   2023:                framelen = countof(fsave_frame_null);
                   2024:                break;
                   2025:         case FPU_STATE_IDLE:
                   2026:         case FPU_STATE_BUSY:   // 実装してないけどとりあえず。
                   2027:                // IDLE フレーム
1.1.1.3   root     2028:                CYCLE3(fsave_idle);     // XXX これは最小値らしいけど
1.1       root     2029:                if (fpu_type.Is4060FPU()) {
                   2030:                        frame = fsave_frame_idle_68040;
                   2031:                        framelen = countof(fsave_frame_idle_68040);
                   2032:                } else {
                   2033:                        frame = fsave_frame_idle_68881;
                   2034:                        framelen = countof(fsave_frame_idle_68881);
                   2035:                }
                   2036:                break;
                   2037:         case FPU_STATE_NOIMPL:
                   2038:                // 68040 で浮動小数点未実装命令を実行した。
                   2039:                fpu_op_fsave_frame_noimpl(frame_noimpl);
                   2040:                frame = frame_noimpl.data();
                   2041:                framelen = frame_noimpl.size();
                   2042:                break;
                   2043:         default:
                   2044:                PANIC("fpu_state=%u corrupted", fpu_state);
                   2045:        }
                   2046: 
                   2047:        switch (ir & 077) {
                   2048:         case 020 ... 027:      // (An)
                   2049:         case 040 ... 047:      // -(An)
                   2050:         case 050 ... 057:      // d16(An)
                   2051:         case 060 ... 067:      // d8(An,IX)
                   2052:         case 070 ... 071:      // Abs.[WL]
                   2053:                ea = cea_fpu(framelen * 4);
                   2054:                break;
                   2055:         default:
                   2056:                fpu_op_illg();
                   2057:                return;
                   2058:        }
                   2059: 
1.1.1.2   root     2060:        // XXX 実機がどう動くか分からないが、とりあえずここでは
                   2061:        // LC なら fpu_state は NULL から変化しないのでフレーム長 4 として動く。
                   2062:        if (__predict_false(GetFPUType().Is4060LC())) {
                   2063:                ExceptionFPLC(ea);
                   2064:                return;
                   2065:        }
                   2066: 
1.1       root     2067:        // -(An) もそれ以外もどちらも、まず先頭フレームを書き出す。
                   2068:        // この時点で ea は先頭フレームの位置を指している。
                   2069:        write_4(ea, frame[0]);
                   2070: 
                   2071:        // -(An) もそれ以外もどちらも、
                   2072:        // 残りはプリデクリメントのように高位側から順に書き出す。
                   2073:        ea += framelen * 4;
                   2074:        for (int i = framelen - 1; i > 0; i--) {
                   2075:                ea -= 4;
                   2076:                write_4(ea, frame[i]);
                   2077:        }
                   2078: }
                   2079: 
                   2080: // FRESTORE
                   2081: // スーパーバイザモードは判定済み
                   2082: void
                   2083: MPU680x0Device::fpu_op_frestore()
                   2084: {
                   2085:        uint mm = eamode(ir);
                   2086:        uint rr = eanum(ir);
                   2087:        uint32 ea;
                   2088:        uint32 fmtword;
                   2089:        uint32 ver_len;
1.1.1.4 ! root     2090:        uint32 ver;
1.1       root     2091:        uint32 len;
                   2092:        bool postinc;
                   2093: 
                   2094:        postinc = false;
                   2095:        // EA は独自体系なのでここでべたに書く
                   2096:        switch (mm) {
                   2097:         case 2:        // (An)
                   2098:                ea = cea_anin(rr);
                   2099:                break;
                   2100:         case 3:        // (An)+
                   2101:                ea = cea_anin(rr);
                   2102:                postinc = true;
                   2103:                break;
                   2104:         case 5:        // d16(An)
                   2105:                ea = cea_andi(rr);
                   2106:                break;
                   2107:         case 6:        // (An,IX)
                   2108:                ea = cea_anix(rr);
                   2109:                break;
                   2110:         case 7:
                   2111:                switch (rr) {
                   2112:                 case 0:        // Abs.W
                   2113:                        ea = cea_absw();
                   2114:                        break;
                   2115:                 case 1:        // Abs.L
                   2116:                        ea = cea_absl();
                   2117:                        break;
                   2118:                 case 2:        // d16(PC)
                   2119:                        ea = cea_pcdi();
                   2120:                        break;
                   2121:                 case 3:        // (PC,IX)
                   2122:                        ea = cea_pcix();
                   2123:                        break;
                   2124:                 default:
                   2125:                        fpu_op_illg();
                   2126:                        return;
                   2127:                }
                   2128:                break;
                   2129:         default:
                   2130:                fpu_op_illg();
                   2131:                return;
                   2132:        }
                   2133: 
1.1.1.2   root     2134:        if (__predict_false(GetFPUType().Is4060LC())) {
                   2135:                ExceptionFPLC(ea);
                   2136:                return;
                   2137:        }
                   2138: 
1.1       root     2139:        // 先頭の1ロングワードを読んでみる。
                   2140:        // これがフォーマットワード $VVLL'xxxx で、VV がバージョン(8bit)、
                   2141:        // LL が(自身を含まないこれ以降の) バイト数 (8bit) を示している。 
                   2142:        // 68881 本では下位ワードは Reserved($0000) となっているが、
                   2143:        // 68040 本では Reserved のみで値の言及はない。
                   2144:        //
                   2145:        // 68881:
                   2146:        //      NULL    $0000'0000
                   2147:        //      IDLE    $1f18'0000 (以降  6 ロングワード)
                   2148:        //      BUSY    $1fb4'0000 (以降 45 ロングワード) (*)
                   2149:        //
                   2150:        // 68040:
                   2151:        //      NULL    $0000'xxxx
                   2152:        //      IDLE    $4100'xxxx
                   2153:        //      BUSY    $4160'xxxx (以降 24 ロングワード) (*)
                   2154:        //      UNIMP   $4130'xxxx (以降 12 ロングワード)
                   2155:        //
                   2156:        // *: BUSY フレームは現状の FSAVE が出力しないので来ないはず。
                   2157: 
                   2158:        fmtword = read_4(ea);
                   2159:        ea += 4;
                   2160: 
                   2161:        ver_len = fmtword >> 16;
1.1.1.4 ! root     2162:        ver = ver_len >> 8;
1.1       root     2163:        len = ver_len & 0xff;
                   2164: 
                   2165:        if (GetFPUType().Is4060FPU()) {
1.1.1.4 ! root     2166:                if (ver == 0) {
1.1       root     2167:                        // NULL フレーム。
                   2168: 
                   2169:                        // NULL フレームのリストアは FPU の状態をリセットする。
1.1.1.3   root     2170:                        CYCLE3(frestore_null);
1.1       root     2171:                        ResetFPU(false);
1.1.1.4 ! root     2172:                        goto done;
1.1       root     2173:                } else if (ver_len == 0x4100) {
                   2174:                        // IDLE フレーム。
                   2175: 
                   2176:                        // 現状何も実装していないので、状態を戻して読み捨てるだけ。
1.1.1.3   root     2177:                        CYCLE3(frestore_idle);
1.1       root     2178:                        fpu_state = FPU_STATE_IDLE;
                   2179:                } else if (ver_len == 0x4130) {
                   2180:                        // 浮動小数点未実装命令フレーム。
                   2181:                        // どうなる?
                   2182:                        putlog(0, "FRESTORE: Unsupported UNIMP frame");
                   2183:                } else if (ver_len == 0x4160) {
                   2184:                        // BUSY フレーム。
                   2185:                        putlog(0, "FRESTORE: Unsupported BUSY frame");
                   2186:                        if (0) {
                   2187:                                putlog(0, "[+00] %08x", fmtword);
                   2188:                                for (int offset = 4; offset < len; offset += 4) {
                   2189:                                        uint32 m = read_4(ea + offset);
                   2190:                                        putlog(0, "[+%02x] %08x", offset, m);
                   2191:                                }
                   2192:                        }
                   2193:                } else {
                   2194:                        Exception(M68K::EXCEP_FORMAT);
                   2195:                        goto done;
                   2196:                }
                   2197:        } else /* 68881 */ {
1.1.1.4 ! root     2198:                if (ver == 0) {
1.1       root     2199:                        // NULL フレーム。
1.1.1.4 ! root     2200:                        // 長さフィールドは見ない。(MC68881UM.pdf 6.4.2.1)
1.1       root     2201: 
                   2202:                        // NULL フレームのリストアは FPU の状態をリセットする。
1.1.1.3   root     2203:                        CYCLE3(frestore_null);
1.1       root     2204:                        ResetFPU(false);
1.1.1.4 ! root     2205:                        goto done;
1.1       root     2206:                } else if (ver_len == 0x1f18) {
                   2207:                        // IDLE フレーム。
                   2208: 
                   2209:                        // 現状何も実装していないので、状態を戻して読み捨てるだけ。
1.1.1.3   root     2210:                        CYCLE3(frestore_idle);
1.1       root     2211:                        fpu_state = FPU_STATE_IDLE;
                   2212:                } else {
                   2213:                        if (ver_len == 0x1fb4) {
                   2214:                                putlog(0, "FRESTORE: Unsupported BUSY frame");
                   2215:                        }
                   2216:                        Exception(M68K::EXCEP_FORMAT);
                   2217:                        goto done;
                   2218:                }
                   2219:        }
                   2220: 
                   2221:        // とにかく残りを全部読み捨てる。
                   2222:        len /= 4;
                   2223:        for (int i = 0; i < len; i++) {
                   2224:                read_4(ea);
                   2225:                ea += 4;
                   2226:        }
                   2227: 
                   2228:  done:
                   2229:        // (An)+ なら更新。
                   2230:        // フォーマットワードを読んだところでエラーが起きたら +4 だけ更新される?
                   2231:        if (postinc) {
                   2232:                reg.A[rr] = ea;
                   2233:        }
                   2234: }
                   2235: 
                   2236: // 現在の fpu40 の状態から
                   2237: // 68040 の浮動小数点未実装命令フレームを作成して frame に書き出す。
                   2238: void
                   2239: MPU680x0Device::fpu_op_fsave_frame_noimpl(std::array<uint32, 13>& frame)
                   2240: {
                   2241:        uint32 cmd1;
                   2242:        uint32 reg3b;
                   2243:        uint32 data6;
                   2244: 
                   2245:        // CMDREG1B 形式の Ry+CMD1 から CMDREG3B 形式の Ry+CMD3 を作る。
                   2246:        cmd1 = fpu40.reg1b & 0x3ff;
                   2247:        reg3b = (cmd1 & 0x3c3) | ((cmd1 >> 1) & 0x1c) | ((cmd1 << 3) & 0x20);
                   2248: 
                   2249:        data6 = fpu40.eflag;
                   2250:        if (fpu40.post) {
                   2251:                data6 |= 0x0010'0000;
                   2252:        }
                   2253: 
                   2254:        frame[0] = 0x41300000;
                   2255:        frame[1] = reg3b << 16;
                   2256:        frame[2] = 0;
                   2257:        frame[3] = (uint32)fpu40.stag << 29;
                   2258:        frame[4] = fpu40.reg1b << 16;
                   2259:        frame[5] = (uint32)fpu40.dtag << 29;
                   2260:        frame[6] = data6;
                   2261:        memcpy(&frame[7], fpu40.fptemp, 12);
                   2262:        memcpy(&frame[10], fpu40.etemp, 12);
                   2263: 
                   2264:        // モニタ表示用。
                   2265:        fpu40.enable = false;
                   2266: }
                   2267: 
                   2268: // 浮動小数点系の例外。
                   2269: // fpu40 の stag, dtag, etemp, fptemp, eflag を必要に応じてセットしてから
                   2270: // 呼ぶこと。
                   2271: void
                   2272: MPU680x0Device::ExceptionFP(uint vector)
                   2273: {
                   2274:        fpu_state = FPU_STATE_NOIMPL;
                   2275: 
                   2276:        // CMDREG1B は実質 2ワード目のことのようだ。
                   2277:        // FMOVECR のケースはドキュメントに見当たらないが、FPSP を読む限り
                   2278:        // CMDREG1B はここでも FMOVECR の第2ワードそのままのようだ。
                   2279:        // FSQRT 用のハックで cmd(offset) の $04 を $05 に書き換えるが、FPSP の
                   2280:        // FMOVECR はどちらも 0.0 を返すので、書き換えてしまっても問題ないはず?
                   2281:        uint32 reg1b = ir2;
                   2282:        if ((reg1b & 0x3f) == 0x04) {
                   2283:                // FSQRT だけマッピングが違う。
                   2284:                reg1b++;
                   2285:        }
                   2286:        fpu40.reg1b = reg1b;
                   2287:        fpu40.post = false;
                   2288:        fpu40.enable = true;
                   2289: 
                   2290:        // この例外を起こした命令のアドレスは FPIAR に置く。
                   2291:        reg.fpframe.fpf_fpiar = ppc;
                   2292: 
                   2293:        // EXCEP_FP_UNIMPL (未実装命令例外) はベクタが F ラインと同じで、
                   2294:        // フレームフォーマットが違うので、定数値に細工がしてある。
1.1.1.3   root     2295:        const uint32 info = BranchHistory_m680x0::InfoException(vector & 0xff);
                   2296:        ExceptionGeneric(vector, info);
1.1       root     2297: }
                   2298: 
                   2299: // CMDREG1B からコマンド名を返す。
                   2300: // FSQRT 命令の第2ワードの cmd 部分は $04 だが CMDREG1B では $05 になる。
                   2301: /*static*/ std::string
                   2302: MPU68040Device::GetReg1BName(uint32 opclass, uint32 sz, uint32 cmd)
                   2303: {
                   2304:        std::string name;
                   2305: 
                   2306:        if (opclass != 0 && opclass != 2) {
                   2307:                return "";
                   2308:        }
                   2309: 
                   2310:        if (sz == 7) {
                   2311:                return "fmovecr";
                   2312:        }
                   2313: 
                   2314:        if (__predict_false(0x30 <= cmd && cmd < 0x38)) {
                   2315:                name = "fsincos";
                   2316:                name += '0' + (cmd - 0x30);
                   2317:                return name;
                   2318:        }
                   2319: 
                   2320:        if (__predict_false(cmd == 0x04)) {
                   2321:                // 来ないはずだけど一応。
                   2322:                return "fsqrt(4)";
                   2323:        }
                   2324: 
                   2325:        if (__predict_false(cmd == 0x05)) {
                   2326:                cmd = 0x04;
                   2327:        }
                   2328:        name = m680x0disasm::make_fpgen(cmd);
                   2329:        return name;
                   2330: }
                   2331: 
                   2332: /*static*/ std::string
                   2333: MPU68040Device::GetFPUTagName(int32 tag)
                   2334: {
                   2335:        const char * const tagnames[] = {
                   2336:                "(Normal)",
                   2337:                "(Zero)",
                   2338:                "(Inf)",
                   2339:                "(NAN)",
                   2340:                "(Unnormal)",
                   2341:                "(Denormal)",
                   2342:        };
                   2343: 
                   2344:        if (__predict_true(tag < countof(tagnames))) {
                   2345:                return tagnames[tag];
                   2346:        }
                   2347:        if (tag == FPU40::TAG_DENORMAL_S) {
                   2348:                return "(Denormal.S)";
                   2349:        }
                   2350:        if (tag == FPU40::TAG_DENORMAL_D) {
                   2351:                return "(Denormal.D)";
                   2352:        }
                   2353:        if (tag == FPU40::TAG_DENORMAL_X) {
                   2354:                return "(Denormal.X)";
                   2355:        }
                   2356:        if (tag == FPU40::TAG_UNNORMAL_X) {
                   2357:                return "(Unnormal.X)";
                   2358:        }
                   2359:        if (tag == FPU40::TAG_NONE) {
                   2360:                return "(NONE)";
                   2361:        }
                   2362:        return "";
                   2363: }
                   2364: 
                   2365: // モニター更新 (040 内部情報)
                   2366: void
1.1.1.4 ! root     2367: MPU68040Device::MonitorScreenFPU40(TextScreen& screen, int y, const FPU40& tmp)
1.1       root     2368: {
                   2369:        // CMDREG1B:$xxxx OPCLASS=0 Rs=7 Rd=7 cmd=00(FTWOTOX) Flags: E3 E1 T
                   2370:        // ETEMP :$01234567_01234567_01234567   STAG:1(Unnormal)
                   2371:        // FPTEMP:
                   2372: 
                   2373:        TA attr = tmp.enable ? TA::Normal : TA::Disable;
                   2374: 
                   2375:        uint32 reg1b = tmp.reg1b;
                   2376:        uint32 opclass = reg1b >> 13;
                   2377:        uint32 rx = (reg1b >> 10) & 7;
                   2378:        uint32 ry = (reg1b >>  7) & 7;
                   2379:        uint32 cmd = reg1b & 0x7f;
                   2380: 
                   2381:        std::string cmdname = GetReg1BName(opclass, rx, cmd);
                   2382:        if (__predict_true(cmdname.empty() == false)) {
                   2383:                cmdname = '(' + cmdname + ')';
                   2384:        }
                   2385: 
                   2386:        std::string stagname = GetFPUTagName(tmp.stag);
                   2387:        std::string dtagname = GetFPUTagName(tmp.dtag);
                   2388: 
                   2389:        screen.Print(0, y, attr,
                   2390:                "CMDREG1B:%04x OPCLASS=%u Rs=%u Rd=%u CMD=$%02x%s",
                   2391:                reg1b, opclass, rx, ry, cmd, cmdname.c_str());
                   2392:        screen.Puts(56, y, attr, "Flags:");
                   2393:        screen.Puts(62, y, attr, (tmp.eflag & FPU40::E1) ? "E1" : "--");
                   2394:        screen.Puts(65, y, attr, (tmp.eflag & FPU40::E3) ? "E3" : "--");
                   2395:        screen.Puts(68, y, attr, (tmp.post) ? "T" : "-");
                   2396:        y++;
                   2397:        screen.Print(0, y, attr, "ETEMP: %08x_%08x_%08x   STAG:%d%s",
                   2398:                tmp.etemp[0], tmp.etemp[1], tmp.etemp[2],
                   2399:                (__predict_true(tmp.stag >= 0) ? (tmp.stag & 7) : tmp.stag),
                   2400:                stagname.c_str());
                   2401:        screen.Print(56, y, attr, "EA:%08x", tmp.ea);
                   2402:        y++;
                   2403:        screen.Print(0, y++, attr, "FPTEMP:%08x_%08x_%08x   DTAG:%d%s",
                   2404:                tmp.fptemp[0], tmp.fptemp[1], tmp.fptemp[2],
                   2405:                (__predict_true(tmp.dtag >= 0) ? (tmp.dtag & 7) : tmp.dtag),
                   2406:                dtagname.c_str());
                   2407: }

unix.superglobalmegacorp.com

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