Annotation of nono/m680x0/m68030core.cpp, revision 1.1.1.9

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.8   root        7: #include "mpu680x0.h"
                      8: #include "debugger.h"
                      9: #include "interrupt.h"
                     10: #include "scheduler.h"
1.1.1.6   root       11: #include "vectortable.h"
1.1       root       12: 
1.1.1.8   root       13: #define OP_FUNC(name)  __CONCAT(op_,name)()
1.1       root       14: 
1.1.1.6   root       15: // 1命令実行する。
1.1.1.8   root       16: // 割り込みチェックなどを省いたショート版。
1.1.1.6   root       17: // 戻り値は消費したサイクル数。
1.1.1.8   root       18: void
                     19: MPU680x0Device::ExecShort(Event& ev)
1.1       root       20: {
1.1.1.8   root       21:        uint64 cycle_start = used_cycle;
1.1       root       22: 
1.1.1.6   root       23:        try {
                     24:                // 1命令版では switch-case を使うしかない。
1.1.1.8   root       25:                ppc = reg.pc;
                     26:                flag_pi = 0;
                     27:                flag_pd = 0;
                     28:                ir = fetch_16();
1.1.1.6   root       29: 
                     30:                // uint16 を 6ビット右シフトしたら 1024 以上になるはずは
                     31:                // ないのだが、デフォルトでは gcc/clang どちらも律儀に
                     32:                // 1024 以上かどうか比較して分岐しようとする。
                     33:                // gcc は __assume() を入れることでこの比較・分岐を出力
                     34:                // しないようにすることが出来た(がパフォーマンスの差は
                     35:                // 見えない程度でしかなかった)。
                     36:                // clang ではどうやったら効くか不明。
1.1.1.8   root       37:                uint16 ir6 = ir >> 6;
                     38:                __assume(ir6 < 1024);
                     39:                switch (ir6) {
1.1       root       40: #include "m68030switch.h"
                     41:                }
1.1.1.4   root       42: 
1.1.1.8   root       43:                used_cycle += cycle_nocache;
                     44:                cycle_nocache = 0;
1.1.1.6   root       45:        } catch (int vector) {
                     46:                // ここで(C++の)例外スローをキャッチするのは
                     47:                // - メモリ空間をアクセスした先でのバスエラー例外
                     48:                // - EA パース中の不当命令例外
                     49:                // のみ。それ以外の命令途中例外はその場で処理できる。
1.1.1.8   root       50:                if (__predict_false(loglevel >= 2)) {
                     51:                        const char *name = vectortable->GetExceptionName(vector);
1.1.1.7   root       52:                        if (__predict_true(name)) {
1.1.1.8   root       53:                                putlogn("%s", name);
1.1.1.7   root       54:                        } else {
1.1.1.8   root       55:                                putlogn("vector 0x%x", vector);
1.1.1.7   root       56:                        }
                     57:                }
1.1.1.9 ! root       58:                if (vector == M68K::EXCEP_BUSERR) {
        !            59:                        ExceptionBuserr(vector);
        !            60:                } else {
        !            61:                        Exception(vector);
        !            62:                }
1.1.1.6   root       63:        }
1.1       root       64: 
1.1.1.6   root       65:        // 外部割り込みの起動は VM 側で処理している。
1.1       root       66: 
1.1.1.8   root       67:        int cycle = used_cycle - cycle_start;
                     68:        ev.time = cycle * clock_nsec;
                     69:        scheduler->StartEvent(ev);
                     70: }
                     71: 
                     72: // 二重バスフォールト
                     73: void
                     74: MPU680x0Device::DoubleBusFault(const char *where)
                     75: {
                     76:        // where をログに出す?
                     77: 
                     78:        // ホールト状態へ移行
                     79:        Halt();
                     80: }
                     81: 
                     82: // SR (と CCR) をセットする。
                     83: // リセット例外以外から使う (リセット例外はやや異なるため)。
                     84: //
                     85: // 割り込みマスクが変わる場合は、ここで次の命令実行コールバックを差し替える。
                     86: void
                     87: MPU680x0Device::SetSR(uint16 data)
                     88: {
                     89:        bool oldS = reg.s;
                     90:        bool oldM = reg.m;
                     91: 
                     92:        // 現在の SP を保存
                     93:        if (oldS == false) {
                     94:                reg.usp = reg.A[7];
                     95:        } else if (oldM == false) {
                     96:                reg.isp = reg.A[7];
                     97:        } else {
                     98:                reg.msp = reg.A[7];
                     99:        }
                    100: 
                    101:        reg.ccr.Set(data);
                    102:        reg.s = ((data & M68K::SR_S) != 0);
                    103:        reg.m = ((data & M68K::SR_M) != 0);
                    104: 
                    105:        // 割り込みマスクレジスタを更新して..
                    106:        uint new_mask = (data >> 8) & 7;
                    107:        if (reg.intr_mask != new_mask) {
                    108:                reg.intr_mask = new_mask;
                    109: 
                    110:                // 次の命令境界で割り込みをチェックさせる
                    111:                MakeNextFull();
                    112:        }
                    113: 
                    114:        // 新しい SP を用意
                    115:        if (reg.s == false) {
                    116:                reg.A[7] = reg.usp;
                    117:        } else if (reg.m == false) {
                    118:                reg.A[7] = reg.isp;
                    119:        } else {
                    120:                reg.A[7] = reg.msp;
                    121:        }
                    122: 
                    123:        // バスの FC2 を変更
                    124:        bus.SetFC2(reg.s);
                    125: 
                    126:        // XXX 他に何か状態変えないといけないことあったっけか。
                    127: }
                    128: 
                    129: // 命令中に (An)+ で変化したアドレスレジスタを命令実行前の状態に巻き戻す。
                    130: // flag_pi は bit7..0 が save_pi[7..0] の A7..A0 に対応している。
                    131: void
                    132: MPU680x0Device::restore_reg_pi()
                    133: {
                    134:        for (int i = 7; flag_pi; i--) {
                    135:                if ((int8)flag_pi < 0) {
                    136:                        reg.A[i] = save_pi[i];
                    137:                }
                    138:                flag_pi <<= 1;
                    139:        }
                    140: }
                    141: 
                    142: // 命令中に -(An) で変化したアドレスレジスタを命令実行前の状態に巻き戻す。
                    143: // flag_pd は bit7..0 が save_pd[7..0] の A7..A0 に対応している。
                    144: void
                    145: MPU680x0Device::restore_reg_pd()
                    146: {
                    147:        for (int i = 7; flag_pd; i--) {
                    148:                if ((int8)flag_pd < 0) {
                    149:                        reg.A[i] = save_pd[i];
                    150:                }
                    151:                flag_pd <<= 1;
                    152:        }
                    153: }
                    154: 
                    155: // vector にジャンプする。vector はベクタ番号(アドレスではない)。
                    156: void
                    157: MPU680x0Device::JumpVector(int vector)
                    158: {
                    159:        uint32 vecaddr;
                    160:        uint32 newpc;
                    161: 
                    162:        vecaddr = reg.vbr + vector * 4;
                    163:        reg.pc = vecaddr;
                    164:        newpc = fetch_32();
                    165:        // VBR 込みのジャンプ先が確定したところで今度はブランチ履歴に記録。
                    166:        // この時のブランチ元はベクタアドレス
                    167:        // (reg.pc は fetch によって進んでしまうので先に保存)
1.1.1.9 ! root      168:        uint32 inst = BranchHistory_m680x0::VectorJump;
        !           169:        brhist.AddEntry(vecaddr | (IsSuper() ? 1 : 0), newpc, inst);
1.1.1.8   root      170: 
                    171:        // 奇数番地ならアドレスエラー
                    172:        if (__predict_false((newpc & 1) != 0)) {
1.1.1.9 ! root      173:                ExceptionBuserr(M68K::EXCEP_ADDRERR);
1.1.1.8   root      174:                return;
                    175:        }
                    176:        reg.pc = newpc;
                    177: 
                    178:        // 実際はここでパイプライン充填のために3ワードフェッチするので、
                    179:        // ベクタテーブルはフェッチ出来たけどそのジャンプ先がバスエラーに
                    180:        // なるケースはここでバスエラーが出なければいけないが、まだ
                    181:        // キャッシュを実装していないので、ここで1ワードフェッチしてみて
                    182:        // PC を戻すあほっぽい方法を取る。
                    183:        fetch_16();
                    184:        reg.pc -= 2;
                    185: }
                    186: 
                    187: // 例外スタックフレーム $0 を生成する。
                    188: // vector はベクタ番号。
                    189: // pc はスタックに積むプログラムカウンタの値 (例外によって、この命令位置か
                    190: // 次の命令位置かが異なる)。
                    191: // sr は例外発生時の SR。
                    192: inline void
                    193: MPU680x0Device::GenerateExframe0(int vector, uint32 pc, uint16 sr)
                    194: {
                    195:        // 例外スタックフレーム $0
                    196:        // SP+$00.W STATUS REGISTER
                    197:        //   +$02.L PROGRAM COUNTER             ; 例外ごとに異なる
                    198:        //   +$06.W %0000 | VECTOR
                    199: 
                    200:        push_16((0 << 12) | (vector * 4));
                    201:        push_32(pc);
                    202:        push_16(sr);
                    203: }
                    204: 
                    205: // 例外スタックフレーム $2 を生成する。
                    206: // vector はベクタ番号。
                    207: // スタックに積む PC は常に次の命令。
                    208: inline void
                    209: MPU680x0Device::GenerateExframe2(int vector, uint16 sr)
                    210: {
                    211:        // 例外スタックフレーム $2
                    212:        // SP+$00.W STATUS REGISTER
                    213:        //   +$02.L PROGRAM COUNTER             ; 次の命令位置
                    214:        //   +$06.W %0010 | VECTOR
                    215:        //   +$08.L INSTRUCTION ADDRESS ; 例外を起こした命令のアドレス
                    216: 
                    217:        push_32(ppc);                   // 例外を起こした命令のアドレス
                    218:        push_16((2 << 12) | (vector * 4));
                    219:        push_32(reg.pc);                // 次の命令位置
                    220:        push_16(sr);
                    221: }
                    222: 
                    223: // 例外スタックフレーム $B を生成する。
                    224: inline void
                    225: MPU680x0Device::GenerateExframeB(int vector, uint16 sr)
                    226: {
                    227:        uint16 ssw;
                    228:        uint32 fault_addr;
                    229:        uint32 stageBaddr;
                    230: 
                    231:        stageBaddr = reg.pc + 2;
                    232:        // この後のスタック操作で bus が変化する前に保存
                    233:        fault_addr = bus.laddr;
                    234:        // DF ビットを立てておくと RTE した後この命令を再実行。
                    235:        ssw = bus.ssw | M68K::SSW_DF;
                    236: 
                    237:        // 例外スタックフレーム $B
                    238:        // SP+$00.W   STATUS REGISTER
                    239:        //   +$02.L   PROGRAM COUNTER
                    240:        //   +$06.W   %1011 | VECTOR
                    241:        //   +$08.W   (internal register)
                    242:        //   +$0a.W   SPECIAL STATUS REGISTER           ; SSW
                    243:        //   +$0c.W   INSTRUCTION PIPE STAGE C
                    244:        //   +$0e.W   INSTRUCTION PIPE STAGE B
                    245:        //   +$10.L   DATA CYCLE FAULT ADDRESS
                    246:        //   +$14.W*2 (internal register)
                    247:        //   +$18.L   DATA OUTPUT BUFFER
                    248:        //   +$1c.W*4 (internal register, 4 words)
                    249:        //   +$24.L   STAGE B ADDRESS
                    250:        //   +$28.W*2 (internal register, 2 words)
                    251:        //   +$2c.L   DATA INPUT BUFFER
                    252:        //   +$30.W*3 (internal register, 3 words)
                    253:        //   +$36.W   VERSION# | internal information
                    254:        //   +$38.W*18 (internal register, 18 words)
                    255:        //   +$5a
                    256:        //      こっちから上に向かって PUSH
                    257: 
                    258:        // internal registers, 18 words
                    259:        // 内部レジスタ18ワードのうち、ここでは17ワード分を save_pd[8] (16ワード)、
                    260:        // flag_pd (1ワード) として使うことにする。
                    261:        // -(An) でバスエラーが起きると An は減算された状態になるが、DF ビットが
                    262:        // 立っていて再実行する時には現行構造では命令先頭から再実行せざるをえず、
                    263:        // そうするともう一度プリデクリメントが動いてしまう。そのため、RTE の時点
                    264:        // で DF=1 ならプリデクリメント発生前の An に戻すという処理をする。
                    265:        // RTE 時点で DF=0 なら命令を再実行しないため An も巻き戻してはならず、
                    266:        // そのためプリデクリメント分の巻き戻しは RTE 時点まで行えない。
                    267:        // 一方、ポストインクリメントのケースはこの少し下の
                    268:        // ExceptionBuserr() 内のコメント参照。
                    269:        for (int i = 7; i >= 0; i--) {
                    270:                push_32(save_pd[i]);
                    271:        }
                    272:        push_16(flag_pd);
                    273:        reg.A[7] -= 2;
                    274: 
                    275:        reg.A[7] -= 2;                                  // VERSION#
                    276:        reg.A[7] -= 6;
                    277:        push_32(0);                                             // DATA INPUT BUFFER
                    278:        reg.A[7] -= 4;
                    279:        push_32(stageBaddr);                    // STAGE B ADDRESS
                    280:        reg.A[7] -= 8;
                    281:        push_32(0);                                             // DATA OUTPUT BUFFER
                    282:        reg.A[7] -= 4;
                    283:        push_32(fault_addr);                    // DATA CYCLE FAULT ADDRESS
                    284:        push_16(0);                                             // INSTRUCTION PIPE STAGE B
                    285:        push_16(0);                                             // INSTRUCTION PIPE STAGE C
                    286:        push_16(ssw);
                    287:        reg.A[7] -= 2;
                    288:        push_16(0xb000 | (vector << 2));
                    289:        // 本当は現在の PC だが、再実行のため PPC を積む。
                    290:        push_32(ppc);                                   // PC
                    291:        push_16(sr);                                    // 例外入り口で保存した SR
                    292: }
                    293: 
                    294: // 例外処理について。
                    295: //
                    296: // 0. リセット例外
                    297: //     リセット例外は外部から ExceptionReset() を呼び出す。
                    298: //
                    299: // 1. バスエラー例外
                    300: //     MMU による論理アドレスでのバスエラーは (Translate*() が false を返した後)
                    301: //     m68030bus.cpp ルーチンが (C++の) 例外をスローする。
                    302: //     物理アドレス空間アクセス後のバスエラーは (VM側の read*()/write*() が
                    303: //     (int64)-1 を返した後) m68030bus.cpp ルーチンが (C++) の例外をスローする。
                    304: //     どちらのケースも m68030core.cpp のメインループで catch し、その catch
1.1.1.9 ! root      305: //     ブロック内で ExceptionBuserr() を呼び出す。
1.1.1.8   root      306: //
                    307: // 2. アドレスエラー例外
                    308: //     アドレスエラーは Jump() 内でのみ発生するはずで、その場で
1.1.1.9 ! root      309: //     ExceptionBuserr() を呼んで処理する。
1.1.1.8   root      310: //
                    311: // 3. 命令中で起きる例外
                    312: //     命令途中で起きる(確定的な)例外は Exception() を呼び出す。
                    313: //     これに該当するのは
                    314: //       o 特権違反
                    315: //       o A系列/F系列命令
                    316: //       o TRAP* 系命令、CHK/CHK2 命令
                    317: //       o トレース例外 (未実装)
                    318: //       o ゼロ除算?
                    319: //       o MMU 構成例外
                    320: //       o 不当命令 (*)
                    321: //     である。
                    322: //     ただし、不当命令についてはどこで不当命令と判定されるかによって
                    323: //     フローが複数存在することに注意。
                    324: //       o 1ワード目が不当命令
                    325: //             -> 命令がそれぞれ Exception() で処理。
                    326: //       o 1ワード目の EA が不当命令
                    327: //             -> (C++の)例外をスローして catch 内で Exception() を実行。
                    328: //       o 2ワード目が不当命令
                    329: //             -> 命令がそれぞれ Exception() で処理。
                    330: //
                    331: // 4. 割り込み例外
                    332: //     別コメント(下のほう)参照。
                    333: //
                    334: 
                    335: // リセット例外処理。
                    336: // 各レジスタを所定の状態にして、リセットベクタを読み込む。
                    337: // リセットベクタが読み込めなければ HALT 状態に移行。
                    338: // 戻り値は消費したサイクル数。
                    339: int
                    340: MPU680x0Device::ExceptionReset()
                    341: {
                    342:        uint64 cycle_start = used_cycle;
                    343: 
                    344:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
                    345:        // m68k では今の所リセット例外発生時の PC にはあまり意味がないけど、
                    346:        // m88k と動作を揃えておく。
                    347:        const uint vector = 0;
1.1.1.9 ! root      348:        exhist.AddEntry(reg.pc | 1, 0, BranchHistory_m680x0::Exception | 0);
        !           349:        brhist.AddEntry(reg.pc | 1, 0, BranchHistory_m680x0::Exception | 0);
1.1.1.8   root      350:        // デバッガに通知 (例外ブレーク用)。こっちのベクタは 0 のままでよい。
                    351:        debugger->NotifyExceptionMain(vector);
                    352: 
                    353:        // RESET 信号線をネゲートしてから SP の読み込み開始まで 4クロック
                    354:        // (Section 7.8, Figure 7-64)
                    355:        used_cycle += 4;
                    356: 
                    357:        // STOP 状態とホールト状態を解除。
                    358:        ChangeState(CPU_STATE_NORMAL);
                    359: 
                    360:        // 1. T0, T1 クリア
                    361:        // 2. S をセット、M をクリア
                    362:        // 3. 割り込みレベルを 7
                    363: 
                    364:        // ここは SetSR を使わずに設定する。
                    365:        reg.s = true;
                    366:        reg.m = false;
                    367:        bus.SetFC2(reg.s);
                    368:        // ここは割り込みレベル変化のチェックは不要でセットだけでいい。
                    369:        reg.intr_mask = 7;
                    370: 
                    371:        // 4. VBR をクリア
                    372:        reg.vbr = 0;
                    373:        // 5. キャッシュ
                    374:        reg.cacr = 0;   // XXX
                    375:        // 6. キャッシュエントリクリア
                    376:        // 7. TC:E、TTn:E をクリア
                    377:        SetTC(GetTC() & ~m68030TC::TC_E);
                    378:        SetTT(0, GetTT(0) & ~m68030TT::E);
                    379:        SetTT(1, GetTT(1) & ~m68030TT::E);
                    380:        // 8. リセットベクタ生成
                    381: 
                    382:        // 9. SP をロード
                    383:        // 10. PC をロード
                    384:        try {
                    385:                reg.pc = 0;
                    386:                reg.A[7] = fetch_32();
                    387:                uint32 pc = fetch_32();
                    388:                // 大丈夫のはずだけど fetch_32() が reg.pc を書き換えるので一応
                    389:                reg.pc = pc;
                    390:                // リセットベクタは常に 0, 4 番地から取得したことになっている
1.1.1.9 ! root      391:                uint32 inst = BranchHistory_m680x0::VectorJump;
        !           392:                brhist.AddEntry(0x00000004 | 1, reg.pc, inst);
1.1.1.8   root      393:        } catch (int) {
                    394:                DoubleBusFault("reset exception");
                    395:        }
                    396: 
                    397:        // SP のアドレスエラーはリセット例外ではチェックしないようだ。
                    398:        // PC のアドレスエラーは本来ならここにあるはずの3ワードのプリフェッチで
                    399:        // 行われるのだが、それがないので、とりあえずここで。
                    400:        if ((reg.pc & 1) != 0) {
                    401:                DoubleBusFault("reset exception");
                    402:        }
                    403: 
                    404:        return used_cycle - cycle_start;
                    405: }
                    406: 
1.1.1.9 ! root      407: // 汎用の例外処理を行う。vector はベクタ番号。
        !           408: // ただし以下の例外はここではなくそれぞれ固有のを呼ぶこと。
        !           409: // o リセット例外は ExceptionReset()
        !           410: // o 割り込み例外は ExceptionInterrupt()
        !           411: // o TRAP#15 例外は ExceptionTrap15()
        !           412: // o バスエラー・アドレスエラーは ExceptionBuserr()
1.1.1.8   root      413: void
                    414: MPU680x0Device::Exception(int vector)
                    415: {
1.1.1.9 ! root      416:        uint32 inst = BranchHistory_m680x0::Exception | vector;
        !           417:        ExceptionGeneric(vector, inst);
        !           418: }
        !           419: 
        !           420: // TRAP #15 の例外処理を行う。
        !           421: // 処理自体は汎用の Exception() とまったく同じだが、
        !           422: // IOCS コールの時には分岐履歴の出力が変わるため入口を分けてある。
        !           423: void
        !           424: MPU680x0Device::ExceptionTrap15()
        !           425: {
        !           426:        // 今発生した TRAP #15 が IOCS コールっぽいかどうか調べる。
        !           427:        //
        !           428:        // Human68k 方面をやってる時は TRAP #15 は IOCS コールで表示してほしい。
        !           429:        // 一方、NetBSD のカーネル内では TRAP #15 は IOCS コールではない別用途
        !           430:        // なので IOCS コールかのように表示されるのは紛らわしい。さらに言えば
        !           431:        // NetBSD でもブートローダの時点はまだ IOCS コールを使うので、出来れば
        !           432:        // 今呼ばれたこれが IOCS コールなのか、そうでない TRAP #15 なのかは
        !           433:        // 区別したい。
        !           434:        //
        !           435:        // IOCS コールかどうかは厳密には分からないが、これが呼ばれた時点で
        !           436:        // ワークエリアの $cbc == 0x03、$cbe == 0xff であれば IOCS コールと
        !           437:        // 判定することにする。
        !           438:        // $cbc は MPU 種別で 3:68030。
        !           439:        // $cbe は MMU 有無で 0xff:有り。
        !           440:        // 今の所 68030/MMU有り しかサポートしていないので。
        !           441:        // だめならまた考える。
        !           442: 
        !           443:        const int vector = M68K::EXCEP_TRAP15;
        !           444:        uint32 inst;
        !           445:        if (mainbus->Peek8(0xcbc) == 0x03 && mainbus->Peek8(0xcbe) == 0xff) {
        !           446:                // IOCS コールっぽい
        !           447:                inst = BranchHistory_m680x0::IOCSCall | (reg.D[0] & 0xff);
        !           448:        } else {
        !           449:                // TRAP#15 っぽい
        !           450:                inst = BranchHistory_m680x0::Exception | vector;
1.1.1.8   root      451:        }
1.1.1.9 ! root      452:        ExceptionGeneric(vector, inst);
        !           453: }
1.1.1.8   root      454: 
1.1.1.9 ! root      455: // 汎用の例外処理本体。
        !           456: void
        !           457: MPU680x0Device::ExceptionGeneric(int vector, uint32 inst)
        !           458: {
1.1.1.8   root      459:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
                    460:        uint32 from = ppc | (IsSuper() ? 1 : 0);
1.1.1.9 ! root      461:        exhist.AddEntry(from, 0, inst);
        !           462:        brhist.AddEntry(from, 0, inst);
1.1.1.8   root      463:        // デバッガに通知 (例外ブレーク用)
                    464:        debugger->NotifyExceptionMain(vector);
                    465: 
                    466:        // 状態を保存
                    467:        uint16 sr = GetSR();
                    468: 
                    469:        // S を立てて T1,T0 を落とす
                    470:        SetSR((GetSR() | M68K::SR_S) & ~M68K::SR_T);
                    471: 
                    472:        try {
                    473:                switch (vector) {
                    474:                 case M68K::EXCEP_ILLEGAL:              // 不当命令
                    475:                 case M68K::EXCEP_PRIV:                 // 特権違反例外
                    476:                 case M68K::EXCEP_ALINE:                // Aライン命令例外
                    477:                 case M68K::EXCEP_FLINE:                // Fライン命令例外
                    478:                        // スタックに積む PC はこの命令のアドレス
                    479:                        GenerateExframe0(vector, ppc, sr);
                    480:                        break;
                    481: 
                    482:                 case M68K::EXCEP_TRAP0                 // TRAP#0
                    483:                  ... M68K::EXCEP_TRAP15:               // TRAP#15
                    484:                        // スタックに積む PC は次の命令
                    485:                        GenerateExframe0(vector, reg.pc, sr);
                    486:                        break;
                    487: 
                    488:                 case M68K::EXCEP_ZERODIV:              // ゼロ除算
                    489:                 case M68K::EXCEP_CHK:                  // CHK
                    490:                 case M68K::EXCEP_TRAPV:                // TRAPV
                    491:                 case M68K::EXCEP_MMU_CONFIG:   // MMU 構成例外
                    492:                        GenerateExframe2(vector, sr);
                    493:                        break;
                    494: 
                    495:                 default:
                    496:                        PANIC("$%08x exception vector %d ?", ppc, vector);
                    497:                        break;
                    498:                }
                    499: 
                    500:                // ベクタにジャンプ
                    501:                JumpVector(vector);
                    502:        } catch (int vector2) {
                    503:                assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector=%d", vector);
                    504: 
                    505:                // バスエラー処理へ
                    506:                ExceptionBuserr(vector2);
                    507:        }
                    508: }
                    509: 
                    510: // バスエラー・アドレスエラー例外処理を行う。
                    511: // 他の例外とは違いが多いので分けた。
                    512: void
                    513: MPU680x0Device::ExceptionBuserr(int vector)
                    514: {
                    515:        assertmsg((vector == M68K::EXCEP_BUSERR || vector == M68K::EXCEP_ADDRERR),
                    516:                "vector=%d", vector);
                    517: 
                    518:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
                    519:        uint32 from = ppc | (IsSuper() ? 1 : 0);
1.1.1.9 ! root      520:        uint32 inst = BranchHistory_m680x0::Exception | vector;
        !           521:        exhist.AddEntry(from, 0, inst);
        !           522:        brhist.AddEntry(from, 0, inst);
1.1.1.8   root      523:        // デバッガに通知 (例外ブレーク用)
                    524:        debugger->NotifyExceptionMain(vector);
                    525: 
                    526:        // 状態を保存
                    527:        uint16 sr = GetSR();
                    528: 
                    529:        // ここで (An)+ で変化したレジスタを命令実行前の状態に巻き戻す。
                    530:        // EA 処理の時点で先にインクリメントしているのだが、バスエラーが
                    531:        // 起きたということは実際にはポストインクリメントは発生しないので、
                    532:        // ここで無条件に巻き戻してよい。SR を書き換えると A7 が切り替わって
                    533:        // しまうので、この巻き戻しは SR を書き換える前のここで行うこと。
                    534:        // 一方、プリデクリメントのケースはこの少し上の ExframeB の中の
                    535:        // コメント参照。
                    536:        restore_reg_pi();
                    537: 
                    538:        // S を立てて T1,T0 を落とす
                    539:        SetSR((GetSR() | M68K::SR_S) & ~M68K::SR_T);
                    540: 
                    541:        try {
                    542:                // フレームを作成。
                    543:                // 実際はショート($A)、ロング($B)の2種類あって、本来ならショートが
                    544:                // 使えればショートを使うのだが、ここでは全部ロングを使う。
                    545:                GenerateExframeB(vector, sr);
                    546:                // ベクタにジャンプ
                    547:                JumpVector(vector);
                    548:        } catch (int vector2) {
                    549:                // ここに来るのはバスエラーだけのはず
                    550:                assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector=%d", vector);
                    551: 
                    552:                // バスエラー・アドレスエラー処理中のバスエラーは
                    553:                // ダブルバスフォールト。
                    554:                DoubleBusFault("bus/address error handling");
                    555:        }
                    556: }
                    557: 
                    558: // 割り込み例外処理を行う。
                    559: // 割り込みの受け付けとレベルのチェック等の後、次命令境界で呼ばれるやつ。
                    560: int
                    561: MPU680x0Device::ExceptionInterrupt()
                    562: {
                    563:        int cycle_start = used_cycle;
                    564:        int level = intr_level;
                    565: 
                    566:        // ユーザーズマニュアル(日本語) p.399 図8-5 の中ほど
                    567:        // 「/IPEND をネゲート、割り込みアクノリッジサイクルを実行」
                    568:        // 以降に相当。
                    569: 
                    570:        // STOP なら解除
                    571:        ChangeState(CPU_STATE_NORMAL);
                    572: 
                    573:        // 割り込みアクノリッジサイクルを実行
                    574:        int vector = interruptdev->InterruptAcknowledge(level);
                    575:        if (vector == -1) {
                    576:                vector = 24 + level;
                    577:        }
                    578: 
                    579:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
                    580:        uint32 from = ppc | (IsSuper() ? 1 : 0);
1.1.1.9 ! root      581:        uint32 inst = BranchHistory_m680x0::Exception | vector;
1.1.1.8   root      582:        exhist.AddEntry(from, 0, inst);
                    583:        brhist.AddEntry(from, 0, inst);
                    584:        // デバッガに通知 (例外ブレーク用)
                    585:        debugger->NotifyExceptionMain(vector);
                    586: 
                    587:        // 状態を保存
                    588:        uint16 oldsr = GetSR();
                    589: 
                    590:        // S を立てて T1,T0 を落とす。割り込みレベルも変更。
                    591:        uint16 newsr = GetSR() & ~(M68K::SR_T | M68K::SR_IMASK);
                    592:        newsr |= M68K::SR_S;
                    593:        newsr |= level << 8;
                    594:        SetSR(newsr);
                    595: 
                    596:        try {
                    597:                // 例外スタックフレーム $0 を生成。
                    598:                // スタックに積む PC は次の命令位置。
                    599:                // M ビットは未実装なのでスローアウェイとか無視
                    600:                GenerateExframe0(vector, reg.pc, oldsr);
                    601: 
                    602:                // ベクタにジャンプ
                    603:                JumpVector(vector);
                    604:        } catch (int vector2) {
                    605:                assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector=%d", vector);
                    606: 
                    607:                // バスエラー処理へ
                    608:                ExceptionBuserr(vector2);
                    609:        }
                    610: 
                    611:        return used_cycle - cycle_start;
                    612: }
                    613: 
                    614: // RTE 命令。
                    615: // 例外処理の近くに置いておくほうが便利なので。
                    616: void
                    617: MPU680x0Device::ops_rte()
                    618: {
                    619:        uint32 pc;
                    620:        uint16 sr;
                    621:        uint16 frame;
                    622: 
                    623:        try {
                    624:                sr = pop_16();
                    625:                pc = pop_32();
                    626:                frame = pop_16();
                    627:                switch (frame >> 12) {
                    628:                 case 0:
                    629:                        CYCLE2(18, 20);
                    630:                        SetSR(sr);
                    631:                        Jump(pc);
                    632:                        break;
                    633: 
                    634:                 case 2:
                    635:                        CYCLE2(18, 20);
                    636:                        // +08.L INSTRUCTION ADDRESS を読み捨てる
                    637:                        reg.A[7] += 4;
                    638:                        SetSR(sr);
                    639:                        Jump(pc);
                    640:                        break;
                    641: 
                    642:                 case 0x0b:
                    643:                 {
                    644:                        uint32 stage_b;
                    645:                        uint16 ssw;
                    646: 
                    647:                        CYCLE(76);
                    648:                        reg.A[7] += 2;                                          // $08.W
                    649:                        ssw = pop_16();                                         // $0a.W SSW
                    650:                        reg.A[7] += 4 * 6;                                      // $0c.L*6
                    651:                        stage_b = pop_32();                                     // $24.L Stage B
                    652:                        reg.A[7] += 2 * 9;                                      // $28.W*9
                    653:                        // $3a..$58 ここが save_pd の取り出し
                    654:                        flag_pd = pop_16();
                    655:                        for (int i = 0; i < 8; i++) {
                    656:                                save_pd[i] = pop_32();
                    657:                        }
                    658:                        // A7 レジスタをリストアするかもしれない前に Super/User を
                    659:                        // 復帰しておかないといけない
                    660:                        SetSR(sr);
                    661: 
                    662:                        // DFビットセットなら命令を再実行するため、-(An) で変化
                    663:                        // したレジスタを巻き戻す。
                    664:                        // DFビットクリアなら例外要因の命令はハンドラで処理された
                    665:                        // とみなして、次の命令に進む。
                    666:                        if ((ssw & M68K::SSW_DF)) {
                    667:                                restore_reg_pd();
                    668:                        } else {
                    669:                                pc = stage_b - 2;
                    670:                        }
                    671:                        Jump(pc);
                    672:                        break;
                    673:                 }
                    674: 
                    675:                 default:
                    676:                        PANIC("RTE frame=$%x not supported", frame >> 12);
                    677:                        break;
                    678:                }
                    679:        } catch (int vector2) {
                    680:                assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector2=%d", vector2);
                    681: 
                    682:                // RTE 処理中のバスエラーはダブルバスフォールト。
                    683:                DoubleBusFault("bus/address error handling");
                    684:        }
                    685: }
                    686: 
                    687: // STOP 命令。
                    688: void
                    689: MPU680x0Device::ops_stop()
                    690: {
                    691:        uint32 data = fetch_16();
                    692:        SetSR(data);
                    693:        ChangeState(CPU_STATE_STOP);
                    694: 
                    695:        MakeNextFull();
1.1       root      696: }

unix.superglobalmegacorp.com

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