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

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

unix.superglobalmegacorp.com

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