Annotation of nono/m88xx0/m88100core.cpp, revision 1.1.1.11

1.1       root        1: //
                      2: // nono
1.1.1.2   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
                      7: #include "m88100.h"
                      8: #include "m88100excep.h"
                      9: #include "debugger.h"
1.1.1.11! root       10: #include "mpu88xx0.h"
1.1       root       11: 
                     12: #define OP_DEF(name)   void __CONCAT(m88kcpu::op_,name)()
                     13: #define OP_FUNC(name)  __CONCAT(op_,name)()
                     14: #include "m88100ops.cpp"
                     15: 
1.1.1.7   root       16: // 文字列を作る前にレベルを評価するためマクロ
                     17: #define cpulog(lv, fmt...)     do {    \
                     18:        if (__predict_false(gMPU->loglevel >= (lv))) {  \
                     19:                gMPU->putlogn(fmt);     \
                     20:        }       \
                     21: } while (0)
                     22: 
1.1.1.11! root       23: // 電源オン
1.1.1.8   root       24: void
                     25: m88kcpu::PowerOn()
                     26: {
1.1.1.11! root       27:        // サイクルを初期化。
        !            28:        used_cycle = 0;
        !            29: 
1.1.1.8   root       30:        // 履歴は電源オン時だけ初期化。
                     31:        // (LUNA88K は ROM が正常パスで CPU リセットを行ったりするので)
                     32:        exhist.Clear();
                     33:        brhist.Clear();
                     34: 
                     35:        // この後起きるリセット例外で xip を初期化する前に参照することになるので
                     36:        // これだけここでも初期化しておく。
                     37:        xip = 0;
                     38: }
                     39: 
1.1       root       40: // リセット例外のようなもの?
1.1.1.11! root       41: uint64
1.1.1.5   root       42: m88kcpu::Reset()
1.1       root       43: {
1.1.1.11! root       44:        uint64 cycle_start = used_cycle;
        !            45: 
1.1.1.8   root       46:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
                     47:        // リセット例外も発生時の XIP を記録する。(LUNA88K の ROM 1.20)
                     48:        exhist.AddEntry(xip | 1, 0, 0xfc000000 | 0);
                     49:        brhist.AddEntry(xip | 1, 0, 0xfc000000 | 0);
                     50:        // デバッガに通知 (例外ブレーク用)
                     51:        debugger_notify_exception(0);
                     52: 
1.1.1.5   root       53:        // 内部の割り込み状態をクリア
                     54:        intr_pending = 0;
1.1.1.11! root       55:        ChangeState(CPU_STATE_NORMAL);
        !            56: 
        !            57:        // 実際どこかは分からんけど PSR 設定の前にリセットしておきたい
        !            58:        cmmu[0].Reset();
        !            59:        cmmu[1].Reset();
1.1.1.4   root       60: 
                     61:        // Table 6-8 (p6-47)
1.1       root       62:        psr = 0x800003ff;
1.1.1.4   root       63:        // XXX ただし SFU1 は未実装なので下げておく
1.1       root       64:        psr &= ~PSR_SFD1;
                     65: 
1.1.1.2   root       66: #if defined(TEST_INTERRUPT)
1.1.1.4   root       67:        psr &= ~PSR_IND;
                     68:        psr &= ~PSR_SFRZ;
1.1       root       69: #endif
                     70: 
1.1.1.4   root       71:        SetPSR();
1.1.1.2   root       72: 
1.1.1.8   root       73:        fip = 0;
1.1.1.7   root       74: 
                     75:        // レジスタのうち明記されてるものをクリア。
                     76:        // 不定と明記されてるものはリセットでは触らないでおく。
                     77:        // scoreboard: cleared
1.1       root       78:        nip = 0;
                     79:        xip = 0;
1.1.1.4   root       80:        vbr = 0;
                     81:        fpecr = 0;
                     82:        fpcr = 0;
                     83:        fpsr = 0;
1.1.1.7   root       84:        // DMTx は bit0(Valid) をクリア。他は不定
                     85:        dmt0 &= ~DM_VALID;
                     86:        dmt1 &= ~DM_VALID;
                     87:        dmt2 &= ~DM_VALID;
1.1.1.4   root       88: 
1.1       root       89:        fetch();
1.1.1.11! root       90: 
        !            91:        return used_cycle - cycle_start;
1.1       root       92: }
                     93: 
1.1.1.11! root       94: // 1命令実行する。
        !            95: // 戻り値は消費したサイクル数。
        !            96: int
        !            97: m88kcpu::Exec()
1.1       root       98: {
1.1.1.11! root       99:        uint64 cycle_start = used_cycle;
1.1.1.5   root      100: 
1.1.1.11! root      101:        {
1.1       root      102:                // shift pipeline
                    103:                opX = opF;
                    104:                xip = nip;
                    105: 
                    106:                // prefetch next inst
                    107:                fetch();
                    108: 
                    109:                // この時点で実行しようとする命令が opX に入っている
                    110: 
                    111:                if (OpIsBusErr(opX)) {
                    112:                        // プリフェッチしていた命令がバスエラー
                    113:                        Exception(M88K_EXCEP_INST);
1.1.1.11! root      114:                        goto exit;
1.1       root      115:                }
                    116: 
                    117:                uint32 op12 = op32_to_12(opX);
                    118: 
                    119:                switch (op12) {
                    120: #include "m88100switch.inc"
                    121:                 default:
1.1.1.2   root      122:                        OP_FUNC(illegal);
                    123:                        break;
1.1       root      124:                }
                    125: 
1.1.1.11! root      126:                if (intr_pending && IsIntrEnable()) {
1.1.1.10  root      127:                        // 割り込み処理要求が来ていて、
                    128:                        // 直前の命令が割り込みを禁止していなければ割り込み
1.1.1.5   root      129:                        // XXX 実際は違う気がする
1.1.1.7   root      130:                        cpulog(4, "INTR take");
1.1.1.5   root      131:                        ExceptionCore(M88K_EXCEP_INTERRUPT, ExceptionKind::INTR);
1.1.1.11! root      132:                        goto exit;
1.1       root      133:                }
                    134: 
1.1.1.5   root      135:                used_cycle++;
1.1.1.2   root      136: 
1.1       root      137:        }
                    138: 
1.1.1.6   root      139:  exit:
1.1.1.11! root      140:        return used_cycle - cycle_start;
1.1.1.5   root      141: }
                    142: 
1.1.1.11! root      143: // STOP 状態で 1 命令実行する。
        !           144: // 戻り値は消費したサイクル数。
        !           145: int
        !           146: m88kcpu::ExecPseudoStop()
1.1       root      147: {
1.1.1.11! root      148:        instruction_in_stop++;
        !           149:        if (instruction_in_stop > 4) {
        !           150:                ChangeState(CPU_STATE_NORMAL);
        !           151:        }
1.1       root      152: 
1.1.1.11! root      153:        return Exec();
1.1.1.5   root      154: }
                    155: 
1.1.1.11! root      156: 
1.1       root      157: // 通常の例外。
1.1.1.2   root      158: // DataAccessException, エラー、割り込み、TRAP からは使わない。
1.1       root      159: // vec はベクタ番号。
                    160: void
                    161: m88kcpu::Exception(int vec)
                    162: {
                    163:        ExceptionCore(vec, ExceptionKind::NORMAL);
                    164: }
                    165: 
                    166: // 例外処理コア部分
                    167: // vec はベクタ番号。
                    168: void
                    169: m88kcpu::ExceptionCore(int vec, ExceptionKind cause)
                    170: {
1.1.1.4   root      171:        uint syscall = 0;
                    172: 
1.1.1.3   root      173:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
1.1.1.4   root      174:        // OpenBSD システムコールなら番号もついでに記録。
                    175:        // システムコール番号は tb0 発行時点で r13 にセットされている。
                    176:        // ただし 0 番は syscall(2) (間接システムコール) で、実際の番号は r2。
                    177:        // 198番 __syscall(2) だと r2:r3 (なので実質 r3)。
                    178:        if (vec == 450) {
                    179:                syscall = r[13];
                    180:                if (syscall == 0) {
                    181:                        syscall = r[2];
                    182:                } else if (syscall == 198) {
                    183:                        syscall = r[3];
                    184:                }
                    185:                syscall &= 0xfff;
                    186:        }
1.1.1.5   root      187:        uint32 from = xip | (IsSuper() ? 1 : 0);
                    188:        uint32 inst = 0xfc000000 | (syscall << 12) | vec;
                    189:        exhist.AddEntry(from, 0, inst);
                    190:        brhist.AddEntry(from, 0, inst);
1.1.1.3   root      191:        // デバッガに通知 (例外ブレーク用)
1.1.1.4   root      192:        debugger_notify_exception(vec);
                    193: 
                    194:        // 命令中で起きる例外はとりあえず全部2クロック追加? (Table.7-5)
                    195:        if (cause != ExceptionKind::INTR) {
1.1.1.5   root      196:                AddCycle(2);
1.1.1.4   root      197:        }
1.1.1.3   root      198: 
1.1       root      199:        if (psr & PSR_SFRZ) {
                    200:                if (cause != ExceptionKind::TRAP) {
1.1.1.7   root      201:                        cpulog(2, "SFRZ Error Exception");
1.1       root      202:                        vec = M88K_EXCEP_ERROR;
                    203:                        cause = ExceptionKind::ERROR;
                    204:                }
                    205:        } else {
1.1.1.7   root      206:                cpulog(2, "Exception %x", vec);
1.1.1.2   root      207:                if (vec != 1) {
1.1.1.7   root      208:                        cpulog(1, "Exception %x x=%x n=%x f=%x", vec, xip, nip, fip);
1.1.1.2   root      209:                }
1.1       root      210:                sxip = xip;
                    211:                snip = nip;
1.1.1.7   root      212:                sfip = fip;
1.1       root      213: 
                    214:                sxip |= SIP_V;
                    215:                snip |= SIP_V;
1.1.1.4   root      216:                sfip |= SIP_V;
1.1       root      217: 
                    218:                if (OpIsBusErr(opX)) {
                    219:                        sxip |= SIP_E;  // E bit
                    220:                }
                    221:                if (OpIsBusErr(opF)) {
                    222:                        snip |= SIP_E;  // E bit
                    223:                }
                    224: 
                    225:                if (vec == M88K_EXCEP_UNIMPL_OP) {
                    226:                        sxip &= ~SIP_V;
                    227:                }
                    228:        }
                    229: 
1.1.1.2   root      230:        if (cause != ExceptionKind::DATA) {
                    231:                // データアクセス例外以外は、
                    232:                // データパイプラインはフラッシュ状態とする。
                    233:                // ほんとうは違う。かも。
                    234:                dmt0 = 0;
                    235:        } else {
                    236:                // xip: ld/st/xmem
                    237:                // nip: next
                    238:                // fip: fetch
                    239: 
                    240:                // rom1.2 は DAE が起きると、
                    241: 
                    242:                // ROM挙動               CPU の RTE 挙動
                    243:                // sfip = sxip
                    244:                // sxip -> ~V (INVALID)  CPU はそもそも sxip を評価しない
                    245:                // snip = 0 (INVALID)    CPU はこれを nop 相当に処理する
                    246:                // rte
                    247: 
                    248:                // してくる。そのまま読むと命令を再実行しようとしているように
                    249:                // 読めるが、再実行すると無限ループになってしまう。
                    250:                // DAE の時点で xip が進んでいることを期待して利用している?
                    251: 
                    252:                // openbsd は
                    253:                // xmem の write バスエラーを検知すると命令を再実行するために
                    254:                // fip = nip, nip = xip して rte する。ということは xip = xmem に
                    255:                // なっていることを期待している。
                    256: 
                    257:                // というわけで
                    258:                // ld で DataAccessException のときは、実CPUはすでに次の命令を
                    259:                // 実行している?
                    260:                // もう少し考えると、スコアボードでレジスタの干渉がなければ、
                    261:                // 実行している?
                    262: 
                    263:                // 仕方がないのでハックでごまかす。
                    264:                // rte のほうも参照のこと。
                    265: 
                    266:                if (IsSuper() && xip >= 0x41000000 && xip < 0x42000000) {
                    267:                        // 遅延例外機構がないので、ROM 合わせのハック。
                    268:                        sxip = snip;
                    269:                }
                    270:        }
                    271: 
1.1       root      272:        epsr = psr;
1.1.1.2   root      273:        SetPSR(psr | PSR_SUPER | PSR_SFD1 | PSR_IND | PSR_SFRZ);
1.1       root      274: 
                    275:        fip = vbr + (vec << 3);
                    276:        fetch();
1.1.1.3   root      277:        // ここでベクタに飛ぶのだが、ベクタ内の2命令でおそらく必ずもう一度
                    278:        // 分岐してそっちでも履歴が残るので、ここでブランチ履歴を残すのは
                    279:        // ちょっと冗長という気もする。
                    280: 
1.1       root      281:        if (OpIsBusErr(opF)) {
                    282:                if (cause == ExceptionKind::ERROR) {
                    283:                        // double bus fault
                    284:                        // 実機は無限ループ状態
                    285:                        PANIC("Infinite ERROR (double bus fault)");
                    286:                } else {
                    287:                        ExceptionCore(M88K_EXCEP_ERROR, ExceptionKind::ERROR);
                    288:                }
                    289:        }
                    290: }
                    291: 
1.1.1.10  root      292: inline uint32
1.1.1.5   root      293: m88kcpu::Calcdmt(uint32 flag)
                    294: {
                    295:        return
                    296:                   ((psr & PSR_BO_LE) ? DM_BO : 0)
                    297:             | ((IsSuper() && !(flag & DM_USR)) ? DM_DAS : 0)
                    298:             | DM_VALID;
                    299: }
                    300: 
1.1       root      301: // データアクセス例外(Read)
1.1.1.5   root      302: // ld.b, ld.h, ld.hu, ld 用
1.1       root      303: void
1.1.1.5   root      304: m88kcpu::ReadDataException32(uint32 addr, uint32 flag)
1.1       root      305: {
                    306:        // ミスアラインドはこの例外より前にチェックされていて、
                    307:        // ここにはアラインドしかこない。
                    308:        dma0 = addr & ~0x3;
1.1.1.5   root      309:        dmt0 = Calcdmt(flag)
1.1       root      310:             | (FLD_D << 7)
                    311:             | (flag & DM_SIGNED)
                    312:             | ((flag & DM_EN_MASK) >> (addr & 0x03))
1.1.1.5   root      313:        ;
                    314:        dmt1 &= ~DM_VALID;
                    315:        dmt2 &= ~DM_VALID;
1.1.1.7   root      316:        cpulog(1, "ReadDAE xip=%x addr=%x", xip, addr);
1.1.1.2   root      317:        ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
1.1       root      318: }
                    319: 
1.1.1.5   root      320: // データアクセス例外(Read)
                    321: // ld.d 用
                    322: void
                    323: m88kcpu::ReadDataException64(uint32 addr, uint32 flag)
                    324: {
                    325:        // ミスアラインドはこの例外より前にチェックされていて、
                    326:        // ここにはアラインドしかこない。
                    327:        dma0 = addr;
                    328:        dmt0 = Calcdmt(flag)
                    329:             | DM_DOUB1                 // ダブルワードの第1アクセスのときセット
                    330:             | (FLD_D << 7)
                    331:             | DM_EN_MASK               // 32ビット有効
                    332:        ;
                    333: 
                    334:        dma1 = dma0 + 4;
                    335:        dmt1 = Calcdmt(flag)
                    336:             | (FLD_D2 << 7)
                    337:             | DM_EN_MASK                       // 32ビット有効
                    338:        ;
                    339: 
                    340:        dmt2 &= ~DM_VALID;
                    341: 
                    342:        if ((flag & DM_DOUB1) == 0) {
                    343:                // .d の2ワード目がバスエラー。第1ワードのアクセスは成功した。
1.1.1.11! root      344:                // DMx0 が例外を起こしたアクセスを示す。
        !           345:                // Manual 6.7.3
        !           346:                dma0 = dma1;
        !           347:                dmt0 = dmt1;
        !           348:                dmt1 &= ~DM_VALID;
1.1.1.5   root      349:        }
                    350: 
1.1.1.7   root      351:        cpulog(1, "ReadDAE64 xip=%x addr=%x", xip, addr);
1.1.1.5   root      352:        ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
                    353: }
                    354: 
1.1       root      355: // データアクセス例外(Write)
1.1.1.5   root      356: // st.b, st.h, st.hu, st 用
1.1       root      357: void
1.1.1.5   root      358: m88kcpu::WriteDataException32(uint32 addr, uint32 flag)
1.1       root      359: {
                    360:        // ミスアラインドはこの例外より前にチェックされていて、
                    361:        // ここにはアラインドしかこない。
                    362:        dma0 = addr & ~0x3;
1.1.1.5   root      363:        dmt0 = Calcdmt(flag)
1.1       root      364:             | (FLD_D << 7)
                    365:             | ((flag & DM_EN_MASK) >> (addr & 0x03))
                    366:             | DM_WRITE
1.1.1.5   root      367:        ;
                    368:        dmd0 = rD;
1.1       root      369: 
1.1.1.5   root      370:        dmt1 &= ~DM_VALID;
                    371:        dmt2 &= ~DM_VALID;
1.1.1.7   root      372:        cpulog(1, "WriteDAE xip=%x addr=%x", xip, addr);
1.1.1.2   root      373:        ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
                    374: }
                    375: 
1.1.1.5   root      376: // データアクセス例外(Write)
                    377: // st.d 用
                    378: void
                    379: m88kcpu::WriteDataException64(uint32 addr, uint32 flag)
                    380: {
                    381:        // ミスアラインドはこの例外より前にチェックされていて、
                    382:        // ここにはアラインドしかこない。
                    383:        dma0 = addr & ~0x3;
                    384:        dmt0 = Calcdmt(flag)
                    385:             | DM_DOUB1         // ダブルワードの第1アクセスのときセット
                    386:             | (FLD_D << 7)
                    387:             | DM_EN_MASK
                    388:             | DM_WRITE
                    389:        ;
                    390:        dmd0 = rD;
                    391: 
                    392:        dma1 = dma0 + 4;
                    393:        dmt1 = Calcdmt(flag)
                    394:             | (FLD_D2 << 7)
                    395:             | DM_EN_MASK
                    396:             | DM_WRITE
                    397:        ;
                    398:        dmd1 = rD2;
                    399: 
                    400:        dmt2 &= ~DM_VALID;
                    401: 
                    402:        if ((flag & DM_DOUB1) == 0) {
                    403:                // .d の2ワード目がバスエラー。第1ワードのアクセスは成功した。
1.1.1.11! root      404:                // DMx0 が例外を起こしたアクセスを示す。
        !           405:                // Manual 6.7.3
        !           406:                dma0 = dma1;
        !           407:                dmt0 = dmt1;
        !           408:                dmd0 = dmd1;
        !           409:                dmt1 &= ~DM_VALID;
1.1.1.5   root      410:        }
                    411: 
1.1.1.7   root      412:        cpulog(1, "WriteDAE64 xip=%x addr=%x", xip, addr);
1.1.1.5   root      413:        ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
                    414: }
                    415: 
1.1.1.2   root      416: // データアクセス例外(xmem)
1.1.1.5   root      417: // xmem には .d は無い
1.1.1.2   root      418: void
1.1.1.5   root      419: m88kcpu::XmemDataException(uint32 addr, uint32 flag)
1.1.1.2   root      420: {
                    421:        dma0 = addr & ~0x3;
1.1.1.5   root      422:        dmt0 = Calcdmt(flag)
                    423:             | DM_LOCK          // xmem でセット
1.1.1.2   root      424:             | (FLD_D << 7)
                    425:             | (flag & DM_SIGNED)
                    426:             | ((flag & DM_EN_MASK) >> (addr & 0x03))
1.1.1.5   root      427:        ;
1.1.1.2   root      428: 
1.1.1.5   root      429:        dma1 = dma0;
                    430:        dmt1 = Calcdmt(flag)
                    431:             | DM_LOCK          // xmem でセット
1.1.1.2   root      432:             | (FLD_D << 7)
                    433:             | (flag & DM_SIGNED)
                    434:             | ((flag & DM_EN_MASK) >> (addr & 0x03))
                    435:             | DM_WRITE
1.1.1.5   root      436:        ;
                    437:        dmd1 = rD;
1.1.1.2   root      438: 
1.1.1.5   root      439:        dmt2 &= ~DM_VALID;
1.1.1.2   root      440: 
                    441:        // ミスアラインドはこの例外より前にチェックされていて、
                    442:        // ここにはアラインドしかこない。
                    443:        if (cmmu[1].fault_code != m88200::FAULT_CODE_BUSERR
                    444:         || cmmu[1].acc_read) {
                    445:                // アドレス変換フォルトまたは read 時点
                    446:                // nop
1.1       root      447:        } else {
1.1.1.2   root      448:                // xmem の write 時点
1.1.1.5   root      449:                dmt0 &= ~DM_VALID;
1.1       root      450:        }
1.1.1.2   root      451: 
1.1.1.7   root      452:        cpulog(1, "xmemDAE xip=%x addr=%x", xip, addr);
1.1.1.2   root      453:        ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
1.1       root      454: }
                    455: 
1.1.1.10  root      456: // FPxS レジスタをセット
1.1.1.5   root      457: void
1.1.1.10  root      458: m88kcpu::SetFPxS(uint32& h, uint32& l, double src, uint32 ts)
1.1.1.5   root      459: {
1.1.1.10  root      460:        // FPHS[12]、FPLS[12] は以下の構造
                    461:        //
                    462:        //    3                   2                   1                   0
                    463:        //  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
                    464:        // +-+---------------------+---------------------------------------+
                    465:        // |S|   Exponent(11bit)   |     High Order 20 bits of Mantissa    | FPHSn
                    466:        // +-+---------------------+---------------------------------------+
                    467:        //
                    468:        // +---------------------------------------------------------------+
                    469:        // |           Low Order bits of Mantissa, or Integer              | FPLSn
                    470:        // +---------------------------------------------------------------+
                    471:        //
                    472:        // ts が 1 (double) の場合は IEEE754 double と同じ。
                    473:        // ts が 0 (single) の場合は float を double にキャスト (拡大変換) した
                    474:        // ものではないことに注意。
                    475:        // S(符号ビット)はそのまま。float の Mantissa (23bit) のうち上位 20bit
                    476:        // を FPHSn に、残り 3bit を FPLSn の上位 3bit に。ここまではいい。
                    477:        // Exponent は float の指数部(8bit、バイアス=127) の値を *そのまま*
                    478:        // 符号拡張(?)する。
                    479:        // (float)1.0 は 1.0 * 2^0 なのでバイアス込みの指数部は 127、
                    480:        // (float)2.0 は 1.0 * 2^1 なのでバイアス込みの指数部は 128。
                    481:        // バイアス込みにした値は符号なし数のはずだが、ここではこれを 11bit に
                    482:        // 符号拡張して FPHSn の Exponent 部に格納するようだ。取り出す際に下位
                    483:        // 8bit しか取り出さなければ害はないし、符号拡張する方がハードウェア的に
                    484:        // 都合がよかったとかだろうか。
                    485:        // 仮に普通に double に変換すると double の指数部バイアスは 1023 なので
                    486:        // バイアス込みの指数部は先程の例だとそれぞれ 1023、1024 になるが
                    487:        // これではないということ。
                    488: 
                    489:        union64 u;
                    490:        u.q = d2u(src);
                    491:        if (ts == 0) {
                    492:                // single
                    493: 
                    494:                uint32 exp;
                    495:                // src は普通の double なのでこの指数部を取り出す
                    496:                uint32 double_biased = (u.h >> 20) & 0x7ff;
                    497:                if (double_biased == 0x7ff) {
                    498:                        // Inf, NAN
                    499:                        exp = 0x7ff00000;
                    500:                } else {
                    501:                        // double のバイアスを外して float のバイアスを足す
                    502:                        int float_biased = (double_biased - 1023) + 127;
                    503:                        // この 8bit 値を 11bit に符号拡張して所定の位置へ
                    504:                        exp = ((int32)(float_biased << 24)) >> 4;
                    505:                        exp &= 0x7ff00000;
                    506:                }
                    507: 
                    508:                h = (u.h & 0x800fffff) | exp;
                    509:                l = u.l;
                    510:        } else {
                    511:                // double
                    512:                h = u.h;
                    513:                l = u.l;
                    514:        }
                    515: }
                    516: 
                    517: // FPR[HL] レジスタに double 値をセット
                    518: // - それ以外のフィールドは保存する XXX ここでクリアしてもいいか?
                    519: // - XXX Guard, Round, Sticky (, AddOne) はまだない
                    520: void
                    521: m88kcpu::SetFPRx(double src)
                    522: {
                    523:        union64 u;
                    524:        uint32 exp;
                    525: 
                    526:        u.q = d2u(src);
                    527: 
                    528:        // Sign は FPRH
                    529:        fprh &= ~(FPRH_SIGN | FPRH_MANT);       // Mantissa もついでにクリア
                    530:        fprh |= u.h & 0x80000000;
                    531: 
                    532:        // Exp  は FPIT。
                    533:        // double は 11bit だが FPIT::RESEXP は 12bit なので 1bit 符号拡張する。
                    534:        // 符号付き数(正確には負数)の右シフトは実装依存だが gcc, clang は
                    535:        // 算術右シフトになる。
                    536:        //
                    537:        //           3                   2
                    538:        //         1 0 9 8 7 6 5 4 3 2 1 0 9
                    539:        //        +-+---------------------+-
                    540:        // double |S|   Exponent(11bit)   |
                    541:        //        +-+---------------------+-
                    542:        //
                    543:        //        +---------------------+-+-
                    544:        // u.h<<1 |  Exponent(11bit)    |X|
                    545:        //        +---------------------+-+-
                    546:        //
                    547:        //        +-----------------------+-
                    548:        // exp>>1 |   Exponent(12bit)     |
                    549:        //        +-----------------------+-
                    550:        exp = u.h << 1;
                    551:        exp = (int32)exp >> 1;
                    552:        fpit &= ~FPIT_RESEXP;
                    553:        fpit |= exp & FPIT_RESEXP;
                    554: 
                    555:        // Mantissa は FPRH, FPRL
                    556:        // 上位側(FPRH)には最上位(実数桁)の隠しビットを含む。
                    557:        fprh |= (u.h & 0x000fffff);
                    558:        fprh |= FPRH_1;
                    559:        fprl = u.l;
                    560: }
                    561: 
                    562: // FP Precise 例外。浮動小数点数1つの場合。
                    563: void
                    564: m88kcpu::FPPreciseException(uint32 cause, double s2)
                    565: {
                    566:        SetFPS2(s2, m88100opf_FP_T2(opX));
                    567:        FPPreciseException(cause);
                    568: }
                    569: 
                    570: // FP Precise 例外。浮動小数点数2つの場合。
                    571: void
                    572: m88kcpu::FPPreciseException(uint32 cause, double s1, double s2)
                    573: {
                    574:        SetFPS1(s1, m88100opf_FP_T1(opX));
                    575:        SetFPS2(s2, m88100opf_FP_T2(opX));
                    576:        FPPreciseException(cause);
                    577: }
                    578: 
                    579: // FP Precise 例外。
                    580: void
                    581: m88kcpu::FPPreciseException(uint32 cause)
                    582: {
                    583:        assert(cause == FPECR_FIOV   ||
                    584:               cause == FPECR_FUNIMP ||
                    585:               cause == FPECR_FPRV   ||
                    586:               cause == FPECR_FROP   ||
                    587:               cause == FPECR_FDVZ);
                    588: 
                    589:        fpecr = cause;
                    590: 
                    591:        // FPPT(FP Precise operation Type Register)
                    592:        fppt = opX & 0xffe0;            // Opcode, T1, T2, TD は opX と同じ位置
                    593:        fppt |= m88100opf_D(opX);       // DEST
                    594: 
                    595:        Exception(M88K_EXCEP_SFU1_PRECISE);
                    596: }
                    597: 
                    598: // FP Imprecise 例外。
                    599: void
                    600: m88kcpu::FPImpreciseException(uint32 cause)
                    601: {
                    602:        assert(cause == FPECR_FUNF ||
                    603:               cause == FPECR_FOVF ||
                    604:               cause == FPECR_FINX);
                    605: 
                    606:        fpecr = cause;
                    607: 
                    608:        // FPIT(FP Imprecise operation Type Register)
                    609:        fpit &= FPIT_RESEXP;
                    610:        fpit |= opX & FPIT_OPCODE;
                    611:        fpit |= (opX & 0x00000020) << 5;        // DESTSIZ
                    612:        fpit |= (fpcr & 0x0000001f) << 5;       // EFINV,EFDVZ,EFUNF,EFOVR,EFINX
                    613:        fpit |= m88100opf_D(opX);                       // DEST
                    614: 
                    615:        // FPRH(FP Result High Register)
                    616:        fprh &= ~FPRH_RNDMODE;
                    617:        fprh |= (fpcr & FPCR_RM) << 14;
1.1.1.5   root      618: 
1.1.1.10  root      619:        Exception(M88K_EXCEP_SFU1_IMPRECISE);
1.1.1.5   root      620: }
                    621: 
1.1       root      622: void
1.1.1.5   root      623: m88kcpu::Interrupt(int level)
1.1       root      624: {
1.1.1.5   root      625:        // level は 0 か 1。
                    626:        intr_pending = level;
1.1.1.11! root      627: 
        !           628:        if (intr_pending && IsIntrEnable() && (cpu_state == CPU_STATE_STOP)) {
        !           629:                // 割り込みを受け付けたら STOP 解除。
        !           630:                ChangeState(CPU_STATE_NORMAL);
        !           631:        }
1.1       root      632: }
                    633: 
                    634: void
                    635: m88kcpu::fpu_unimpl()
                    636: {
                    637:        printf("%s\n", __func__);
1.1.1.10  root      638:        FPPreciseException(FPECR_FUNIMP);
1.1       root      639: }
1.1.1.2   root      640: 
                    641: OP_DEF(illegal)
                    642: {
                    643:        // 本来は不当命令例外?
1.1.1.7   root      644:        cpulog(0, "Illegal instruction %08x", (uint32)opX);
1.1.1.2   root      645: }
1.1.1.11! root      646: 
        !           647: void
        !           648: m88kcpu::ChangeState(uint32 new_state)
        !           649: {
        !           650:        if (new_state == CPU_STATE_STOP) {
        !           651:                instruction_in_stop = 0;
        !           652:        }
        !           653: 
        !           654:        if (cpu_state != new_state) {
        !           655:                cpu_state = new_state;
        !           656:                // スケジューラに通知
        !           657:                dev->NotifyCPUMode(cpu_state);
        !           658:        }
        !           659: }

unix.superglobalmegacorp.com

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