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

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

unix.superglobalmegacorp.com

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