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

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

unix.superglobalmegacorp.com

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