Annotation of nono/m680x0/m68030subr.cpp, revision 1.1.1.2

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 "m68030core.h"
                      8: #include "m68030bus.h"
                      9: #include "m68030fpu.h"
                     10: 
                     11: static void m68030_change_intr(m68kcpu *, int);
                     12: static void m68030_set_intr(m68kcpu *, int);
                     13: static void m68030_double_bus_fault(m68kcpu *, const char *);
                     14: 
                     15: // CPU コアの領域を確保して初期化
                     16: // reset_vector はリセット例外時に 0 番地に見せる(通常ROMの)アドレス。
                     17: m68kcpu *
                     18: m68030_init(uint32 reset_vector)
                     19: {
                     20:        m68kcpu *cpu;
                     21: 
                     22:        cpu = new m68kcpu();
                     23:        fpu_init(cpu);
                     24: 
                     25:        for (int i = 0; i < 16; i++) {
                     26:                RegR(i) = 0xcccccccc;
                     27:        }
                     28:        // XXX ただし X68030 IPLROM には A6 を初期化せずに書き込んでいるバグが
                     29:        // あるため、A6 を概ね RAM のあるあたりに指定しておく…。
                     30:        RegA(6) = 0x000ccccc;
                     31: 
                     32:        // 手抜きのためリセットベクタを知っている
                     33:        cpu->reset_vector = reset_vector;
                     34: 
                     35:        return cpu;
                     36: }
                     37: 
                     38: // 二重バスフォールト
                     39: static void
                     40: m68030_double_bus_fault(m68kcpu *cpu, const char *where)
                     41: {
1.1.1.2 ! root       42:        cpu->atomic_reqflag |= CPU_REQ_RELEASE | CPU_REQ_HALT;
        !            43: 
        !            44:        // コールバックがあれば呼び出す
        !            45:        if (cpu->halt_callback) {
        !            46:                cpu->halt_callback(cpu->halt_arg);
        !            47:        }
1.1       root       48: }
                     49: 
                     50: // リセット例外を発生させる。
                     51: // 各レジスタを所定の状態にして、リセットベクタを読み込む。
                     52: // リセットベクタが読み込めなければ HALT 状態に移行。
                     53: void
                     54: m68030_exception_reset(m68kcpu *cpu)
                     55: {
                     56:        // 1. T0, T1 クリア
                     57:        // 2. S をセット、M をクリア
                     58:        // 3. 割り込みレベルを 7
                     59: 
                     60:        // ここは set_sr を使わずに設定する。
                     61:        cpu->reg.s = true;
                     62:        cpu->reg.m = false;
                     63:        cpu->bus.SetFC2(cpu->reg.s);
                     64:        // ここは割り込みレベル変化のチェックは不要でセットだけでいい。
                     65:        m68030_set_intr(cpu, 7);
                     66: 
                     67:        // 4. VBR をクリア
                     68:        RegVBR = 0;
                     69:        // 5. キャッシュ
                     70:        RegCACR = 0;    // XXX
                     71:        // 6. キャッシュエントリクリア
                     72:        // 7. TC:E、TTn:E をクリア
                     73:        cpu->SetTC(cpu->GetTC() & ~m68030TC::TC_E);
                     74:        cpu->SetTT(0, cpu->GetTT(0) & ~m68030TT::E);
                     75:        cpu->SetTT(1, cpu->GetTT(1) & ~m68030TT::E);
                     76:        // 8. リセットベクタ生成
                     77: 
                     78:        // 9. SP をロード
                     79:        // 10. PC をロード
                     80: 
                     81:        // 手抜き。
                     82:        // XXX 本当は ROM を 0番地に見せかけてから 0番地からロードするのだが
                     83:        //     ぶっちゃけそれを外部から観測する手段もないのでなー。
                     84:        // XXX FC を気にしないといけない
                     85:        // XXX 読めなければ二重バスフォールト
                     86:        // 本当はアドレスエラーもチェックするのだが、起きないので省略。
                     87:        try {
                     88:                RegA(7) = m68030_read_32(cpu, cpu->reset_vector);
                     89:                RegPC = m68030_read_32(cpu, cpu->reset_vector + 4);
                     90:        } catch (int) {
                     91:                m68030_double_bus_fault(cpu, "reset exception");
                     92:        }
                     93: }
                     94: 
                     95: // MPU 外部からの割り込み受付。
                     96: // オートベクタの場合は vector にオートベクタの例外ベクタを指定のこと。
                     97: void
                     98: m68030_interrupt(m68kcpu *cpu, int level, int vector)
                     99: {
                    100:        std::unique_lock<std::mutex> lock(cpu->intrmtx);
                    101: 
                    102:        // この割り込みレベルがすでにペンディングなら何もしない
                    103:        if ((int8)(cpu->intr_pending << level) < 0) {
                    104:                return;
                    105:        }
                    106: 
                    107:        // 割り込みを受理
                    108:        cpu->intr_pending |= (0x80U >> level);
                    109:        cpu->intr_vector[level] = vector;
                    110:        cpu->atomic_reqflag |= CPU_REQ_INTR;
                    111: }
                    112: 
                    113: // 割り込みレベルの設定のみを行う。
                    114: // 割り込みチェックは行わない。
                    115: static void
                    116: m68030_set_intr(m68kcpu *cpu, int level)
                    117: {
                    118:        cpu->reg.intr_level = level;
                    119:        cpu->intr_mask = 0x7f >> level;
                    120: }
                    121: 
                    122: // 割り込みのチェックとレベルの変更。
                    123: // ステータスレジスタの割り込みレベルを変更し、必要な割り込みチェックを行う。
                    124: static void
                    125: m68030_change_intr(m68kcpu *cpu, int level)
                    126: {
                    127:        int oldlevel = cpu->reg.intr_level;
                    128: 
                    129:        if (oldlevel < 7 && level == 7) {
                    130:                // レベル 7 に引き上げられたら割り込み確認
                    131:                cpu->atomic_reqflag |= CPU_REQ_INTR;
                    132:        } else if (oldlevel == 7 && level < 7) {
                    133:                // レベル 7 から引き下げられたら割り込み確認
                    134:                cpu->atomic_reqflag |= CPU_REQ_INTR;
                    135:        } else if (oldlevel != level) {
                    136:                // それ以外でレベルが変わったら割り込み確認?
                    137:                cpu->atomic_reqflag |= CPU_REQ_INTR;
                    138:        }
                    139:        m68030_set_intr(cpu, level);
                    140: }
                    141: 
                    142: // SR (と CCR) に data を代入する。
                    143: // リセット例外時には呼ばれないのであっちで必要に応じて似た処理をする必要が
                    144: // ある。XXX なんとかしたほうがいい
                    145: void
                    146: m68030_set_sr(m68kcpu *cpu, uint16 data)
                    147: {
                    148:        bool oldS = cpu->reg.s;
                    149:        bool oldM = cpu->reg.m;
                    150: 
                    151:        // 現在の SP を保存
                    152:        if (oldS == false) {
                    153:                RegUSP = RegA(7);
                    154:        } else if (oldM == false) {
                    155:                RegISP = RegA(7);
                    156:        } else {
                    157:                RegMSP = RegA(7);
                    158:        }
                    159: 
                    160:        CCR.Set(data);
                    161:        cpu->reg.s = ((data & M68K_SR_S) != 0);
                    162:        cpu->reg.m = ((data & M68K_SR_M) != 0);
                    163:        m68030_change_intr(cpu, (data >> 8) & 7);
                    164: 
                    165:        // 新しい SP を用意
                    166:        if (cpu->reg.s == false) {
                    167:                RegA(7) = RegUSP;
                    168:        } else if (cpu->reg.m == false) {
                    169:                RegA(7) = RegISP;
                    170:        } else {
                    171:                RegA(7) = RegMSP;
                    172:        }
                    173: 
                    174:        // バスの FC2 を変更
                    175:        cpu->bus.SetFC2(cpu->reg.s);
                    176: 
                    177:        // XXX 他に何か状態変えないといけないことあったっけか。
                    178: }
                    179: 
                    180: // 命令中に (An)+ で変化したアドレスレジスタを命令実行前の状態に巻き戻す。
                    181: // flag_pi は bit7..0 が save_pi[7..0] の A7..A0 に対応している。
                    182: void
                    183: m68030_restore_reg_pi(m68kcpu *cpu)
                    184: {
                    185:        for (int i = 7; cpu->flag_pi; i--) {
                    186:                if ((int8)cpu->flag_pi < 0) {
                    187:                        RegA(i) = cpu->save_pi[i];
                    188:                }
                    189:                cpu->flag_pi <<= 1;
                    190:        }
                    191: }
                    192: 
                    193: // 命令中に -(An) で変化したアドレスレジスタを命令実行前の状態に巻き戻す。
                    194: // flag_pd は bit7..0 が save_pd[7..0] の A7..A0 に対応している。
                    195: void
                    196: m68030_restore_reg_pd(m68kcpu *cpu)
                    197: {
                    198:        for (int i = 7; cpu->flag_pd; i--) {
                    199:                if ((int8)cpu->flag_pd < 0) {
                    200:                        RegA(i) = cpu->save_pd[i];
                    201:                }
                    202:                cpu->flag_pd <<= 1;
                    203:        }
                    204: }
                    205: 
                    206: // 例外処理について。
                    207: //
                    208: // 0. リセット例外
                    209: //     リセット例外は外部から m68030_exception_reset() を呼び出す。
                    210: //
                    211: // 1. バスエラー例外
                    212: //     物理アドレス空間アクセス後のバスエラーは、物理空間側(VM側)から
                    213: //     (C++の)例外がスローされるので、catch したところで処理する。
                    214: //
                    215: //     MMU による論理アドレスでのバスエラーについては後で考える。
                    216: //
                    217: // 2. アドレスエラー例外
                    218: //     アドレスエラーは m68030_jump() 内でのみ発生するはずで、その場で
                    219: //     例外処理をするはず。
                    220: //
                    221: // 3. 命令中で起きる例外
                    222: //     命令途中で起きる(確定的な)例外は m68030_exception() を呼び出す。
                    223: //     これに該当するのは
                    224: //       o 特権違反
                    225: //       o A系列/F系列命令
                    226: //       o TRAP* 系命令、CHK/CHK2 命令
                    227: //       o トレース例外 (未実装)
                    228: //       o ゼロ除算?
                    229: //       o MMU 構成例外
                    230: //       o 不当命令 (*)
                    231: //     である。
                    232: //     ただし、不当命令についてはどこで不当命令と判定されるかによって
                    233: //     フローが複数存在することに注意。
                    234: //       o 1ワード目が不当命令
                    235: //             -> 命令がそれぞれ m68030_exception() で処理。
                    236: //       o 1ワード目の EA が不当命令
                    237: //             -> (C++の)例外スローして catch 内で処理。
                    238: //       o 2ワード目が不当命令
                    239: //             -> 命令がそれぞれ m68030_exception() で処理。
                    240: //
                    241: // 4. 割り込み例外
                    242: //     zzz
                    243: 
                    244: // vector にジャンプする。vector はベクタ番号(アドレスではない)。
                    245: static inline void
                    246: m68030_jump_vector(m68kcpu *cpu, int vector)
                    247: {
                    248:        uint32 newpc;
                    249: 
                    250:        RegPC = RegVBR + vector * 4;
                    251:        newpc = m68030_fetch_32(cpu);
                    252:        m68030_jump(cpu, newpc);
1.1.1.2 ! root      253: 
        !           254:        // 実際はここでパイプライン充填のために3ワードフェッチするので、
        !           255:        // ベクタテーブルはフェッチ出来たけどそのジャンプ先がバスエラーに
        !           256:        // なるケースはここでバスエラーが出なければいけないが、まだ
        !           257:        // キャッシュを実装していないので、ここで1ワードフェッチしてみて
        !           258:        // PC を戻すあほっぽい方法を取る。
        !           259:        m68030_fetch_16(cpu);
        !           260:        RegPC -= 2;
1.1       root      261: }
                    262: 
                    263: // 例外スタックフレーム $0 を生成する。
                    264: // vector はベクタ番号。
                    265: // pc はスタックに積むプログラムカウンタの値 (例外によって、この命令位置か
                    266: // 次の命令位置かが異なる)。
                    267: // sr は例外発生時の SR。
                    268: static inline void
                    269: m68030_generate_exframe_0(m68kcpu *cpu, int vector, uint32 pc, uint16 sr)
                    270: {
                    271:        // 例外スタックフレーム $0
                    272:        // SP+$00.W STATUS REGISTER
                    273:        //   +$02.L PROGRAM COUNTER             ; 例外ごとに異なる
                    274:        //   +$06.W %0000 | VECTOR
                    275: 
                    276:        m68030_push_16(cpu, (0 << 12) | (vector * 4));
                    277:        m68030_push_32(cpu, pc);
                    278:        m68030_push_16(cpu, sr);
                    279: }
                    280: 
                    281: // 例外スタックフレーム $2 を生成する。
                    282: // vector はベクタ番号。
                    283: // スタックに積む PC は常に次の命令。
                    284: static inline void
                    285: m68030_generate_exframe_2(m68kcpu *cpu, int vector, uint16 sr)
                    286: {
                    287:        // 例外スタックフレーム $2
                    288:        // SP+$00.W STATUS REGISTER
                    289:        //   +$02.L PROGRAM COUNTER             ; 次の命令位置
                    290:        //   +$06.W %0010 | VECTOR
                    291:        //   +$08.L INSTRUCTION ADDRESS ; 例外を起こした命令のアドレス
                    292: 
                    293:        m68030_push_32(cpu, RegPPC);    // 例外を起こした命令のアドレス
                    294:        m68030_push_16(cpu, (2 << 12) | (vector * 4));
                    295:        m68030_push_32(cpu, RegPC);             // 次の命令位置
                    296:        m68030_push_16(cpu, sr);
                    297: }
                    298: 
                    299: // 例外スタックフレーム $B を生成する。
                    300: static inline void
                    301: m68030_generate_exframe_b(m68kcpu *cpu, int vector, uint16 sr)
                    302: {
                    303:        uint16 ssw;
                    304:        uint32 fault_addr;
                    305:        uint32 stageBaddr;
                    306: 
                    307:        stageBaddr = RegPC + 2;
                    308:        // この後のスタック操作で bus が変化する前に保存
                    309:        fault_addr = cpu->bus.laddr;
                    310:        // DF ビットを立てておくと RTE した後この命令を再実行。
                    311:        ssw = cpu->bus.ssw | SSW_DF;
                    312: 
                    313:        // 例外スタックフレーム $B
                    314:        // SP+$00.W   STATUS REGISTER
                    315:        //   +$02.L   PROGRAM COUNTER
                    316:        //   +$06.W   %1011 | VECTOR
                    317:        //   +$08.W   (internal register)
                    318:        //   +$0a.W   SPECIAL STATUS REGISTER           ; SSW
                    319:        //   +$0c.W   INSTRUCTION PIPE STAGE C
                    320:        //   +$0e.W   INSTRUCTION PIPE STAGE B
                    321:        //   +$10.L   DATA CYCLE FAULT ADDRESS
                    322:        //   +$14.W*2 (internal register)
                    323:        //   +$18.L   DATA OUTPUT BUFFER
                    324:        //   +$1c.W*4 (internal register, 4 words)
                    325:        //   +$24.L   STAGE B ADDRESS
                    326:        //   +$28.W*2 (internal register, 2 words)
                    327:        //   +$2c.L   DATA INPUT BUFFER
                    328:        //   +$30.W*3 (internal register, 3 words)
                    329:        //   +$36.W   VERSION# | internal information
                    330:        //   +$38.W*18 (internal register, 18 words)
                    331:        //   +$5a
                    332:        //      こっちから上に向かって PUSH
                    333: 
                    334:        // internal registers, 18 words
                    335:        // 内部レジスタ18ワードのうち、ここでは17ワード分を save_pd[8] (16ワード)、
                    336:        // flag_pd (1ワード) として使うことにする。
                    337:        // -(An) でバスエラーが起きると An は減算された状態になるが、DF ビットが
                    338:        // 立っていて再実行する時には現行構造では命令先頭から再実行せざるをえず、
                    339:        // そうするともう一度プリデクリメントが動いてしまう。そのため、RTE の時点
                    340:        // で DF=1 ならプリデクリメント発生前の An に戻すという処理をする。
                    341:        // RTE 時点で DF=0 なら命令を再実行しないため An も巻き戻してはならず、
                    342:        // そのためプリデクリメント分の巻き戻しは RTE 時点まで行えない。
1.1.1.2 ! root      343:        // 一方、ポストインクリメントのケースはこの少し下の
        !           344:        // m68030_exception_buserr() 内のコメント参照。
1.1       root      345:        for (int i = 7; i >= 0; i--) {
                    346:                m68030_push_32(cpu, cpu->save_pd[i]);
                    347:        }
                    348:        m68030_push_16(cpu, cpu->flag_pd);
                    349:        RegA(7) -= 2;
                    350: 
                    351:        RegA(7) -= 2;                                           // VERSION#
                    352:        RegA(7) -= 6;
                    353:        m68030_push_32(cpu, 0);                         // DATA INPUT BUFFER
                    354:        RegA(7) -= 4;
                    355:        m68030_push_32(cpu, stageBaddr);        // STAGE B ADDRESS
                    356:        RegA(7) -= 8;
                    357:        m68030_push_32(cpu, 0);                         // DATA OUTPUT BUFFER
                    358:        RegA(7) -= 4;
                    359:        m68030_push_32(cpu, fault_addr);        // DATA CYCLE FAULT ADDRESS
                    360:        m68030_push_16(cpu, 0);                         // INSTRUCTION PIPE STAGE B
                    361:        m68030_push_16(cpu, 0);                         // INSTRUCTION PIPE STAGE C
                    362:        m68030_push_16(cpu, ssw);
                    363:        RegA(7) -= 2;
                    364:        m68030_push_16(cpu, 0xb000 | (vector << 2));
                    365:        // 本当は現在の PC だが、再実行のため PPC を積む。
                    366:        m68030_push_32(cpu, RegPPC);            // PC
                    367:        m68030_push_16(cpu, sr);                        // 例外入り口で保存した SR
                    368: }
                    369: 
                    370: // 例外処理 (リセット・割り込み以外) を行う。
                    371: // vector はベクタ番号。
                    372: void
                    373: m68030_exception(m68kcpu *cpu, int vector)
                    374: {
1.1.1.2 ! root      375:        // バスエラー・アドレスエラーは別で処理。
        !           376:        if (vector <= M68K_EXCEP_ADDRERR) {
        !           377:                m68030_exception_buserr(cpu, vector);
        !           378:                return;
        !           379:        }
        !           380: 
1.1       root      381:        // 状態を保存
                    382:        uint16 sr = RegSR;
                    383: 
                    384:        // S を立てて T1,T0 を落とす
                    385:        m68030_set_sr(cpu, (RegSR | M68K_SR_S) & ~M68K_SR_T);
                    386: 
1.1.1.2 ! root      387:        try {
        !           388:                switch (vector) {
        !           389:                 case M68K_EXCEP_ILLEGAL:               // 不当命令
        !           390:                 case M68K_EXCEP_PRIV:                  // 特権違反例外
        !           391:                 case M68K_EXCEP_ALINE:                 // Aライン命令例外
        !           392:                 case M68K_EXCEP_FLINE:                 // Fライン命令例外
        !           393:                        // スタックに積む PC はこの命令のアドレス
        !           394:                        m68030_generate_exframe_0(cpu, vector, RegPPC, sr);
        !           395:                        break;
        !           396: 
        !           397:                 case M68K_EXCEP_TRAP0                  // TRAP#0
        !           398:                  ... M68K_EXCEP_TRAP15:                // TRAP#15
        !           399:                        // スタックに積む PC は次の命令
        !           400:                        m68030_generate_exframe_0(cpu, vector, RegPC, sr);
        !           401:                        break;
        !           402: 
        !           403:                 case M68K_EXCEP_ZERODIV:               // ゼロ除算
        !           404:                 case M68K_EXCEP_CHK:                   // CHK
        !           405:                 case M68K_EXCEP_TRAPV:                 // TRAPV
        !           406:                 case M68K_EXCEP_MMU_CONFIG:    // MMU 構成例外
        !           407:                        m68030_generate_exframe_2(cpu, vector, sr);
        !           408:                        break;
        !           409: 
        !           410:                 default:
        !           411:                        PANIC("$%08x exception vector %d ?", RegPPC, vector);
        !           412:                        break;
1.1       root      413:                }
                    414: 
1.1.1.2 ! root      415:                // ベクタにジャンプ
        !           416:                m68030_jump_vector(cpu, vector);
        !           417:        } catch (int vector2) {
        !           418:                assertmsg(vector2 == M68K_EXCEP_BUSERR, "vector=%d", vector);
1.1       root      419: 
1.1.1.2 ! root      420:                // バスエラー処理へ
        !           421:                m68030_exception_buserr(cpu, vector2);
1.1       root      422:        }
1.1.1.2 ! root      423: }
        !           424: 
        !           425: // バスエラー・アドレスエラー例外処理を行う。
        !           426: // 他の例外とは違いが多いので分けた。
        !           427: void
        !           428: m68030_exception_buserr(m68kcpu *cpu, int vector)
        !           429: {
        !           430:        assertmsg((vector == M68K_EXCEP_BUSERR || vector == M68K_EXCEP_ADDRERR),
        !           431:                "vector=%d", vector);
        !           432: 
        !           433:        // 状態を保存
        !           434:        uint16 sr = RegSR;
1.1       root      435: 
1.1.1.2 ! root      436:        // ここで (An)+ で変化したレジスタを命令実行前の状態に巻き戻す。
        !           437:        // EA 処理の時点で先にインクリメントしているのだが、バスエラーが
        !           438:        // 起きたということは実際にはポストインクリメントは発生しないので、
        !           439:        // ここで無条件に巻き戻してよい。SR を書き換えると A7 が切り替わって
        !           440:        // しまうので、この巻き戻しは SR を書き換える前のここで行うこと。
        !           441:        // 一方、プリデクリメントのケースはこの少し上の exframe_b の中の
        !           442:        // コメント参照。
        !           443:        m68030_restore_reg_pi(cpu);
        !           444: 
        !           445:        // S を立てて T1,T0 を落とす
        !           446:        m68030_set_sr(cpu, (RegSR | M68K_SR_S) & ~M68K_SR_T);
        !           447: 
        !           448:        try {
        !           449:                // フレームを作成。
        !           450:                // 実際はショート($A)、ロング($B)の2種類あって、本来ならショートが
        !           451:                // 使えればショートを使うのだが、ここでは全部ロングを使う。
        !           452:                m68030_generate_exframe_b(cpu, vector, sr);
        !           453:                // ベクタにジャンプ
        !           454:                m68030_jump_vector(cpu, vector);
        !           455:        } catch (int vector2) {
        !           456:                // ここに来るのはバスエラーだけのはず
        !           457:                assertmsg(vector2 == M68K_EXCEP_BUSERR, "vector=%d", vector);
        !           458: 
        !           459:                // バスエラー・アドレスエラー処理中のバスエラーは
        !           460:                // ダブルバスフォールト。
        !           461:                m68030_double_bus_fault(cpu, "bus/address error handling");
        !           462:        }
1.1       root      463: }
                    464: 
                    465: // 割り込み例外処理を行う。
                    466: // intrmtx なしで呼び出すこと。
                    467: // 割り込みチェックは m68030core.cpp::m68030_flush_interrupt() で判定している。
                    468: void
                    469: m68030_exception_interrupt(m68kcpu *cpu, int level, int vector)
                    470: {
                    471:        if (0) {
                    472:                cpulog(2, "Interrupt lv=%d vec=%d occured: %s",
                    473:                        level, vector, m68030_get_exception_name(vector));
                    474:        }
                    475: 
                    476:        // 状態を保存
                    477:        uint16 sr = RegSR;
                    478: 
                    479:        // S を立てて T1,T0 を落とす
                    480:        m68030_set_sr(cpu, (RegSR | M68K_SR_S) & ~M68K_SR_T);
                    481:        // 割り込みレベルを変更
                    482:        m68030_change_intr(cpu, level);
                    483: 
1.1.1.2 ! root      484:        try {
        !           485:                // 例外スタックフレーム $0 を生成。
        !           486:                // スタックに積む PC は次の命令位置。
        !           487:                // M ビットは未実装なのでスローアウェイとか無視
        !           488:                m68030_generate_exframe_0(cpu, vector, RegPC, sr);
1.1       root      489: 
1.1.1.2 ! root      490:                // ベクタにジャンプ
        !           491:                m68030_jump_vector(cpu, vector);
        !           492:        } catch (int vector2) {
        !           493:                assertmsg(vector2 == M68K_EXCEP_BUSERR, "vector=%d", vector);
        !           494: 
        !           495:                // バスエラー処理へ
        !           496:                m68030_exception_buserr(cpu, vector2);
        !           497:        }
1.1       root      498: }
                    499: 
                    500: // RTE 命令。
                    501: // 例外処理の近くに置いておくほうが便利なので。
                    502: void
                    503: m68030_rte(m68kcpu *cpu)
                    504: {
                    505:        uint32 pc;
                    506:        uint16 sr;
                    507:        uint16 frame;
                    508: 
1.1.1.2 ! root      509:        try {
        !           510:                sr = m68030_pop_16(cpu);
        !           511:                pc = m68030_pop_32(cpu);
        !           512:                frame = m68030_pop_16(cpu);
        !           513:                switch (frame >> 12) {
        !           514:                 case 0:
        !           515:                        CYCLE2(18, 20);
        !           516:                        m68030_set_sr(cpu, sr);
        !           517:                        m68030_jump(cpu, pc);
        !           518:                        break;
        !           519: 
        !           520:                 case 2:
        !           521:                        CYCLE2(18, 20);
        !           522:                        // +08.L INSTRUCTION ADDRESS を読み捨てる
        !           523:                        RegA(7) += 4;
        !           524:                        m68030_set_sr(cpu, sr);
        !           525:                        m68030_jump(cpu, pc);
        !           526:                        break;
        !           527: 
        !           528:                 case 0x0b:
        !           529:                 {
        !           530:                        uint32 stage_b;
        !           531:                        uint16 ssw;
        !           532: 
        !           533:                        CYCLE(76);
        !           534:                        RegA(7) += 2;                                           // $08.W
        !           535:                        ssw = m68030_pop_16(cpu);                       // $0a.W SSW
        !           536:                        RegA(7) += 4 * 6;                                       // $0c.L*6
        !           537:                        stage_b = m68030_pop_32(cpu);           // $24.L Stage B
        !           538:                        RegA(7) += 2 * 9;                                       // $28.W*9
        !           539:                        // $3a..$58 ここが save_pd の取り出し
        !           540:                        cpu->flag_pd = m68030_pop_16(cpu);
        !           541:                        for (int i = 0; i < 8; i++) {
        !           542:                                cpu->save_pd[i] = m68030_pop_32(cpu);
        !           543:                        }
        !           544:                        // A7 レジスタをリストアするかもしれない前に Super/User を
        !           545:                        // 復帰しておかないといけない
        !           546:                        m68030_set_sr(cpu, sr);
        !           547: 
        !           548:                        // DFビットセットなら命令を再実行するため、-(An) で変化
        !           549:                        // したレジスタを巻き戻す。
        !           550:                        // DFビットクリアなら例外要因の命令はハンドラで処理された
        !           551:                        // とみなして、次の命令に進む。
        !           552:                        if ((ssw & SSW_DF)) {
        !           553:                                m68030_restore_reg_pd(cpu);
        !           554:                        } else {
        !           555:                                pc = stage_b - 2;
        !           556:                        }
        !           557:                        m68030_jump(cpu, pc);
        !           558:                        break;
        !           559:                 }
        !           560: 
        !           561:                 default:
        !           562:                        PANIC("RTE frame=$%x not supported", frame >> 12);
        !           563:                        break;
1.1       root      564:                }
1.1.1.2 ! root      565:        } catch (int vector2) {
        !           566:                assertmsg(vector2 == M68K_EXCEP_BUSERR, "vector2=%d", vector2);
1.1       root      567: 
1.1.1.2 ! root      568:                // RTE 処理中のバスエラーはダブルバスフォールト。
        !           569:                m68030_double_bus_fault(cpu, "bus/address error handling");
1.1       root      570:        }
                    571: }
                    572: 
                    573: static const char * const exception_name_table[] = {
                    574:        /*  0 */        "Reset",
                    575:        /*  1 */        NULL,
                    576:        /*  2 */        "Bus Error",
                    577:        /*  3 */        "Address Error",
                    578:        /*  4 */        "Illegal Instruction",
                    579:        /*  5 */        "Div by Zero",
                    580:        /*  6 */        "CHK/CHK2 Instruction",
                    581:        /*  7 */        "TRAP Instruction",
                    582:        /*  8 */        "Priviledge Violation",
                    583:        /*  9 */        "Trace",
                    584:        /* 10 */        "A line emulation",
                    585:        /* 11 */        "F line emulation",
                    586:        /* 12 */        NULL,
                    587:        /* 13 */        "Co-processor",
                    588:        /* 14 */        "Format",
                    589:        /* 15 */        NULL,
                    590:        /* 16 */        "Uninitialized Interrupt",
                    591:        /* 17 */        NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                    592:        /* 24 */        "Spurious Interrupt",
                    593:        /* 25 */        "Level 1 Interrupt",
                    594:        /* 26 */        "Level 2 Interrupt",
                    595:        /* 27 */        "Level 3 Interrupt",
                    596:        /* 28 */        "Level 4 Interrupt",
                    597:        /* 29 */        "Level 5 Interrupt",
                    598:        /* 30 */        "Level 6 Interrupt",
                    599:        /* 31 */        "Level 7 Interrupt",
                    600:        /* 32 */        "Trap #0",
                    601:        /* 33 */        "Trap #1",
                    602:        /* 34 */        "Trap #2",
                    603:        /* 35 */        "Trap #3",
                    604:        /* 36 */        "Trap #4",
                    605:        /* 37 */        "Trap #5",
                    606:        /* 38 */        "Trap #6",
                    607:        /* 39 */        "Trap #7",
                    608:        /* 40 */        "Trap #8",
                    609:        /* 41 */        "Trap #9",
                    610:        /* 42 */        "Trap #10",
                    611:        /* 43 */        "Trap #11",
                    612:        /* 44 */        "Trap #12",
                    613:        /* 45 */        "Trap #13",
                    614:        /* 46 */        "Trap #14",
                    615:        /* 47 */        "Trap #15",
                    616:        /* 48 */        "FPCP Branch",
                    617:        /* 49 */        "FPCP Inexcact",
                    618:        /* 50 */        "FPCP Div by Zero",
                    619:        /* 51 */        "FPCP UnderFlow",
                    620:        /* 52 */        "FPCP Operation Error",
                    621:        /* 53 */        "FPCP OverFlow",
                    622:        /* 54 */        "FPCP SNAN",
                    623:        /* 55 */        NULL,
                    624:        /* 56 */        "MMU Configuration Error",
                    625:        /* 57 */        NULL,
                    626:        /* 58 */        NULL,
                    627:        /* 59 */        NULL,
                    628:        /* 60 */        NULL,
                    629:        /* 61 */        NULL,
                    630:        /* 62 */        NULL,
                    631:        /* 63 */        NULL,
                    632:        /* 64 */        "MFP Alarm",
                    633:        /* 65 */        "MFP EXPON",
                    634:        /* 66 */        "MFP POWSW",
                    635:        /* 67 */        "MFP FMIRQ",
                    636:        /* 68 */        "MFP Timer-D",
                    637:        /* 69 */        "MFP Timer-C",
                    638:        /* 70 */        "MFP V-Disp",
                    639:        /* 71 */        "MFP GPIP5",
                    640:        /* 72 */        "MFP Timer-B",
                    641:        /* 73 */        "MFP TXError",
                    642:        /* 74 */        "MFP TXEmpty",
                    643:        /* 75 */        "MFP RXError",
                    644:        /* 76 */        "MFP RXFull",
                    645:        /* 77 */        "MFP Timer-A",
                    646:        /* 78 */        "MFP CIRQ",
                    647:        /* 79 */        "MFP H-Sync",
                    648: };
                    649: 
                    650: // ベクタ番号から表示名を返す
                    651: const char *
                    652: m68030_get_exception_name(int vector)
                    653: {
                    654:        const char *name = NULL;
                    655:        if (vector < countof(exception_name_table)) {
                    656:                name = exception_name_table[vector];
                    657:        }
                    658:        if (name == NULL) {
                    659:                name = "(reserved?)";
                    660:        }
                    661:        return name;
                    662: }

unix.superglobalmegacorp.com

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