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

1.1       root        1: //
                      2: // nono
1.1.1.2   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
                      7: #include "m68030core.h"
                      8: #include "m68030bus.h"
                      9: #include "m68030ea.h"
1.1.1.2   root       10: #include "m68030excep.h"
1.1       root       11: #include "m68030fpu.h"
                     12: 
                     13: static void fgen(m68kcpu *);
                     14: static void fpu_op_fmovecr(m68kcpu *);
                     15: 
                     16: // リセット用のレジスタ初期値
1.1.1.2   root       17: static struct fpframe initial_fpframe;
1.1       root       18: 
                     19: // 初期化
                     20: void
                     21: fpu_init(m68kcpu *cpu)
                     22: {
                     23:        int i;
                     24:        uint32_t *p;
                     25: 
                     26:        // XXX cpu の初期化のところと見直してマージするとか
                     27:        memset(&cpu->fe, 0, sizeof(cpu->fe));
                     28:        memset(&cpu->reg.fpframe, 0, sizeof(cpu->reg.fpframe));
                     29:        cpu->fe.fe_fpframe = &cpu->reg.fpframe;
                     30: 
                     31:        // FRESTORE によるリセット用に FP レジスタの初期値を用意しておく
                     32:        memset(&initial_fpframe, 0, sizeof(initial_fpframe));
                     33:        p = initial_fpframe.fpf_regs;
                     34:        for (i = 0; i < 8; i++) {
                     35:                *p++ = 0x7fff0000;
                     36:                *p++ = 0xffffffff;
                     37:                *p++ = 0xffffffff;
                     38:        }
                     39: }
                     40: 
                     41: // FPU をリセットする。
                     42: // MPU リセット時と、NULL フレームのリストア時に呼ばれる。
1.1.1.2   root       43: static void
1.1       root       44: fpu_reset(m68kcpu *cpu)
                     45: {
                     46:        // 高速化のため、あらかじめ用意しておいたイメージをコピーする
                     47:        memcpy(&cpu->reg.fpframe, &initial_fpframe, sizeof(initial_fpframe));
                     48: 
                     49:        cpu->fpu_dirty = false;
                     50: }
                     51: 
                     52: // FPU からの呼び出し用。
                     53: //
                     54: // (An)+, -(An) は、サイズが増えているのとクロックが増加している(2->6)。
                     55: // それ以外のアドレッシングモードでもクロック数は微妙に違うのだが、
                     56: // 大きくは違わないのでそっちは本体の cea と同じということにする。
                     57: //
                     58: // このルーチンは Dn、An、#imm には対応していないので(自明)、呼び出し側で
                     59: // 事前に弾くこと。いずれも消費クロック数は 0 なので問題ない。
                     60: // またそれ以外のすべてのアドレッシングモードで反応するため、命令ごとに
                     61: // 対応していないアドレッシングモードは事前に弾くこと。
                     62: static inline uint32
                     63: cea_fpu(m68kcpu *cpu, int bytes)
                     64: {
                     65:        int n;
                     66: 
                     67:        switch (eamode(RegIR)) {
                     68:         case 0:        // Dn
                     69:         case 1:        // An
                     70:                break;
                     71:         case 2:        // (An)
                     72:                return cea_anin(cpu, eanum(RegIR));
                     73:         case 3:        // (An)+
                     74:                CYCLE(6);
                     75:                n = eanum(RegIR);
                     76:                m68030_save_reg_pi(cpu, n);
                     77:                if (bytes == 1) {
                     78:                        return internal_ea_anpi_8(cpu, n);
                     79:                } else {
                     80:                        // _anpi_{16,32} のマクロは用意されてるけど、これと同じなので
                     81:                        RegA(n) += bytes;
                     82:                        return RegA(n) - bytes;
                     83:                }
                     84:                break;
                     85:         case 4:        // -(An)
                     86:                CYCLE(6);
                     87:                n = eanum(RegIR);
                     88:                m68030_save_reg_pd(cpu, n);
                     89:                if (bytes == 1) {
                     90:                        return internal_ea_anpd_8(cpu, n);
                     91:                } else {
                     92:                        // _anpd_{16,32} のマクロは用意されてるけど、これと同じなので
                     93:                        RegA(n) -= bytes;
                     94:                        return RegA(n);
                     95:                }
                     96:                break;
                     97:         case 5:        // d16(An)
                     98:                return cea_andi(cpu, eanum(RegIR));
                     99:         case 6:        // (An,IX)
                    100:                return cea_anix(cpu, eanum(RegIR));
                    101:         case 7:
                    102:                switch (eanum(RegIR)) {
                    103:                 case 0:        // Abs.W
                    104:                        return cea_absw(cpu);
                    105:                 case 1:        // Abs.L
                    106:                        return cea_absl(cpu);
                    107:                 case 2:        // d16(PC)
                    108:                        return cea_pcdi(cpu);
                    109:                 case 3:        // (PC,IX)
                    110:                        return cea_pcix(cpu);
                    111:                 case 4:        // #imm
                    112:                        break;
                    113:                 default:
                    114:                        break;
                    115:                }
                    116:                break;
                    117:        }
                    118:        // 不当命令
                    119:        throw M68K_EXCEP_ILLEGAL;
                    120: }
                    121: 
                    122: // メモリから 64ビット値を読み込む
1.1.1.2   root      123: static void
1.1       root      124: m68030_read_64(m68kcpu *cpu, uint32 addr, uint32 *data)
                    125: {
                    126:        data[0] = m68030_read_32(cpu, addr);
                    127:        data[1] = m68030_read_32(cpu, addr + 4);
                    128: }
                    129: 
                    130: // メモリから 96ビット値を読み込む
1.1.1.2   root      131: static void
1.1       root      132: m68030_read_96(m68kcpu *cpu, uint32 addr, uint32 *data)
                    133: {
                    134:        data[0] = m68030_read_32(cpu, addr);
                    135:        data[1] = m68030_read_32(cpu, addr + 4);
                    136:        data[2] = m68030_read_32(cpu, addr + 8);
                    137: }
                    138: 
                    139: // 64ビット値(.D)をメモリに書き込む
1.1.1.2   root      140: static void
1.1       root      141: m68030_write_64(m68kcpu *cpu, int32 addr, const uint32 *data)
                    142: {
                    143:        m68030_write_32(cpu, addr,     data[0]);
                    144:        m68030_write_32(cpu, addr + 4, data[1]);
                    145: }
                    146: 
                    147: // 96ビット値(.D)をメモリに書き込む
1.1.1.2   root      148: static void
1.1       root      149: m68030_write_96(m68kcpu *cpu, int32 addr, const uint32 *data)
                    150: {
                    151:        m68030_write_32(cpu, addr,     data[0]);
                    152:        m68030_write_32(cpu, addr + 4, data[1]);
                    153:        m68030_write_32(cpu, addr + 8, data[2]);
                    154: }
                    155: 
1.1.1.2   root      156: // ソースを読み込む。
                    157: // 不当命令パターンなら false を返す。
                    158: // size_id は SIZE_*。
1.1       root      159: static bool
                    160: readSRC(m68kcpu *cpu, int size_id, struct fpn *fpn)
                    161: {
                    162:        struct fpemu *fe = &cpu->fe;
                    163:        uint mr = RegIR & 0x3f;
                    164:        uint32 ea;
                    165:        uint32 data[3];
                    166: 
                    167:        // 68881 本(p6-13) にはクロック数はこう書いてあるので
1.1.1.3   root      168:        // Inst | src=FPn       | memory source or dst operand format
                    169:        //      |                       | Int   Sgl             Dbl             Ext             Pakced
                    170:        // ---- +----------     +------ ------- ------- ------- -------
                    171:        // FABS | 35            | 62    54              60              58              872
1.1       root      172:        //            (差分)  +27     +19             +25             +23             +837
                    173:        // FADD | 51            | 80    72              78              76              888
                    174:        //            (差分)  +29     +21             +27             +25             +837
                    175:        //
                    176:        // FABS.X FPn,FPm は 35 としてこれは fgen() 内で加算。
                    177:        // FABS.L <ea>,FPm は 62 クロックなので、ここでは差分の 27 を加算。
                    178:        // FABS.L Dn,FPm  の場合 src がレジスタなので 62 から 5 引く。
                    179:        // FABS.P <ea>,FPm は 872 クロックなので、ここでは差分の  837 を加算。
                    180:        //
                    181:        // XXX 多くの命令が FABS と同じだけの差分だが、
                    182:        // FADD などいくつかは .P 以外に +2 クロックの追加があるようだ。
                    183:        // どうしたもんか。
                    184: 
                    185:        if (mr < 8) {   // Dn
                    186:                switch (size_id) {
                    187:                 case SIZE_B:
                    188:                        data[0] = (int32)(int8)RegD(mr);
                    189:                        break;
                    190:                 case SIZE_W:
                    191:                        data[0] = (int32)(int16)RegD(mr);
                    192:                        break;
                    193:                 case SIZE_L:
                    194:                 case SIZE_S:
                    195:                        data[0] = RegD(mr);
                    196:                        break;
                    197:                 default:
                    198:                        return false;
                    199:                }
                    200:                // ソースが Dn の場合は 5クロック減
                    201:                CYCLE(-5);
                    202:        } else if (mr == 0x3c) {                // #imm
                    203:                switch (size_id) {
                    204:                 case SIZE_B:
                    205:                        data[0] = m68030_fetch_16(cpu) & 0xff;
                    206:                        break;
                    207:                 case SIZE_W:
                    208:                        data[0] = m68030_fetch_16(cpu);
                    209:                        break;
                    210:                 case SIZE_L:
                    211:                 case SIZE_S:
                    212:                        data[0] = m68030_fetch_32(cpu);
                    213:                        break;
                    214:                 case SIZE_D:
                    215:                        data[0] = m68030_fetch_32(cpu);
                    216:                        data[1] = m68030_fetch_32(cpu);
                    217:                        break;
                    218:                 case SIZE_X:
                    219:                 case SIZE_P:
                    220:                        data[0] = m68030_fetch_32(cpu);
                    221:                        data[1] = m68030_fetch_32(cpu);
                    222:                        data[2] = m68030_fetch_32(cpu);
                    223:                        break;
                    224:                 default:
                    225:                        return false;
                    226:                }
                    227:        } else {
                    228:                // それ以外は EA を求めてからメモリから読み込む
                    229:                switch (size_id) {
                    230:                 case SIZE_B:
                    231:                        ea = cea_fpu(cpu, 1);
                    232:                        data[0] = (int32)(int8)m68030_read_8(cpu, ea);
                    233:                        break;
                    234:                 case SIZE_W:
                    235:                        ea = cea_fpu(cpu, 2);
                    236:                        data[0] = (int32)(int16)m68030_read_16(cpu, ea);
                    237:                        break;
                    238:                 case SIZE_L:
                    239:                 case SIZE_S:
                    240:                        ea = cea_fpu(cpu, 4);
                    241:                        data[0] = m68030_read_32(cpu, ea);
                    242:                        break;
                    243:                 case SIZE_D:
                    244:                        ea = cea_fpu(cpu, 8);
                    245:                        m68030_read_64(cpu, ea, data);
                    246:                        break;
                    247:                 case SIZE_X:
                    248:                 case SIZE_P:
                    249:                        ea = cea_fpu(cpu, 12);
                    250:                        m68030_read_96(cpu, ea, data);
                    251:                        break;
                    252:                 default:
                    253:                        return false;
                    254:                }
                    255:        }
                    256: 
                    257:        // 型別に fpn に変換
                    258:        switch (size_id) {
                    259:         case SIZE_B:
                    260:         case SIZE_W:
                    261:         case SIZE_L:
                    262:                CYCLE(+27);
                    263:                fpu_explode(fe, fpn, FTYPE_LNG, data);
                    264:                break;
                    265:         case SIZE_S:
                    266:                CYCLE(+19);
                    267:                fpu_explode(fe, fpn, FTYPE_SNG, data);
                    268:                break;
                    269:         case SIZE_D:
                    270:                CYCLE(+25);
                    271:                fpu_explode(fe, fpn, FTYPE_DBL, data);
                    272:                break;
                    273:         case SIZE_X:
                    274:                CYCLE(+23);
                    275:                fpu_explode(fe, fpn, FTYPE_EXT, data);
                    276:                break;
                    277:         case SIZE_P:
                    278:                CYCLE(+837);
                    279:                fpu_explode(fe, fpn, FTYPE_BCD, data);
                    280:                break;
                    281:        }
                    282: 
                    283:        return true;
                    284: }
                    285: 
                    286: // FPU 不当命令 (1ワード目で確定)
                    287: void
                    288: fpu_op_illg(m68kcpu *cpu)
                    289: {
1.1.1.4 ! root      290:        cpulog(1, "FPU illegal instruction %04X", RegIR);
1.1       root      291:        m68030_exception(cpu, M68K_EXCEP_FLINE);
                    292: }
                    293: 
                    294: // FPU 不当命令 (2ワード目で確定)
1.1.1.2   root      295: static void
1.1       root      296: fpu_op_illg2(m68kcpu *cpu)
                    297: {
1.1.1.4 ! root      298:        cpulog(1, "FPU illegal instruction %04X %04X", RegIR, RegIR2);
1.1       root      299:        m68030_exception(cpu, M68K_EXCEP_FLINE);
                    300: }
                    301: 
                    302: // R/M=0 (レジスタ-レジスタ演算)
                    303: void
                    304: fpu_op_fgen_reg(m68kcpu *cpu)
                    305: {
                    306:        struct fpemu *fe = &cpu->fe;
                    307:        uint srcnum = (RegIR2 >> 10) & 7;
                    308:        uint dstnum = (RegIR2 >> 7) & 7;
                    309: 
                    310:        fpu_explode(fe, &fe->fe_f2, FTYPE_EXT, &RegFP(srcnum * 3));
                    311:        fpu_explode(fe, &fe->fe_f1, FTYPE_EXT, &RegFP(dstnum * 3));
                    312:        fgen(cpu);
                    313: }
                    314: 
                    315: // R/M=1 (メモリ-レジスタ演算)
                    316: void
                    317: fpu_op_fgen_mem(m68kcpu *cpu)
                    318: {
                    319:        struct fpemu *fe = &cpu->fe;
                    320:        uint size_id = (RegIR2 >> 10) & 7;
                    321:        uint dstnum = (RegIR2 >> 7) & 7;
                    322: 
                    323:        // source specifier はオペランドサイズ
                    324:        if (size_id == 7) {
                    325:                // こんなところに FMOVECR
                    326:                fpu_op_fmovecr(cpu);
                    327:                return;
                    328:        }
                    329: 
                    330:        // 第1ワードの EA がソース EA
                    331:        if (!readSRC(cpu, size_id, &fe->fe_f2)) {
                    332:                fpu_op_illg2(cpu);
                    333:                return;
                    334:        }
                    335:        fpu_explode(fe, &fe->fe_f1, FTYPE_EXT, &RegFP(dstnum * 3));
                    336:        fgen(cpu);
                    337: }
                    338: 
                    339: // 一般算術演算
                    340: static void
                    341: fgen(m68kcpu *cpu)
                    342: {
                    343:        struct fpemu *fe = &cpu->fe;
                    344:        uint opmode = RegIR2 & 0x3f;
                    345:        uint dstnum = (RegIR2 >> 7) & 7;
                    346:        bool discard_result = false;
                    347:        struct fpn *res = NULL; // shutup gcc
                    348: 
                    349:        switch (opmode) {
                    350:         case 0x00:             // FMOVE
                    351:                CYCLE(33);
                    352:                res = &fe->fe_f2;
                    353:                fpu_round_prec(fe, res);
                    354:                break;
                    355:         case 0x01:             // FINT
                    356:                CYCLE(55);
                    357:                res = fpu_int(fe);
                    358:                break;
                    359:         case 0x02:             // FSINH
                    360:                CYCLE(687);
                    361:                res = fpu_sinh(fe);
                    362:                fpu_round_prec(fe, res);
                    363:                break;
                    364:         case 0x03:             // FINTRZ
                    365:                CYCLE(55);
                    366:                res = fpu_intrz(fe);
                    367:                break;
                    368:         case 0x04:             // FSQRT
                    369:                CYCLE(107);
                    370:                res = fpu_sqrt(fe);
                    371:                fpu_round_prec(fe, res);
                    372:                break;
                    373:         case 0x06:             // FLOGNP1
                    374:                CYCLE(571);
                    375:                res = fpu_lognp1(fe);
                    376:                fpu_round_prec(fe, res);
                    377:                break;
                    378:         case 0x08:             // FETOXM1
                    379:                CYCLE(545);
                    380:                res = fpu_etoxm1(fe);
                    381:                fpu_round_prec(fe, res);
                    382:                break;
                    383:         case 0x09:             // FTANH
                    384:                CYCLE(661);
                    385:                res = fpu_tanh(fe);
                    386:                fpu_round_prec(fe, res);
                    387:                break;
                    388:         case 0x0a:             // FATAN
                    389:                CYCLE(403);
                    390:                res = fpu_atan(fe);
                    391:                fpu_round_prec(fe, res);
                    392:                break;
                    393:         case 0x0c:             // FASIN
                    394:                CYCLE(581);
                    395:                res = fpu_asin(fe);
                    396:                fpu_round_prec(fe, res);
                    397:                break;
                    398:         case 0x0d:             // FATANH
                    399:                CYCLE(693);
                    400:                res = fpu_atanh(fe);
                    401:                fpu_round_prec(fe, res);
                    402:                break;
                    403:         case 0x0e:             // FSIN
                    404:                CYCLE(391);
                    405:                res = fpu_sin(fe);
                    406:                fpu_round_prec(fe, res);
                    407:                break;
                    408:         case 0x0f:             // FTAN
                    409:                CYCLE(473);
                    410:                res = fpu_tan(fe);
                    411:                fpu_round_prec(fe, res);
                    412:                break;
                    413:         case 0x10:             // FETOX
                    414:                CYCLE(497);
                    415:                res = fpu_etox(fe);
                    416:                fpu_round_prec(fe, res);
                    417:                break;
                    418:         case 0x11:             // FTWOTOX
                    419:                CYCLE(567);
                    420:                res = fpu_twotox(fe);
                    421:                fpu_round_prec(fe, res);
                    422:                break;
                    423:         case 0x12:             // FTENTOX
                    424:                CYCLE(567);
                    425:                res = fpu_tentox(fe);
                    426:                fpu_round_prec(fe, res);
                    427:                break;
                    428:         case 0x14:             // FLOGN
                    429:                CYCLE(525);
                    430:                res = fpu_logn(fe);
                    431:                fpu_round_prec(fe, res);
                    432:                break;
                    433:         case 0x15:             // FLOG10
                    434:                CYCLE(581);
                    435:                res = fpu_log10(fe);
                    436:                fpu_round_prec(fe, res);
                    437:                break;
                    438:         case 0x16:             // FLOG2
                    439:                CYCLE(581);
                    440:                res = fpu_log2(fe);
                    441:                fpu_round_prec(fe, res);
                    442:                break;
                    443:         case 0x18:             // FABS
                    444:                CYCLE(35);
                    445:                fe->fe_f2.fp_sign = 0;
                    446:                res = &fe->fe_f2;
                    447:                fpu_round_prec(fe, res);
                    448:                break;
                    449:         case 0x19:             // FCOSH
                    450:                CYCLE(607);
                    451:                res = fpu_cosh(fe);
                    452:                fpu_round_prec(fe, res);
                    453:                break;
                    454:         case 0x1a:             // FNEG
                    455:                CYCLE(35);
                    456:                res = &fe->fe_f2;
                    457:                if (!ISNAN(res)) {
                    458:                        res->fp_sign = !res->fp_sign;
                    459:                        fpu_round_prec(fe, res);
                    460:                }
                    461:                break;
                    462:         case 0x1c:             // FACOS
                    463:                CYCLE(625);
                    464:                res = fpu_acos(fe);
                    465:                fpu_round_prec(fe, res);
                    466:                break;
                    467:         case 0x1d:             // FCOS
                    468:                CYCLE(391);
                    469:                res = fpu_cos(fe);
                    470:                fpu_round_prec(fe, res);
                    471:                break;
                    472:         case 0x1e:             // FGETEXP
                    473:                CYCLE(45);
                    474:                res = fpu_getexp(fe);
                    475:                fpu_round_prec(fe, res);
                    476:                break;
                    477:         case 0x1f:             // FGETMAN
                    478:                CYCLE(31);
                    479:                res = fpu_getman(fe);
                    480:                fpu_round_prec(fe, res);
                    481:                break;
                    482:         case 0x20:             // FDIV
                    483:                CYCLE(103);
                    484:                res = fpu_div(fe);
                    485:                fpu_round_prec(fe, res);
                    486:                break;
                    487:         case 0x21:             // FMOD
                    488:                CYCLE(67);
                    489:                res = fpu_mod(fe);
                    490:                fpu_round_prec(fe, res);
                    491:                break;
                    492:         case 0x22:             // FADD
                    493:                CYCLE(51);
                    494:                res = fpu_add(fe);
                    495:                fpu_round_prec(fe, res);
                    496:                break;
                    497:         case 0x23:             // FMUL
                    498:                CYCLE(71);
                    499:                res = fpu_mul(fe);
                    500:                fpu_round_prec(fe, res);
                    501:                break;
                    502:         case 0x24:             // FSGLDIV
                    503:                CYCLE(69);
                    504:                res = fpu_sgldiv(fe);
                    505:                break;
                    506:         case 0x25:             // FREM
                    507:                CYCLE(67);
                    508:                res = fpu_rem(fe);
                    509:                fpu_round_prec(fe, res);
                    510:                break;
                    511:         case 0x26:             // FSCALE
                    512:                // こいつだけ形式が違う。
                    513:                // 結果は dst に直接格納済み、FPSR も演算済み。
                    514:                CYCLE(41);
                    515:                fpu_emul_fscale(fe, RegIR2);
                    516:                return;
                    517:         case 0x27:             // FSGLMUL
                    518:                CYCLE(59);
                    519:                res = fpu_sglmul(fe);
                    520:                break;
                    521:         case 0x28:             // FSUB
                    522:                CYCLE(51);
                    523:                res = fpu_sub(fe);
                    524:                fpu_round_prec(fe, res);
                    525:                break;
                    526:         case 0x30:
                    527:         case 0x31:
                    528:         case 0x32:
                    529:         case 0x33:
                    530:         case 0x34:
                    531:         case 0x35:
                    532:         case 0x36:
                    533:         case 0x37:             // FSINCOS
                    534:                CYCLE(451);
                    535:                res = fpu_sincos(fe, opmode & 7);
                    536:                fpu_round_prec(fe, res);
                    537:                break;
                    538:         case 0x38:             // FCMP
                    539:                CYCLE(33);
                    540:                res = fpu_cmp(fe);
                    541:                discard_result = 1;
                    542:                break;
                    543:         case 0x3a:             // FTST
                    544:                CYCLE(33);
                    545:                res = &fe->fe_f2;
                    546:                discard_result = 1;
                    547:                break;
                    548: 
                    549:         default:
                    550:                // 不当命令
                    551:                fpu_op_illg2(cpu);
                    552:                return;
                    553:        }
                    554: 
                    555:        assert(res);
                    556:        if (!discard_result) {
                    557:                fpu_implode(fe, res, FTYPE_EXT, &RegFP(dstnum * 3));
                    558:        }
                    559:        fpu_upd_fpsr(fe, res);
                    560:        fpu_upd_excp(fe);
                    561: }
                    562: 
                    563: // FMOVECR
                    564: void
                    565: fpu_op_fmovecr(m68kcpu *cpu)
                    566: {
                    567:        CYCLE(29);
                    568: 
                    569:        struct fpemu *fe = &cpu->fe;
                    570:        uint offset = (RegIR2 & 0x7f);
                    571:        uint dstnum = (RegIR2 >> 7) & 7;
                    572: 
                    573:        fpu_const(&fe->fe_f3, offset);
                    574:        fpu_implode(fe, &fe->fe_f3, FTYPE_EXT, &RegFP(dstnum * 3));
                    575:        fpu_upd_fpsr(fe, &fe->fe_f3);
                    576:        fpu_upd_excp(fe);
                    577: }
                    578: 
                    579: // FMOVE.B FPn,<ea>
                    580: // cf. 68000PRM.pdf p378 (5-76)
                    581: void
                    582: fpu_op_fmove_b_mem(m68kcpu *cpu)
                    583: {
                    584:        struct fpemu *fe = &cpu->fe;
                    585:        uint mr = RegIR & 0x3f;
                    586:        uint srcnum = (RegIR2 >> 7) & 7;
                    587:        uint32 ea;
                    588:        uint32 data;
                    589: 
                    590:        fpu_explode(fe, &fe->fe_f3, FTYPE_EXT, &RegFP(srcnum * 3));
                    591:        fpu_implode(fe, &fe->fe_f3, FTYPE_LNG, &data);
                    592:        if ((int32)data < INT8_MIN || (int32)data > INT8_MAX) {
                    593:                RegFPSR |= FPSR_OPERR | FPSR_AIOP;
                    594:        }
                    595: 
                    596:        if (mr < 8) {   // Dn
                    597:                CYCLE(100-2);
                    598:                RegD(mr) &= 0xffffff00;
                    599:                RegD(mr) |= (uint8)data;
                    600:        } else {
                    601:                CYCLE(100);
                    602:                ea = cea_fpu(cpu, 1);
                    603:                m68030_write_8(cpu, ea, (uint8)data);
                    604:        }
                    605: }
                    606: 
                    607: // FMOVE.W FPn,<ea>
                    608: // cf. 68000PRM.pdf p378 (5-76)
                    609: void
                    610: fpu_op_fmove_w_mem(m68kcpu *cpu)
                    611: {
                    612:        struct fpemu *fe = &cpu->fe;
                    613:        uint mr = RegIR & 0x3f;
                    614:        uint srcnum = (RegIR2 >> 7) & 7;
                    615:        uint32 ea;
                    616:        uint32 data;
                    617: 
                    618:        fpu_explode(fe, &fe->fe_f3, FTYPE_EXT, &RegFP(srcnum * 3));
                    619:        fpu_implode(fe, &fe->fe_f3, FTYPE_LNG, &data);
                    620:        if ((int32)data < INT16_MIN || (int32)data > INT16_MAX) {
                    621:                RegFPSR |= FPSR_OPERR | FPSR_AIOP;
                    622:        }
                    623: 
                    624:        if (mr < 8) {   // Dn
                    625:                CYCLE(100-2);
                    626:                RegD(mr) &= 0xffff0000;
                    627:                RegD(mr) |= (uint16)data;
                    628:        } else {
                    629:                CYCLE(100);
                    630:                ea = cea_fpu(cpu, 2);
                    631:                m68030_write_16(cpu, ea, (uint16)data);
                    632:        }
                    633: }
                    634: 
                    635: // FMOVE.L FPn,<ea>
                    636: // cf. 68000PRM.pdf p378 (5-76)
                    637: void
                    638: fpu_op_fmove_l_mem(m68kcpu *cpu)
                    639: {
                    640:        struct fpemu *fe = &cpu->fe;
                    641:        uint mr = RegIR & 0x3f;
                    642:        uint srcnum = (RegIR2 >> 7) & 7;
                    643:        uint32 ea;
                    644:        uint32 data;
                    645: 
                    646:        fpu_explode(fe, &fe->fe_f3, FTYPE_EXT, &RegFP(srcnum * 3));
                    647:        fpu_implode(fe, &fe->fe_f3, FTYPE_LNG, &data);
                    648:        // XXX オーバーフローチェック
                    649: 
                    650:        if (mr < 8) {   // Dn
                    651:                CYCLE(100-2);
                    652:                RegD(mr) = data;
                    653:        } else {
                    654:                CYCLE(100);
                    655:                ea = cea_fpu(cpu, 4);
                    656:                m68030_write_32(cpu, ea, data);
                    657:        }
                    658: }
                    659: 
                    660: // FMOVE.S FPn,<ea>
                    661: // cf. 68000PRM.pdf p378 (5-76)
                    662: void
                    663: fpu_op_fmove_s_mem(m68kcpu *cpu)
                    664: {
                    665:        struct fpemu *fe = &cpu->fe;
                    666:        uint mr = RegIR & 0x3f;
                    667:        uint srcnum = (RegIR2 >> 7) & 7;
                    668:        uint32 ea;
                    669:        uint32 data;
                    670: 
                    671:        fpu_explode(fe, &fe->fe_f3, FTYPE_EXT, &RegFP(srcnum * 3));
                    672:        fpu_implode(fe, &fe->fe_f3, FTYPE_SNG, &data);
                    673: 
                    674:        if (mr < 8) {   // Dn
                    675:                CYCLE(80-2);
                    676:                RegD(mr) = data;
                    677:        } else {
                    678:                CYCLE(80);
                    679:                ea = cea_fpu(cpu, 4);
                    680:                m68030_write_32(cpu, ea, data);
                    681:        }
                    682: }
                    683: 
                    684: // FMOVE.D FPn,<ea>
                    685: // cf. 68000PRM.pdf p378 (5-76)
                    686: void
                    687: fpu_op_fmove_d_mem(m68kcpu *cpu)
                    688: {
                    689:        CYCLE(86);
                    690: 
                    691:        struct fpemu *fe = &cpu->fe;
                    692:        uint srcnum = (RegIR2 >> 7) & 7;
                    693:        uint32 ea;
                    694:        uint32 data[2];
                    695: 
                    696:        fpu_explode(fe, &fe->fe_f3, FTYPE_EXT, &RegFP(srcnum * 3));
                    697:        fpu_implode(fe, &fe->fe_f3, FTYPE_DBL, data);
                    698: 
                    699:        ea = cea_fpu(cpu, 8);
                    700:        m68030_write_64(cpu, ea, data);
                    701: }
                    702: 
                    703: // FMOVE.X FPn,<ea>
                    704: // cf. 68000PRM.pdf p378 (5-76)
                    705: void
                    706: fpu_op_fmove_x_mem(m68kcpu *cpu)
                    707: {
                    708:        CYCLE(72);
                    709: 
                    710:        uint srcnum = (RegIR2 >> 7) & 7;
                    711:        uint32 ea;
                    712: 
                    713:        ea = cea_fpu(cpu, 12);
                    714:        m68030_write_96(cpu, ea, &RegFP(srcnum * 3));
                    715: }
                    716: 
                    717: // FMOVE.P FPn,<ea>
                    718: // cf. 68000PRM.pdf p378 (5-76)
                    719: void
                    720: fpu_op_fmove_p_mem(m68kcpu *cpu)
                    721: {
                    722:        struct fpemu *fe = &cpu->fe;
                    723:        uint srcnum = (RegIR2 >> 7) & 7;
                    724:        uint32 ea;
                    725:        uint32 data[3];
                    726:        uint32 k;
                    727: 
                    728:        if ((RegIR2 & 0x1000)) {
                    729:                // dynamic k-factor
                    730:                CYCLE(1996+14);
                    731:                k = RegD((RegIR2 >> 4) & 7);
                    732:        } else {
                    733:                // static k-factor
                    734:                CYCLE(1996);
                    735:                k = RegIR2;
                    736:        }
                    737:        // k は7ビット符号付き数
                    738:        k &= 0x7f;
                    739:        if ((k & 0x40)) {
                    740:                k = (int32)(int8)(k | 0x80);
                    741:        }
                    742: 
                    743:        fpu_explode(fe, &fe->fe_f3, FTYPE_EXT, &RegFP(srcnum * 3));
                    744:        fpu_ftop(fe, &fe->fe_f3, data, k);
                    745: 
                    746:        ea = cea_fpu(cpu, 12);
                    747:        m68030_write_96(cpu, ea, data);
                    748: }
                    749: 
                    750: // FMOVEM.L <ea>,<ctllist>
                    751: // 1111 ccc 000 mmmrrr | 10D RRR 0000 000000
                    752: //  D=0: <ea> to FPctl
                    753: //  RRR: register list
                    754: void
                    755: fpu_op_fmovem_ea2ctl(m68kcpu *cpu)
                    756: {
                    757:        uint mr = RegIR & 0x3f;
                    758:        uint reglist = (RegIR2 >> 10) & 7;
                    759:        int count;
                    760:        uint32 ea;
                    761:        uint32 src[3];
                    762:        int i;
                    763: 
                    764:        //                      cache case      worst case
                    765:        // FMOVE  Rn,FPc                28                      31
                    766:        // FMOVE  <ea>,FPc              33                      36
                    767:        // FMOVE  #imm,FPc              30                      31
                    768:        // FMOVEM <ea>,FPcs             27+6n           30+6n
                    769:        // FMOVEM #imm,FPcs             25+6n           29+6n
                    770:        //
                    771:        // FMOVE #imm と FMOVEM #imm (n==1) は cache case が 1クロックだけ違う
                    772:        // ようだけどもう無視する。
                    773: 
                    774:        // 転送するレジスタ数
                    775:        // ただし nofpc は FPIAR とみなされるようだ。see exp/fmovem.php
                    776:        if (reglist == 0)
                    777:                reglist = 1;
                    778:        count = __builtin_popcount(reglist);
                    779: 
                    780:        if (mr < 8) {                           // Dn
                    781:                CYCLE2(28, 31);
                    782:                // 対データレジスタは転送数 1 のみ有効
                    783:                if (count > 1) {
                    784:                        fpu_op_illg2(cpu);
                    785:                        return;
                    786:                }
                    787:                src[0] = RegR(mr);
                    788: 
                    789:        } else if (mr < 16) {           // An
                    790:                CYCLE2(28, 31);
                    791:                // 対アドレスレジスタは FPIAR のみ有効
                    792:                if (reglist != 1) {
                    793:                        fpu_op_illg2(cpu);
                    794:                        return;
                    795:                }
                    796:                src[0] = RegR(mr);
                    797: 
                    798:        } else if (mr < 0x3c) {         // 対メモリ
                    799:                CYCLE2(28, 30);
                    800:                CYCLE(count * 6);
                    801: 
                    802:                // EA を取得。
                    803:                // -(An) の時も先にレジスタ数分一気に減算して、そこからプラス方向に
                    804:                // 読み込んでいくので、ロジックは全部同じになる。
                    805:                // (68000PRM.pdf p393)
                    806:                ea = cea_fpu(cpu, count * 4);
                    807:                for (i = 0; i < count; i++) {
                    808:                        src[i] = m68030_read_32(cpu, ea);
                    809:                        ea += 4;
                    810:                }
                    811: 
                    812:        } else if (mr == 0x3c) {        // #imm
                    813:                CYCLE2(25, 29);
                    814:                CYCLE(count * 6);
                    815: 
                    816:                for (i = 0; i < count; i++) {
                    817:                        src[i] = m68030_fetch_32(cpu);
                    818:                }
                    819: 
                    820:        } else {
                    821:                fpu_op_illg2(cpu);
                    822:                return;
                    823:        }
                    824: 
                    825:        // 該当レジスタへ読み込み
                    826:        i = 0;
                    827:        if ((reglist & 4)) {
                    828:                RegFPCR = src[i++] & M68K_FPCR_MASK;
                    829:        }
                    830:        if ((reglist & 2)) {
                    831:                RegFPSR = src[i++] & M68K_FPSR_MASK;
                    832:        }
                    833:        if ((reglist & 1)) {
                    834:                RegFPIAR = src[i++];
                    835:        }
                    836: }
                    837: 
                    838: // FMOVEM.L <ctllist>,<ea>
                    839: // 1111 ccc 000 mmmrrr | 10D RRR 0000 000000
                    840: //  D=1: FPctl to <ea>
                    841: //  RRR: register list
                    842: void
                    843: fpu_op_fmovem_ctl2ea(m68kcpu *cpu)
                    844: {
                    845:        uint mr = RegIR & 0x3f;
                    846:        uint reglist = (RegIR2 >> 10) & 7;
                    847:        int count;
                    848:        uint32 ea;
                    849: 
                    850:        //                      cache case      worst case
                    851:        // FMOVE  FPc,Rn                31                      34
                    852:        // FMOVE  FPc,<ea>              33                      36
                    853:        // FMOVEM FPcs,<ea>             27+6n           30+6n
                    854: 
                    855:        // 転送するレジスタ数
                    856:        // ただし nofpc は FPIAR とみなされるようだ。see exp/fmovem.php
                    857:        if (reglist == 0)
                    858:                reglist = 1;
                    859:        count = __builtin_popcount(reglist);
                    860: 
                    861:        if (mr < 8) {                   // Dn
                    862:                CYCLE2(31, 34);
                    863:                // 対データレジスタは転送数は 1 のみ有効
                    864:                if (count > 1) {
                    865:                        fpu_op_illg2(cpu);
                    866:                        return;
                    867:                }
                    868: 
                    869:                if ((reglist & 4)) {
                    870:                        RegR(mr) = RegFPCR;
                    871:                }
                    872:                if ((reglist & 2)) {
                    873:                        RegR(mr) = RegFPSR;
                    874:                }
                    875:                if ((reglist & 1)) {
                    876:                        RegR(mr) = RegFPIAR;
                    877:                }
                    878:                return;
                    879:        }
                    880:        if (mr < 16) {                  // An
                    881:                CYCLE2(31, 34);
                    882:                // 対アドレスレジスタは FPIAR のみ有効
                    883:                if (reglist != 1) {
                    884:                        fpu_op_illg2(cpu);
                    885:                        return;
                    886:                }
                    887:                RegR(mr) = RegFPIAR;
                    888:                return;
                    889:        }
                    890:        if (mr >= 0x3a) {               // #imm, d16(PC), (PC,IX)
                    891:                fpu_op_illg2(cpu);
                    892:                return;
                    893:        }
                    894: 
                    895:        // それ以外、対メモリの場合。
                    896:        CYCLE2(27, 30);
                    897:        CYCLE(count * 6);
                    898: 
                    899:        // EA を取得して...
                    900:        ea = cea_fpu(cpu, count * 4);
                    901:        // 該当レジスタをメモリへ書き出し
                    902:        if ((reglist & 4)) {
                    903:                m68030_write_32(cpu, ea, RegFPCR);
                    904:                ea += 4;
                    905:        }
                    906:        if ((reglist & 2)) {
                    907:                m68030_write_32(cpu, ea, RegFPSR);
                    908:                ea += 4;
                    909:        }
                    910:        if ((reglist & 1)) {
                    911:                m68030_write_32(cpu, ea, RegFPIAR);
                    912:                ea += 4;
                    913:        }
                    914: }
                    915: 
                    916: // FMOVEM.X <ea>,<reglist>
                    917: // FMOVEM.X <ea>,Dn
                    918: // 1111 ccc 000 mmmrrr | 11D MM000 RRRRRRRR
                    919: // D=0: <ea> to FPn
                    920: void
                    921: fpu_op_fmovem_ea2reg(m68kcpu *cpu)
                    922: {
                    923:        uint mr = RegIR & 0x3f;
                    924:        bool predec = !(RegIR2 & 0x1000);
                    925:        bool dynamic = (RegIR2 & 0x0800);
                    926:        uint8 reglist = RegIR2 & 0xff;
                    927:        int i;
                    928:        uint32 ea;
                    929: 
                    930:        //                      cache   worst
                    931:        // FMOVEM.X <ea>,<list> 35+23n  38+23n
                    932:        // FMOVEM.X <ea>,Dn             49+23n  52+23n
                    933: 
                    934:        // 不当パターンを弾く
                    935:        switch (mr) {
                    936:         case 0x00 ... 0x07:            // Dn
                    937:         case 0x08 ... 0x0f:            // An
                    938:         case 0x20 ... 0x27:            // -(An)
                    939:         case 0x3c:                                     // #imm
                    940:         case 0x3d ... 0x3f:
                    941:                fpu_op_illg2(cpu);
                    942:                return;
                    943:        }
                    944: 
                    945:        // ダイナミックモードなら reglist の %0nnn0000 にレジスタ番号が
                    946:        // 入っているので、この Dn の下位8ビットを取り出す。レジスタ番号以外の
                    947:        // ビットは無視、Dn の上位ビットも無視。
                    948:        // ついでにここでベースクロックを記録
                    949:        if (dynamic) {
                    950:                reglist = RegD((reglist >> 4) & 7);
                    951:                CYCLE2(49, 52);
                    952:        } else {
                    953:                CYCLE2(35, 38);
                    954:        }
                    955: 
                    956:        // EA は最初に一度取得しておいて...
                    957:        int count = __builtin_popcount(reglist);
                    958:        ea = cea_fpu(cpu, 12 * count);
                    959: 
                    960:        if (predec) {
                    961:                // predec ならビット7から FP7..FP0 で、bit7 側から順に転送。
                    962:                for (i = 7; reglist; reglist <<=1, i--) {
                    963:                        if ((int8)reglist < 0) {
                    964:                                m68030_read_96(cpu, ea, &RegFP(i * 3));
                    965:                                ea += 12;
                    966:                        }
                    967:                }
                    968:        } else {
                    969:                // ctrl/postinc ならビット7から FP0..FP7 で、bit7 側から順に転送。
                    970:                for (i = 0; reglist; reglist <<= 1, i++) {
                    971:                        if ((int8)reglist < 0) {
                    972:                                m68030_read_96(cpu, ea, &RegFP(i * 3));
                    973:                                ea += 12;
                    974:                        }
                    975:                }
                    976:        }
                    977:        CYCLE(23 * count);
                    978: }
                    979: 
                    980: // FMOVEM.X <reglist>,<ea>
                    981: // FMOVEM.X Dn,<ea>
                    982: // 1111 ccc 000 mmmrrr | 11D MM000 RRRRRRRR
                    983: // D=1: FPn to <ea>
                    984: void
                    985: fpu_op_fmovem_reg2ea(m68kcpu *cpu)
                    986: {
                    987:        uint mr = RegIR & 0x3f;
                    988:        bool anpd = false;                                      // 第1ワード EA が -(An) か
                    989:        bool predec = !(RegIR2 & 0x1000);       // 第2ワードの mode が predec か
                    990:        bool dynamic = (RegIR2 & 0x0800);
                    991:        uint8 reglist = RegIR2 & 0xff;
                    992:        int i;
                    993:        uint32 ea;
                    994: 
                    995:        //                      cache   worst
                    996:        // FMOVEM.X <list>,<ea> 37+25n  40+25n
                    997:        // FMOVEM.X Dn,<ea>             51+25n  54+25n
                    998: 
                    999:        // 不当パターンを弾く
                   1000:        // ついでに -(An) だけ覚えておく
                   1001:        switch (mr) {
                   1002:         case 0x00 ... 0x07:            // Dn
                   1003:         case 0x08 ... 0x0f:            // An
                   1004:         case 0x18 ... 0x1f:            // (An)+
                   1005:         case 0x3a:                                     // d16(PC)
                   1006:         case 0x3b:                                     // (PC,IX)
                   1007:         case 0x3c:                                     // #imm
                   1008:         case 0x3d ... 0x3f:
                   1009:                fpu_op_illg2(cpu);
                   1010:                return;
                   1011:         case 0x20 ... 0x27:            // -(An)
                   1012:                anpd = true;
                   1013:                break;
                   1014:        }
                   1015: 
                   1016:        // ダイナミックモードなら reglist の %0nnn0000 にレジスタ番号が
                   1017:        // 入っているので、この Dn の下位8ビットを取り出す。レジスタ番号以外の
                   1018:        // ビットは無視、Dn の上位ビットも無視。
                   1019:        // ついでにここでベースクロックを記録
                   1020:        if (dynamic) {
                   1021:                reglist = RegD((reglist >> 4) & 7);
                   1022:                CYCLE2(51, 54);
                   1023:        } else {
                   1024:                CYCLE2(37, 40);
                   1025:        }
                   1026: 
                   1027:        int count = __builtin_popcount(reglist);
                   1028: 
                   1029:        // -(An) の時だけ EA を別処理。
                   1030:        // 現状の cea_fpu() は -(An) の時、巻き戻し用のレジスタを保存し
                   1031:        // デクリメントしたアドレスを返すまでを一度に行う便利関数だが、
                   1032:        // FMOVEM fpn,-(An) は最初に巻き戻し用レジスタを保存し (これは命令先頭
                   1033:        // に戻るためなので最初の1回だけ)、その後レジスタ1つずつ 12バイトを
                   1034:        // プリデクリメントしながら格納していく必要がある (この順に実行しないと
                   1035:        // バスエラーの原因箇所が異なってしまう)。
                   1036:        // そのため cea_fpu() がそのまま使えないので、ここだけ独自対応する。
                   1037:        // cea_fpu() は1命令中で EA の取得が1回である前提のあくまで便利関数
                   1038:        // なので、例外的である FMOVEM は仕方がない。
                   1039:        if (anpd) {
                   1040:                CYCLE(6);
                   1041:                uint n = eanum(RegIR);
                   1042:                m68030_save_reg_pd(cpu, n);
                   1043: 
                   1044:                if (predec) {
                   1045:                        // predec ならビット7から FP7..FP0 で、bit7 側から順に転送。
                   1046:                        for (i = 7; reglist; reglist <<= 1, i--) {
                   1047:                                if ((int8)reglist < 0) {
                   1048:                                        RegA(n) -= 12;
                   1049:                                        m68030_write_96(cpu, RegA(n), &RegFP(i * 3));
                   1050:                                }
                   1051:                        }
                   1052:                } else {
                   1053:                        // ctrl/postinc ならビット7から FP0..FP7 で、bit7 側から順に転送。
                   1054:                        for (i = 0; reglist; reglist <<= 1, i++) {
                   1055:                                if ((int8)reglist < 0) {
                   1056:                                        RegA(n) -= 12;
                   1057:                                        m68030_write_96(cpu, RegA(n), &RegFP(i * 3));
                   1058:                                }
                   1059:                        }
                   1060:                }
                   1061:        } else {
                   1062:                // -(An) 以外は EA を最初に一度計算しておく方法が使える
                   1063:                ea = cea_fpu(cpu, 12 * count);
                   1064: 
                   1065:                if (predec) {
                   1066:                        // predec ならビット7から FP7..FP0 で、bit7 側から順に転送。
                   1067:                        for (i = 7; reglist; reglist <<= 1, i--) {
                   1068:                                if ((int8)reglist < 0) {
                   1069:                                        m68030_write_96(cpu, ea, &RegFP(i * 3));
                   1070:                                        ea += 12;
                   1071:                                }
                   1072:                        }
                   1073:                } else {
                   1074:                        // ctrl/postinc ならビット7から FP0..FP7 で、bit7 側から順に転送。
                   1075:                        for (i = 0; reglist; reglist <<= 1, i++) {
                   1076:                                if ((int8)reglist < 0) {
                   1077:                                        m68030_write_96(cpu, ea, &RegFP(i * 3));
                   1078:                                        ea += 12;
                   1079:                                }
                   1080:                        }
                   1081:                }
                   1082:        }
                   1083:        CYCLE(25 * count);
                   1084: }
                   1085: 
                   1086: // FScc.B <ea>
                   1087: // 1111 ccc 001 mmmrrr | 0000 000 000 CCCCCC
                   1088: void
                   1089: fpu_op_fscc(m68kcpu *cpu)
                   1090: {
                   1091:        struct fpemu *fe = &cpu->fe;
                   1092:        uint mr = RegIR & 0x3f;
                   1093:        uint mm = eamode(RegIR);
                   1094:        uint rr = eanum(RegIR);
                   1095:        uint cond = RegIR2 & 0x3f;
                   1096:        int data;
                   1097:        uint32 ea;
                   1098: 
                   1099:        //                      cache   worst
                   1100:        // FScc.B Dn                    18              21
                   1101:        // FScc.B (An)+/-(An)   22              25              ; condition is true
                   1102:        // FScc.B (An)+/-(An)   21              24              ; condition is false
                   1103:        // FScc.B <ea>                  20              23
                   1104: 
                   1105:        if (cond > 0x1f) {
                   1106:                fpu_op_illg2(cpu);
                   1107:                return;
                   1108:        }
                   1109: 
                   1110:        data = (test_cc(fe, cond) == -1) ? 0xff : 0x00;
                   1111: 
                   1112:        switch (mm) {
                   1113:         case 0:        // Dn
                   1114:                CYCLE2(18, 21);
                   1115:                RegD(rr) &= 0xffffff00;
                   1116:                RegD(rr) |= data;
                   1117:                return;
                   1118: 
                   1119:         case 3:        // (An)+
                   1120:         case 4:        // -(An)
                   1121:                // ここだけ他のメモリ系 EA とはクロックが違うし、
                   1122:                // 条件の成立可否でも違う。
                   1123:                if (data == 0x00) {
                   1124:                        CYCLE2(21, 24);
                   1125:                } else {
                   1126:                        CYCLE2(22, 25);
                   1127:                }
                   1128:                break;
                   1129:         case 7:
                   1130:                if (mr == 0x38 || mr == 0x39) { // Abs.W, Abs.L
                   1131:                } else {
                   1132:                        fpu_op_illg2(cpu);
                   1133:                        return;
                   1134:                }
                   1135:                FALLTHROUGH;
                   1136:         default:
                   1137:                CYCLE2(20, 23);
                   1138:                break;
                   1139:        }
                   1140: 
                   1141:        ea = cea_fpu(cpu, 1);
                   1142:        m68030_write_8(cpu, ea, data);
                   1143: }
                   1144: 
                   1145: // FDBcc Dn,<label>
                   1146: // 1111 ccc 001 001rrr | 0000 000 000 CCCCCC | <16bit disp>
                   1147: void
                   1148: fpu_op_fdbcc(m68kcpu *cpu)
                   1149: {
                   1150:        struct fpemu *fe = &cpu->fe;
                   1151:        uint rr = RegIR & 7;
                   1152:        uint cond = RegIR2 & 0x3f;
                   1153: 
                   1154:        if (cond > 0x1f) {
                   1155:                fpu_op_illg2(cpu);
                   1156:                return;
                   1157:        }
                   1158: 
                   1159:        if (test_cc(fe, cond) == -1) {
                   1160:                // 真なら何もしない。disp を読み飛ばして次へ
                   1161:                CYCLE2(20, 24);
                   1162:                m68030_fetch_16(cpu);
                   1163:        } else {
                   1164:                // 偽の場合
                   1165:                uint16 data = RegD(rr) - 1;
                   1166:                RegD(rr) = (RegD(rr) & 0xffff0000) | data;
                   1167: 
                   1168:                if (data == 0xffff) {
                   1169:                        // ループ終了。disp を読み飛ばす
                   1170:                        CYCLE2(24, 32);
                   1171:                        m68030_fetch_16(cpu);
                   1172:                } else {
                   1173:                        // 計算に使う PC は FDBcc 命令+2 のところらしい
                   1174:                        CYCLE2(20, 26);
                   1175:                        uint32 pc = RegPPC + 2;
                   1176:                        int32 disp = (int32)(int16)m68030_fetch_16(cpu);
                   1177:                        m68030_jump(cpu, pc + disp);
                   1178:                }
                   1179:        }
                   1180: }
                   1181: 
                   1182: // FTRAPcc.W #<data>
                   1183: void
                   1184: fpu_op_ftrapcc_w(m68kcpu *cpu)
                   1185: {
                   1186:        struct fpemu *fe = &cpu->fe;
                   1187:        uint cond = RegIR2 & 0x3f;
                   1188: 
                   1189:        if (cond > 0x1f) {
                   1190:                fpu_op_illg2(cpu);
                   1191:                return;
                   1192:        }
                   1193: 
                   1194:        if (test_cc(fe, cond) == -1) {
                   1195:                // TODO: 例外発生
                   1196:                CYCLE2(41, 45);
                   1197:                PANIC("unimpl ftrapcc_w at %08X", RegPPC);
                   1198:        } else {
                   1199:                // 即値は読み捨て
                   1200:                CYCLE2(20, 23);
                   1201:                m68030_fetch_16(cpu);
                   1202:        }
                   1203: }
                   1204: 
                   1205: // FTRAPcc.L #<data>
                   1206: void
                   1207: fpu_op_ftrapcc_l(m68kcpu *cpu)
                   1208: {
                   1209:        struct fpemu *fe = &cpu->fe;
                   1210:        uint cond = RegIR2 & 0x3f;
                   1211: 
                   1212:        if (cond > 0x1f) {
                   1213:                fpu_op_illg2(cpu);
                   1214:                return;
                   1215:        }
                   1216: 
                   1217:        if (test_cc(fe, cond) == -1) {
                   1218:                // TODO: 例外発生
                   1219:                CYCLE2(43, 52);
                   1220:                PANIC("unimpl ftrapcc_l at %08X", RegPPC);
                   1221:        } else {
                   1222:                // 即値は読み捨て
                   1223:                CYCLE2(22, 27);
                   1224:                m68030_fetch_32(cpu);
                   1225:        }
                   1226: }
                   1227: 
                   1228: // FTRAPcc
                   1229: void
                   1230: fpu_op_ftrapcc(m68kcpu *cpu)
                   1231: {
                   1232:        struct fpemu *fe = &cpu->fe;
                   1233:        uint cond = RegIR2 & 0x3f;
                   1234: 
                   1235:        if (cond > 0x1f) {
                   1236:                fpu_op_illg2(cpu);
                   1237:                return;
                   1238:        }
                   1239: 
                   1240:        if (test_cc(fe, cond) == -1) {
                   1241:                // TODO: 例外発生
                   1242:                CYCLE2(39, 47);
                   1243:                PANIC("unimpl ftrapcc_l at %08X", RegPPC);
                   1244:        } else {
                   1245:                // 即値はないので、何もしない
                   1246:                CYCLE2(18, 22);
                   1247:        }
                   1248: }
                   1249: 
                   1250: // FBcc.W <label>
                   1251: // 1111 ccc 01S CCCCCC | <16bit disp>
                   1252: // S=0: 16bit disp
                   1253: //
                   1254: // FNOP
                   1255: // 1111 ccc 010 000000 | 0000 0000 0000 0000
                   1256: void
                   1257: fpu_op_fbcc_w(m68kcpu *cpu)
                   1258: {
                   1259:        struct fpemu *fe = &cpu->fe;
                   1260:        uint cond = RegIR & 0x3f;
                   1261: 
                   1262:        if (test_cc(fe, cond) == -1) {
                   1263:                CYCLE2(20, 23);
                   1264:                uint32 pc = RegPC;
                   1265:                int32 disp = (int32)(int16)m68030_fetch_16(cpu);
                   1266:                m68030_jump(cpu, pc + disp);
                   1267:        } else {
                   1268:                // disp を読み飛ばす
                   1269:                CYCLE2(18, 19);
                   1270:                m68030_fetch_16(cpu);
                   1271:        }
                   1272: }
                   1273: 
                   1274: // FBcc.L <label>
                   1275: // 1111 ccc 01S CCCCCC | <32bit disp>
                   1276: // S=1: 32bit disp
                   1277: void
                   1278: fpu_op_fbcc_l(m68kcpu *cpu)
                   1279: {
                   1280:        struct fpemu *fe = &cpu->fe;
                   1281:        uint cond = RegIR & 0x3f;
                   1282: 
                   1283:        if (test_cc(fe, cond) == -1) {
                   1284:                CYCLE2(20, 23);
                   1285:                uint32 pc = RegPC;
                   1286:                int32 disp = (int32)m68030_fetch_32(cpu);
                   1287:                m68030_jump(cpu, pc + disp);
                   1288:        } else {
                   1289:                // disp を読み飛ばす
                   1290:                CYCLE2(18, 21);
                   1291:                m68030_fetch_32(cpu);
                   1292:        }
                   1293: }
                   1294: 
                   1295: // FSAVE の NULL フレーム (全機種共通で4バイト)
                   1296: static const uint32 fsave_frame_null[] = {
                   1297:        0,
                   1298: };
                   1299: 
                   1300: // FSAVE のアイドルフレーム (68881 は 0x1c = 28 バイト、 7ロングワード)
                   1301: static const uint32 fsave_frame_idle[] = {
                   1302:        0x1f180000,
                   1303:        0,
                   1304:        0,
                   1305:        0,
                   1306:        0,
                   1307:        0,
                   1308:        0x70000000,
                   1309: };
                   1310: 
                   1311: // FSAVE
                   1312: // スーパーバイザモードは判定済み
                   1313: void
                   1314: fpu_op_fsave(m68kcpu *cpu)
                   1315: {
                   1316:        uint mm = eamode(RegIR);
                   1317:        uint rr = eanum(RegIR);
                   1318:        uint32 ea;
                   1319:        const uint32 *frame;
                   1320:        int framelen;
                   1321: 
                   1322:        // XXX EA が -(An) の時 An が逐次減算て書いてあるソースきぼんぬ
                   1323: 
                   1324:        // フレームを選択
                   1325:        if (cpu->fpu_dirty == false) {
                   1326:                // NULL フレーム
                   1327:                CYCLE2(16, 18);
                   1328:                frame = fsave_frame_null;
                   1329:                framelen = countof(fsave_frame_null);
                   1330:        } else {
                   1331:                // IDLE フレーム
                   1332:                CYCLE2(52, 54); // XXX これは最小値らしいけど
                   1333:                frame = fsave_frame_idle;
                   1334:                framelen = countof(fsave_frame_idle);
                   1335:        }
                   1336: 
                   1337:        // EA は独自体系なのでここでべたに書く
                   1338:        switch (mm) {
                   1339:         case 2:        // (An)
                   1340:                ea = cea_anin(cpu, rr);
                   1341:                break;
                   1342:         case 4:        // -(An)
                   1343:                // これだけ処理が違うので、ここでやる
                   1344:                m68030_save_reg_pd(cpu, rr);
1.1.1.3   root     1345:                for (int i = framelen - 1; i >= 0; i--) {
1.1       root     1346:                        RegA(rr) -= 4;
                   1347:                        m68030_write_32(cpu, RegA(rr), frame[i]);
                   1348:                }
                   1349:                return;
                   1350: 
                   1351:         case 5:        // d16(An)
                   1352:                ea = cea_andi(cpu, rr);
                   1353:                break;
                   1354:         case 6:        // (An,IX)
                   1355:                ea = cea_anix(cpu, rr);
                   1356:                break;
                   1357:         case 7:
                   1358:                switch (rr) {
                   1359:                 case 0:        // Abs.W
                   1360:                        ea = cea_absw(cpu);
                   1361:                        break;
                   1362:                 case 1:        // Abs.L
                   1363:                        ea = cea_absl(cpu);
                   1364:                        break;
                   1365:                 default:
                   1366:                        fpu_op_illg(cpu);
                   1367:                        return;
                   1368:                }
                   1369:                break;
                   1370:         default:
                   1371:                fpu_op_illg(cpu);
                   1372:                return;
                   1373:        }
                   1374: 
                   1375:        // -(An) 以外の EA の場合
                   1376:        for (int i = 0; i < framelen; i++) {
                   1377:                m68030_write_32(cpu, ea, frame[i]);
                   1378:                ea += 4;
                   1379:        }
                   1380: }
                   1381: 
                   1382: // FRESTORE
                   1383: // スーパーバイザモードは判定済み
                   1384: void
                   1385: fpu_op_frestore(m68kcpu *cpu)
                   1386: {
                   1387:        uint mm = eamode(RegIR);
                   1388:        uint rr = eanum(RegIR);
                   1389:        uint32 ea;
                   1390:        uint32 data;
                   1391:        bool postinc;
                   1392: 
                   1393:        postinc = false;
                   1394:        // EA は独自体系なのでここでべたに書く
                   1395:        switch (mm) {
                   1396:         case 2:        // (An)
                   1397:                ea = cea_anin(cpu, rr);
                   1398:                break;
                   1399:         case 3:        // (An)+
                   1400:                ea = cea_anin(cpu, rr);
                   1401:                postinc = true;
                   1402:                break;
                   1403:         case 5:        // d16(An)
                   1404:                ea = cea_andi(cpu, rr);
                   1405:                break;
                   1406:         case 6:        // (An,IX)
                   1407:                ea = cea_anix(cpu, rr);
                   1408:                break;
                   1409:         case 7:
                   1410:                switch (rr) {
                   1411:                 case 0:        // Abs.W
                   1412:                        ea = cea_absw(cpu);
                   1413:                        break;
                   1414:                 case 1:        // Abs.L
                   1415:                        ea = cea_absl(cpu);
                   1416:                        break;
                   1417:                 case 2:        // d16(PC)
                   1418:                        ea = cea_pcdi(cpu);
                   1419:                        break;
                   1420:                 case 3:        // (PC,IX)
                   1421:                        ea = cea_pcix(cpu);
                   1422:                        break;
                   1423:                 default:
                   1424:                        fpu_op_illg(cpu);
                   1425:                        return;
                   1426:                }
                   1427:                break;
                   1428:         default:
                   1429:                fpu_op_illg(cpu);
                   1430:                return;
                   1431:        }
                   1432: 
                   1433:        // 1ロングワード読んでみる
                   1434:        data = m68030_read_32(cpu, ea);
                   1435:        ea += 4;
                   1436: 
                   1437:        if (data == 0) {
                   1438:                // NULL フレームなら、これ以上フレームはない。
                   1439:                CYCLE2(21, 22);
                   1440: 
                   1441:                // NULL フレームのリストアは FPU の状態をリセットする
                   1442:                fpu_reset(cpu);
                   1443:        } else {
                   1444:                // それ以外のフレームは先頭ロングワードから長さを取得。
                   1445:                // 先頭1ロングワードは $VVLL0000 で VV がバージョン(8bit)、
                   1446:                // LL が(自身を含まないこれ以降の)バイト数 (8bit) を示している。
                   1447:                // 現在の実装ではセーブ/リストアは何も実装していないので、
                   1448:                // 全部読み捨てる。
                   1449: 
                   1450:                // 実際にはフレーム種別によってサイクル数は変わるけど、ここでは
                   1451:                // FSAVE は NULL フレーム以外には IDLE フレームしか吐かないので
                   1452:                // IDLE フレームのサイクルだけでいい。
                   1453:                CYCLE2(57, 58);
                   1454: 
                   1455:                int len = (data >> 16) & 0xff;
                   1456:                len /= 4;
                   1457:                for (int i = 0; i < len; i++) {
                   1458:                        m68030_read_32(cpu, ea);
                   1459:                        ea += 4;
                   1460:                }
                   1461: 
                   1462:                cpu->fpu_dirty = true;
                   1463:        }
                   1464: 
                   1465:        // (An)+ なら書き戻し
                   1466:        if (postinc) {
                   1467:                RegA(rr) = ea;
                   1468:        }
                   1469: }

unix.superglobalmegacorp.com

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