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

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

unix.superglobalmegacorp.com

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