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

1.1     ! root        1: //
        !             2: // nono
        !             3: // Copyright (C) 2018 [email protected]
        !             4: //
        !             5: 
        !             6: #include "header.h"
        !             7: #include "m68030core.h"
        !             8: #include "m68030bus.h"
        !             9: #include "m68030excep.h"
        !            10: #include "m68030ea.h"
        !            11: #include "m68030fpu.h"
        !            12: 
        !            13: static void fgen(m68kcpu *);
        !            14: static void fpu_op_fmovecr(m68kcpu *);
        !            15: 
        !            16: // リセット用のレジスタ初期値
        !            17: struct fpframe initial_fpframe;
        !            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 フレームのリストア時に呼ばれる。
        !            43: void
        !            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ビット値を読み込む
        !           123: void
        !           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ビット値を読み込む
        !           131: void
        !           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)をメモリに書き込む
        !           140: void
        !           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)をメモリに書き込む
        !           148: void
        !           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: 
        !           156: // ソースを読み込みます。
        !           157: // 不当命令パターンなら false を返します。
        !           158: // size_id は SIZE_* です。
        !           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) にはクロック数はこう書いてあるので
        !           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
        !           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: {
        !           290:        cpulog(1, "FPU 不当命令 %04X", RegIR);
        !           291:        m68030_exception(cpu, M68K_EXCEP_FLINE);
        !           292: }
        !           293: 
        !           294: // FPU 不当命令 (2ワード目で確定)
        !           295: void
        !           296: fpu_op_illg2(m68kcpu *cpu)
        !           297: {
        !           298:        cpulog(1, "FPU 不当命令 %04X %04X", RegIR, RegIR2);
        !           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);
        !          1345:                for (int i = framelen; i >= 0; i--) {
        !          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.