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

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

unix.superglobalmegacorp.com

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