Annotation of nono/m680x0/m680x0fpu.cpp, revision 1.1.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.