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

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

unix.superglobalmegacorp.com

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