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

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"
1.1.1.3   root       10: #include "debugger.h"
1.1.1.7   root       11: #include "scheduler.h"
1.1       root       12: 
                     13: static void m68030_change_intr(m68kcpu *, int);
                     14: static void m68030_set_intr(m68kcpu *, int);
                     15: static void m68030_double_bus_fault(m68kcpu *, const char *);
                     16: 
                     17: // CPU コアの領域を確保して初期化
                     18: m68kcpu *
1.1.1.8 ! root       19: m68030_init()
1.1       root       20: {
                     21:        m68kcpu *cpu;
                     22: 
                     23:        cpu = new m68kcpu();
                     24:        fpu_init(cpu);
                     25: 
                     26:        for (int i = 0; i < 16; i++) {
                     27:                RegR(i) = 0xcccccccc;
                     28:        }
                     29:        // XXX ただし X68030 IPLROM には A6 を初期化せずに書き込んでいるバグが
                     30:        // あるため、A6 を概ね RAM のあるあたりに指定しておく…。
                     31:        RegA(6) = 0x000ccccc;
                     32: 
                     33:        return cpu;
                     34: }
                     35: 
1.1.1.5   root       36: // 仮想時刻を返す
                     37: uint64
                     38: m68030_get_vtime(m68kcpu *cpu)
                     39: {
1.1.1.6   root       40:        return cpu->total_vtime + cpu->Cycle2Vtime(cpu->used_cycle);
1.1.1.5   root       41: }
                     42: 
1.1.1.7   root       43: // クロックを設定する。
                     44: void
                     45: m68030_set_clockspeed(m68kcpu *cpu, uint32 clock_khz_)
                     46: {
                     47:        cpu->clock_khz = clock_khz_;
                     48: 
                     49:        // サイクル数を nsec に変換する際の係数。25MHz なら c2v は 40 [nsec/clock]
                     50:        cpu->c2v = 1000 * 1000 / cpu->clock_khz;
                     51: 
                     52:        // nsec をクロック数に変換する際の係数、つまり c2v の逆数。
                     53:        // (http://hp.vector.co.jp/authors/VA003988/how_to_o.htm#27_2)
                     54:        int b = 32 - __builtin_clz(cpu->c2v) - 1;
                     55:        int r = 32 + b;
                     56:        // 小数部を近接丸め(0捨1入)するため一桁余分に計算しておいて..
                     57:        uint64 f = (1ULL << (r + 1)) / cpu->c2v;
                     58:        // 最下位ビットを丸める
                     59:        if ((f & 1) != 0) {
                     60:                f += 1;
                     61:        }
                     62:        f >>= 1;
                     63: 
                     64:        cpu->v2c_factor = f;
                     65:        cpu->v2c_shift  = r;
                     66: }
                     67: 
1.1       root       68: // 二重バスフォールト
                     69: static void
                     70: m68030_double_bus_fault(m68kcpu *cpu, const char *where)
                     71: {
1.1.1.2   root       72:        cpu->atomic_reqflag |= CPU_REQ_RELEASE | CPU_REQ_HALT;
                     73: 
                     74:        // コールバックがあれば呼び出す
                     75:        if (cpu->halt_callback) {
                     76:                cpu->halt_callback(cpu->halt_arg);
                     77:        }
1.1       root       78: }
                     79: 
1.1.1.8 ! root       80: // 電源オン
        !            81: void
        !            82: m68030_power_on(m68kcpu *cpu)
        !            83: {
        !            84:        // 履歴を初期化。電源(再)投入時のみ行う。
        !            85:        cpu->exhist.Clear();
        !            86:        cpu->brhist.Clear();
        !            87: 
        !            88:        // この後起きるリセット例外で PC を初期化する前に参照することになるので
        !            89:        // これだけここでも初期化しておく。
        !            90:        RegPC = 0;
        !            91: }
        !            92: 
1.1.1.5   root       93: // リセット例外を発生させる。(外部ルーチン)
                     94: void
                     95: m68030_request_reset_exception(m68kcpu *cpu)
                     96: {
                     97:        cpu->atomic_reqflag |= CPU_REQ_RESET;
                     98: }
                     99: 
                    100: // リセット例外処理。
1.1       root      101: // 各レジスタを所定の状態にして、リセットベクタを読み込む。
                    102: // リセットベクタが読み込めなければ HALT 状態に移行。
                    103: void
                    104: m68030_exception_reset(m68kcpu *cpu)
                    105: {
1.1.1.4   root      106:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
1.1.1.8 ! root      107:        // m68k では今の所リセット例外発生時の PC にはあまり意味がないけど、
        !           108:        // m88k と動作を揃えておく。
1.1.1.4   root      109:        // 履歴のリセットベクタは 0 の代わりに 1 を使う仕様になっている。
                    110:        const uint vector = 0;
1.1.1.8 ! root      111:        cpu->exhist.AddEntry(RegPC | 1, 0, 0x8000 | (vector + 1));
        !           112:        cpu->brhist.AddEntry(RegPC | 1, 0, 0x8000 | (vector + 1));
1.1.1.4   root      113:        // デバッガに通知 (例外ブレーク用)。こっちのベクタは 0 のままでよい。
                    114:        debugger_notify_exception(vector);
1.1.1.3   root      115: 
1.1       root      116:        // 1. T0, T1 クリア
                    117:        // 2. S をセット、M をクリア
                    118:        // 3. 割り込みレベルを 7
                    119: 
1.1.1.7   root      120:        // 受け付け中だった割り込みをクリア。
                    121:        // STOP 状態とホールト状態を解除。
1.1.1.5   root      122:        cpu->intr_pending = 0;
1.1.1.7   root      123:        cpu->atomic_reqflag &= ~(CPU_REQ_INTR | CPU_REQ_STOP | CPU_REQ_HALT);
                    124:        cpu->reg.state = Scheduler::SCHED_CPU_NORMAL;
1.1.1.4   root      125: 
1.1       root      126:        // ここは set_sr を使わずに設定する。
                    127:        cpu->reg.s = true;
                    128:        cpu->reg.m = false;
                    129:        cpu->bus.SetFC2(cpu->reg.s);
                    130:        // ここは割り込みレベル変化のチェックは不要でセットだけでいい。
                    131:        m68030_set_intr(cpu, 7);
                    132: 
                    133:        // 4. VBR をクリア
                    134:        RegVBR = 0;
                    135:        // 5. キャッシュ
                    136:        RegCACR = 0;    // XXX
                    137:        // 6. キャッシュエントリクリア
                    138:        // 7. TC:E、TTn:E をクリア
                    139:        cpu->SetTC(cpu->GetTC() & ~m68030TC::TC_E);
                    140:        cpu->SetTT(0, cpu->GetTT(0) & ~m68030TT::E);
                    141:        cpu->SetTT(1, cpu->GetTT(1) & ~m68030TT::E);
                    142:        // 8. リセットベクタ生成
                    143: 
                    144:        // 9. SP をロード
                    145:        // 10. PC をロード
                    146: 
                    147:        // 手抜き。
                    148:        // XXX FC を気にしないといけない
                    149:        // XXX 読めなければ二重バスフォールト
                    150:        // 本当はアドレスエラーもチェックするのだが、起きないので省略。
                    151:        try {
1.1.1.8 ! root      152:                RegA(7) = m68030_read_32(cpu, 0);
        !           153:                RegPC = m68030_read_32(cpu, 4);
1.1.1.4   root      154:                // リセットベクタは常に 0, 4 番地から取得したことになっている
1.1.1.5   root      155:                cpu->brhist.AddEntry(0x00000004 | 1, RegPC, 0x8000);
1.1       root      156:        } catch (int) {
                    157:                m68030_double_bus_fault(cpu, "reset exception");
                    158:        }
                    159: }
                    160: 
1.1.1.5   root      161: // 割り込みを受理
1.1       root      162: void
1.1.1.5   root      163: m68030_interrupt(m68kcpu *cpu, int level)
1.1       root      164: {
1.1.1.5   root      165:        // レベル比較等は VM 側で行ってあるので、ここは割り込みの受理。
                    166:        // といってもフラグを立てるだけで実際の処理はメインループから呼ばれる
                    167:        // m68030_exception_interrupt() (少し下にある) で行っている。
                    168:        cpu->intr_pending = level;
1.1       root      169:        cpu->atomic_reqflag |= CPU_REQ_INTR;
                    170: }
                    171: 
                    172: // 割り込みレベルの設定のみを行う。
                    173: // 割り込みチェックは行わない。
                    174: static void
                    175: m68030_set_intr(m68kcpu *cpu, int level)
                    176: {
                    177:        cpu->reg.intr_level = level;
                    178: }
                    179: 
                    180: // 割り込みのチェックとレベルの変更。
                    181: // ステータスレジスタの割り込みレベルを変更し、必要な割り込みチェックを行う。
                    182: static void
                    183: m68030_change_intr(m68kcpu *cpu, int level)
                    184: {
                    185:        int oldlevel = cpu->reg.intr_level;
                    186: 
                    187:        if (oldlevel < 7 && level == 7) {
                    188:                // レベル 7 に引き上げられたら割り込み確認
                    189:                cpu->atomic_reqflag |= CPU_REQ_INTR;
                    190:        } else if (oldlevel == 7 && level < 7) {
                    191:                // レベル 7 から引き下げられたら割り込み確認
                    192:                cpu->atomic_reqflag |= CPU_REQ_INTR;
                    193:        } else if (oldlevel != level) {
                    194:                // それ以外でレベルが変わったら割り込み確認?
                    195:                cpu->atomic_reqflag |= CPU_REQ_INTR;
                    196:        }
                    197:        m68030_set_intr(cpu, level);
                    198: }
                    199: 
                    200: // SR (と CCR) に data を代入する。
                    201: // リセット例外時には呼ばれないのであっちで必要に応じて似た処理をする必要が
                    202: // ある。XXX なんとかしたほうがいい
                    203: void
                    204: m68030_set_sr(m68kcpu *cpu, uint16 data)
                    205: {
                    206:        bool oldS = cpu->reg.s;
                    207:        bool oldM = cpu->reg.m;
                    208: 
                    209:        // 現在の SP を保存
                    210:        if (oldS == false) {
                    211:                RegUSP = RegA(7);
                    212:        } else if (oldM == false) {
                    213:                RegISP = RegA(7);
                    214:        } else {
                    215:                RegMSP = RegA(7);
                    216:        }
                    217: 
                    218:        CCR.Set(data);
                    219:        cpu->reg.s = ((data & M68K_SR_S) != 0);
                    220:        cpu->reg.m = ((data & M68K_SR_M) != 0);
                    221:        m68030_change_intr(cpu, (data >> 8) & 7);
                    222: 
                    223:        // 新しい SP を用意
                    224:        if (cpu->reg.s == false) {
                    225:                RegA(7) = RegUSP;
                    226:        } else if (cpu->reg.m == false) {
                    227:                RegA(7) = RegISP;
                    228:        } else {
                    229:                RegA(7) = RegMSP;
                    230:        }
                    231: 
                    232:        // バスの FC2 を変更
                    233:        cpu->bus.SetFC2(cpu->reg.s);
                    234: 
                    235:        // XXX 他に何か状態変えないといけないことあったっけか。
                    236: }
                    237: 
                    238: // 命令中に (An)+ で変化したアドレスレジスタを命令実行前の状態に巻き戻す。
                    239: // flag_pi は bit7..0 が save_pi[7..0] の A7..A0 に対応している。
                    240: void
                    241: m68030_restore_reg_pi(m68kcpu *cpu)
                    242: {
                    243:        for (int i = 7; cpu->flag_pi; i--) {
                    244:                if ((int8)cpu->flag_pi < 0) {
                    245:                        RegA(i) = cpu->save_pi[i];
                    246:                }
                    247:                cpu->flag_pi <<= 1;
                    248:        }
                    249: }
                    250: 
                    251: // 命令中に -(An) で変化したアドレスレジスタを命令実行前の状態に巻き戻す。
                    252: // flag_pd は bit7..0 が save_pd[7..0] の A7..A0 に対応している。
                    253: void
                    254: m68030_restore_reg_pd(m68kcpu *cpu)
                    255: {
                    256:        for (int i = 7; cpu->flag_pd; i--) {
                    257:                if ((int8)cpu->flag_pd < 0) {
                    258:                        RegA(i) = cpu->save_pd[i];
                    259:                }
                    260:                cpu->flag_pd <<= 1;
                    261:        }
                    262: }
                    263: 
                    264: // 例外処理について。
                    265: //
                    266: // 0. リセット例外
                    267: //     リセット例外は外部から m68030_exception_reset() を呼び出す。
                    268: //
                    269: // 1. バスエラー例外
1.1.1.3   root      270: //     MMU による論理アドレスでのバスエラーは (m68030_mmu_translate_*() が
                    271: //     false を返した後) m68030bus.cpp ルーチンが (C++の) 例外をスローする。
                    272: //     物理アドレス空間アクセス後のバスエラーは (VM側の read*()/write*() が
                    273: //     (int64)-1 を返した後) m68030bus.cpp ルーチンが (C++) の例外をスローする。
                    274: //     どちらのケースも m68030core.cpp のメインループで catch し、その catch
                    275: //     ブロック内で m68030_exception() を呼び出す。
1.1       root      276: //
                    277: // 2. アドレスエラー例外
                    278: //     アドレスエラーは m68030_jump() 内でのみ発生するはずで、その場で
1.1.1.3   root      279: //     m68030_exception() を呼んで処理する。
1.1       root      280: //
                    281: // 3. 命令中で起きる例外
                    282: //     命令途中で起きる(確定的な)例外は m68030_exception() を呼び出す。
                    283: //     これに該当するのは
                    284: //       o 特権違反
                    285: //       o A系列/F系列命令
                    286: //       o TRAP* 系命令、CHK/CHK2 命令
                    287: //       o トレース例外 (未実装)
                    288: //       o ゼロ除算?
                    289: //       o MMU 構成例外
                    290: //       o 不当命令 (*)
                    291: //     である。
                    292: //     ただし、不当命令についてはどこで不当命令と判定されるかによって
                    293: //     フローが複数存在することに注意。
                    294: //       o 1ワード目が不当命令
                    295: //             -> 命令がそれぞれ m68030_exception() で処理。
                    296: //       o 1ワード目の EA が不当命令
1.1.1.3   root      297: //             -> (C++の)例外をスローして catch 内で m68030_exception() を実行。
1.1       root      298: //       o 2ワード目が不当命令
                    299: //             -> 命令がそれぞれ m68030_exception() で処理。
                    300: //
                    301: // 4. 割り込み例外
1.1.1.3   root      302: //     外部デバイスは m68030_interrpt() を呼び出すことで MPU に割り込みを要求
                    303: //     する。その結果 MPU は直後の命令境界で割り込みをチェックし、
                    304: //     m68030_exception_interrupt() を呼び出す。
                    305: //
1.1       root      306: 
                    307: // vector にジャンプする。vector はベクタ番号(アドレスではない)。
                    308: static inline void
                    309: m68030_jump_vector(m68kcpu *cpu, int vector)
                    310: {
1.1.1.3   root      311:        uint32 vecaddr;
1.1       root      312:        uint32 newpc;
                    313: 
1.1.1.3   root      314:        vecaddr = RegVBR + vector * 4;
                    315:        RegPC = vecaddr;
1.1       root      316:        newpc = m68030_fetch_32(cpu);
1.1.1.3   root      317:        // VBR 込みのジャンプ先が確定したところで今度はブランチ履歴に記録。
                    318:        // この時のブランチ元はベクタアドレス
                    319:        // (RegPC は fetch によって進んでしまうので先に保存)
1.1.1.5   root      320:        cpu->brhist.AddEntry(vecaddr | (cpu->reg.s ? 1 : 0), newpc, 0x8000);
1.1.1.3   root      321: 
                    322:        CHECK_ADDRESS_ERROR(newpc);
                    323:        RegPC = newpc;
1.1.1.2   root      324: 
                    325:        // 実際はここでパイプライン充填のために3ワードフェッチするので、
                    326:        // ベクタテーブルはフェッチ出来たけどそのジャンプ先がバスエラーに
                    327:        // なるケースはここでバスエラーが出なければいけないが、まだ
                    328:        // キャッシュを実装していないので、ここで1ワードフェッチしてみて
                    329:        // PC を戻すあほっぽい方法を取る。
                    330:        m68030_fetch_16(cpu);
                    331:        RegPC -= 2;
1.1       root      332: }
                    333: 
                    334: // 例外スタックフレーム $0 を生成する。
                    335: // vector はベクタ番号。
                    336: // pc はスタックに積むプログラムカウンタの値 (例外によって、この命令位置か
                    337: // 次の命令位置かが異なる)。
                    338: // sr は例外発生時の SR。
                    339: static inline void
                    340: m68030_generate_exframe_0(m68kcpu *cpu, int vector, uint32 pc, uint16 sr)
                    341: {
                    342:        // 例外スタックフレーム $0
                    343:        // SP+$00.W STATUS REGISTER
                    344:        //   +$02.L PROGRAM COUNTER             ; 例外ごとに異なる
                    345:        //   +$06.W %0000 | VECTOR
                    346: 
                    347:        m68030_push_16(cpu, (0 << 12) | (vector * 4));
                    348:        m68030_push_32(cpu, pc);
                    349:        m68030_push_16(cpu, sr);
                    350: }
                    351: 
                    352: // 例外スタックフレーム $2 を生成する。
                    353: // vector はベクタ番号。
                    354: // スタックに積む PC は常に次の命令。
                    355: static inline void
                    356: m68030_generate_exframe_2(m68kcpu *cpu, int vector, uint16 sr)
                    357: {
                    358:        // 例外スタックフレーム $2
                    359:        // SP+$00.W STATUS REGISTER
                    360:        //   +$02.L PROGRAM COUNTER             ; 次の命令位置
                    361:        //   +$06.W %0010 | VECTOR
                    362:        //   +$08.L INSTRUCTION ADDRESS ; 例外を起こした命令のアドレス
                    363: 
                    364:        m68030_push_32(cpu, RegPPC);    // 例外を起こした命令のアドレス
                    365:        m68030_push_16(cpu, (2 << 12) | (vector * 4));
                    366:        m68030_push_32(cpu, RegPC);             // 次の命令位置
                    367:        m68030_push_16(cpu, sr);
                    368: }
                    369: 
                    370: // 例外スタックフレーム $B を生成する。
                    371: static inline void
                    372: m68030_generate_exframe_b(m68kcpu *cpu, int vector, uint16 sr)
                    373: {
                    374:        uint16 ssw;
                    375:        uint32 fault_addr;
                    376:        uint32 stageBaddr;
                    377: 
                    378:        stageBaddr = RegPC + 2;
                    379:        // この後のスタック操作で bus が変化する前に保存
                    380:        fault_addr = cpu->bus.laddr;
                    381:        // DF ビットを立てておくと RTE した後この命令を再実行。
                    382:        ssw = cpu->bus.ssw | SSW_DF;
                    383: 
                    384:        // 例外スタックフレーム $B
                    385:        // SP+$00.W   STATUS REGISTER
                    386:        //   +$02.L   PROGRAM COUNTER
                    387:        //   +$06.W   %1011 | VECTOR
                    388:        //   +$08.W   (internal register)
                    389:        //   +$0a.W   SPECIAL STATUS REGISTER           ; SSW
                    390:        //   +$0c.W   INSTRUCTION PIPE STAGE C
                    391:        //   +$0e.W   INSTRUCTION PIPE STAGE B
                    392:        //   +$10.L   DATA CYCLE FAULT ADDRESS
                    393:        //   +$14.W*2 (internal register)
                    394:        //   +$18.L   DATA OUTPUT BUFFER
                    395:        //   +$1c.W*4 (internal register, 4 words)
                    396:        //   +$24.L   STAGE B ADDRESS
                    397:        //   +$28.W*2 (internal register, 2 words)
                    398:        //   +$2c.L   DATA INPUT BUFFER
                    399:        //   +$30.W*3 (internal register, 3 words)
                    400:        //   +$36.W   VERSION# | internal information
                    401:        //   +$38.W*18 (internal register, 18 words)
                    402:        //   +$5a
                    403:        //      こっちから上に向かって PUSH
                    404: 
                    405:        // internal registers, 18 words
                    406:        // 内部レジスタ18ワードのうち、ここでは17ワード分を save_pd[8] (16ワード)、
                    407:        // flag_pd (1ワード) として使うことにする。
                    408:        // -(An) でバスエラーが起きると An は減算された状態になるが、DF ビットが
                    409:        // 立っていて再実行する時には現行構造では命令先頭から再実行せざるをえず、
                    410:        // そうするともう一度プリデクリメントが動いてしまう。そのため、RTE の時点
                    411:        // で DF=1 ならプリデクリメント発生前の An に戻すという処理をする。
                    412:        // RTE 時点で DF=0 なら命令を再実行しないため An も巻き戻してはならず、
                    413:        // そのためプリデクリメント分の巻き戻しは RTE 時点まで行えない。
1.1.1.2   root      414:        // 一方、ポストインクリメントのケースはこの少し下の
                    415:        // m68030_exception_buserr() 内のコメント参照。
1.1       root      416:        for (int i = 7; i >= 0; i--) {
                    417:                m68030_push_32(cpu, cpu->save_pd[i]);
                    418:        }
                    419:        m68030_push_16(cpu, cpu->flag_pd);
                    420:        RegA(7) -= 2;
                    421: 
                    422:        RegA(7) -= 2;                                           // VERSION#
                    423:        RegA(7) -= 6;
                    424:        m68030_push_32(cpu, 0);                         // DATA INPUT BUFFER
                    425:        RegA(7) -= 4;
                    426:        m68030_push_32(cpu, stageBaddr);        // STAGE B ADDRESS
                    427:        RegA(7) -= 8;
                    428:        m68030_push_32(cpu, 0);                         // DATA OUTPUT BUFFER
                    429:        RegA(7) -= 4;
                    430:        m68030_push_32(cpu, fault_addr);        // DATA CYCLE FAULT ADDRESS
                    431:        m68030_push_16(cpu, 0);                         // INSTRUCTION PIPE STAGE B
                    432:        m68030_push_16(cpu, 0);                         // INSTRUCTION PIPE STAGE C
                    433:        m68030_push_16(cpu, ssw);
                    434:        RegA(7) -= 2;
                    435:        m68030_push_16(cpu, 0xb000 | (vector << 2));
                    436:        // 本当は現在の PC だが、再実行のため PPC を積む。
                    437:        m68030_push_32(cpu, RegPPC);            // PC
                    438:        m68030_push_16(cpu, sr);                        // 例外入り口で保存した SR
                    439: }
                    440: 
                    441: // 例外処理 (リセット・割り込み以外) を行う。
                    442: // vector はベクタ番号。
                    443: void
                    444: m68030_exception(m68kcpu *cpu, int vector)
                    445: {
1.1.1.2   root      446:        // バスエラー・アドレスエラーは別で処理。
                    447:        if (vector <= M68K_EXCEP_ADDRERR) {
                    448:                m68030_exception_buserr(cpu, vector);
                    449:                return;
                    450:        }
                    451: 
1.1.1.3   root      452:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
1.1.1.5   root      453:        uint32 from = RegPPC | (cpu->reg.s ? 1 : 0);
                    454:        cpu->exhist.AddEntry(from, 0, 0x8000 | vector);
                    455:        cpu->brhist.AddEntry(from, 0, 0x8000 | vector);
1.1.1.3   root      456:        // デバッガに通知 (例外ブレーク用)
1.1.1.4   root      457:        debugger_notify_exception(vector);
1.1.1.3   root      458: 
1.1       root      459:        // 状態を保存
                    460:        uint16 sr = RegSR;
                    461: 
                    462:        // S を立てて T1,T0 を落とす
                    463:        m68030_set_sr(cpu, (RegSR | M68K_SR_S) & ~M68K_SR_T);
                    464: 
1.1.1.2   root      465:        try {
                    466:                switch (vector) {
                    467:                 case M68K_EXCEP_ILLEGAL:               // 不当命令
                    468:                 case M68K_EXCEP_PRIV:                  // 特権違反例外
                    469:                 case M68K_EXCEP_ALINE:                 // Aライン命令例外
                    470:                 case M68K_EXCEP_FLINE:                 // Fライン命令例外
                    471:                        // スタックに積む PC はこの命令のアドレス
                    472:                        m68030_generate_exframe_0(cpu, vector, RegPPC, sr);
                    473:                        break;
                    474: 
                    475:                 case M68K_EXCEP_TRAP0                  // TRAP#0
                    476:                  ... M68K_EXCEP_TRAP15:                // TRAP#15
                    477:                        // スタックに積む PC は次の命令
                    478:                        m68030_generate_exframe_0(cpu, vector, RegPC, sr);
                    479:                        break;
                    480: 
                    481:                 case M68K_EXCEP_ZERODIV:               // ゼロ除算
                    482:                 case M68K_EXCEP_CHK:                   // CHK
                    483:                 case M68K_EXCEP_TRAPV:                 // TRAPV
                    484:                 case M68K_EXCEP_MMU_CONFIG:    // MMU 構成例外
                    485:                        m68030_generate_exframe_2(cpu, vector, sr);
                    486:                        break;
                    487: 
                    488:                 default:
                    489:                        PANIC("$%08x exception vector %d ?", RegPPC, vector);
                    490:                        break;
1.1       root      491:                }
                    492: 
1.1.1.2   root      493:                // ベクタにジャンプ
                    494:                m68030_jump_vector(cpu, vector);
                    495:        } catch (int vector2) {
                    496:                assertmsg(vector2 == M68K_EXCEP_BUSERR, "vector=%d", vector);
1.1       root      497: 
1.1.1.2   root      498:                // バスエラー処理へ
                    499:                m68030_exception_buserr(cpu, vector2);
1.1       root      500:        }
1.1.1.2   root      501: }
                    502: 
                    503: // バスエラー・アドレスエラー例外処理を行う。
                    504: // 他の例外とは違いが多いので分けた。
                    505: void
                    506: m68030_exception_buserr(m68kcpu *cpu, int vector)
                    507: {
                    508:        assertmsg((vector == M68K_EXCEP_BUSERR || vector == M68K_EXCEP_ADDRERR),
                    509:                "vector=%d", vector);
                    510: 
1.1.1.3   root      511:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
1.1.1.5   root      512:        uint32 from = RegPPC | (cpu->reg.s ? 1 : 0);
                    513:        cpu->exhist.AddEntry(from, 0, 0x8000 | vector);
                    514:        cpu->brhist.AddEntry(from, 0, 0x8000 | vector);
1.1.1.3   root      515:        // デバッガに通知 (例外ブレーク用)
1.1.1.4   root      516:        debugger_notify_exception(vector);
1.1.1.3   root      517: 
1.1.1.2   root      518:        // 状態を保存
                    519:        uint16 sr = RegSR;
1.1       root      520: 
1.1.1.2   root      521:        // ここで (An)+ で変化したレジスタを命令実行前の状態に巻き戻す。
                    522:        // EA 処理の時点で先にインクリメントしているのだが、バスエラーが
                    523:        // 起きたということは実際にはポストインクリメントは発生しないので、
                    524:        // ここで無条件に巻き戻してよい。SR を書き換えると A7 が切り替わって
                    525:        // しまうので、この巻き戻しは SR を書き換える前のここで行うこと。
                    526:        // 一方、プリデクリメントのケースはこの少し上の exframe_b の中の
                    527:        // コメント参照。
                    528:        m68030_restore_reg_pi(cpu);
                    529: 
                    530:        // S を立てて T1,T0 を落とす
                    531:        m68030_set_sr(cpu, (RegSR | M68K_SR_S) & ~M68K_SR_T);
                    532: 
                    533:        try {
                    534:                // フレームを作成。
                    535:                // 実際はショート($A)、ロング($B)の2種類あって、本来ならショートが
                    536:                // 使えればショートを使うのだが、ここでは全部ロングを使う。
                    537:                m68030_generate_exframe_b(cpu, vector, sr);
                    538:                // ベクタにジャンプ
                    539:                m68030_jump_vector(cpu, vector);
                    540:        } catch (int vector2) {
                    541:                // ここに来るのはバスエラーだけのはず
                    542:                assertmsg(vector2 == M68K_EXCEP_BUSERR, "vector=%d", vector);
                    543: 
                    544:                // バスエラー・アドレスエラー処理中のバスエラーは
                    545:                // ダブルバスフォールト。
                    546:                m68030_double_bus_fault(cpu, "bus/address error handling");
                    547:        }
1.1       root      548: }
                    549: 
                    550: // 割り込み例外処理を行う。
                    551: // 割り込みチェックは m68030core.cpp::m68030_flush_interrupt() で判定している。
                    552: void
1.1.1.5   root      553: m68030_exception_interrupt(m68kcpu *cpu, int level)
1.1       root      554: {
1.1.1.5   root      555:        // ユーザーズマニュアル(日本語) p.399 図8-5 の中ほど
                    556:        // 「/IPEND をネゲート、割り込みアクノリッジサイクルを実行」
                    557:        // 以降に相当。
                    558: 
                    559:        // 割り込みアクノリッジサイクルを実行
                    560:        int vector = m68030_interrupt_acknowledge(level);
                    561:        if (vector == -1) {
                    562:                vector = 24 + level;
                    563:        }
                    564: 
1.1.1.3   root      565:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
1.1.1.5   root      566:        uint32 from = RegPPC | (cpu->reg.s ? 1 : 0);
                    567:        uint32 inst = 0x8000 | (level << 8) | vector;
                    568:        cpu->exhist.AddEntry(from, 0, inst);
                    569:        cpu->brhist.AddEntry(from, 0, inst);
1.1.1.3   root      570:        // デバッガに通知 (例外ブレーク用)
1.1.1.4   root      571:        debugger_notify_exception(vector);
1.1       root      572: 
                    573:        // 状態を保存
                    574:        uint16 sr = RegSR;
                    575: 
                    576:        // S を立てて T1,T0 を落とす
                    577:        m68030_set_sr(cpu, (RegSR | M68K_SR_S) & ~M68K_SR_T);
                    578:        // 割り込みレベルを変更
                    579:        m68030_change_intr(cpu, level);
                    580: 
1.1.1.2   root      581:        try {
                    582:                // 例外スタックフレーム $0 を生成。
                    583:                // スタックに積む PC は次の命令位置。
                    584:                // M ビットは未実装なのでスローアウェイとか無視
                    585:                m68030_generate_exframe_0(cpu, vector, RegPC, sr);
1.1       root      586: 
1.1.1.2   root      587:                // ベクタにジャンプ
                    588:                m68030_jump_vector(cpu, vector);
                    589:        } catch (int vector2) {
                    590:                assertmsg(vector2 == M68K_EXCEP_BUSERR, "vector=%d", vector);
                    591: 
                    592:                // バスエラー処理へ
                    593:                m68030_exception_buserr(cpu, vector2);
                    594:        }
1.1       root      595: }
                    596: 
                    597: // RTE 命令。
                    598: // 例外処理の近くに置いておくほうが便利なので。
                    599: void
                    600: m68030_rte(m68kcpu *cpu)
                    601: {
                    602:        uint32 pc;
                    603:        uint16 sr;
                    604:        uint16 frame;
                    605: 
1.1.1.2   root      606:        try {
                    607:                sr = m68030_pop_16(cpu);
                    608:                pc = m68030_pop_32(cpu);
                    609:                frame = m68030_pop_16(cpu);
                    610:                switch (frame >> 12) {
                    611:                 case 0:
                    612:                        CYCLE2(18, 20);
                    613:                        m68030_set_sr(cpu, sr);
                    614:                        m68030_jump(cpu, pc);
                    615:                        break;
                    616: 
                    617:                 case 2:
                    618:                        CYCLE2(18, 20);
                    619:                        // +08.L INSTRUCTION ADDRESS を読み捨てる
                    620:                        RegA(7) += 4;
                    621:                        m68030_set_sr(cpu, sr);
                    622:                        m68030_jump(cpu, pc);
                    623:                        break;
                    624: 
                    625:                 case 0x0b:
                    626:                 {
                    627:                        uint32 stage_b;
                    628:                        uint16 ssw;
                    629: 
                    630:                        CYCLE(76);
                    631:                        RegA(7) += 2;                                           // $08.W
                    632:                        ssw = m68030_pop_16(cpu);                       // $0a.W SSW
                    633:                        RegA(7) += 4 * 6;                                       // $0c.L*6
                    634:                        stage_b = m68030_pop_32(cpu);           // $24.L Stage B
                    635:                        RegA(7) += 2 * 9;                                       // $28.W*9
                    636:                        // $3a..$58 ここが save_pd の取り出し
                    637:                        cpu->flag_pd = m68030_pop_16(cpu);
                    638:                        for (int i = 0; i < 8; i++) {
                    639:                                cpu->save_pd[i] = m68030_pop_32(cpu);
                    640:                        }
                    641:                        // A7 レジスタをリストアするかもしれない前に Super/User を
                    642:                        // 復帰しておかないといけない
                    643:                        m68030_set_sr(cpu, sr);
                    644: 
                    645:                        // DFビットセットなら命令を再実行するため、-(An) で変化
                    646:                        // したレジスタを巻き戻す。
                    647:                        // DFビットクリアなら例外要因の命令はハンドラで処理された
                    648:                        // とみなして、次の命令に進む。
                    649:                        if ((ssw & SSW_DF)) {
                    650:                                m68030_restore_reg_pd(cpu);
                    651:                        } else {
                    652:                                pc = stage_b - 2;
                    653:                        }
                    654:                        m68030_jump(cpu, pc);
                    655:                        break;
                    656:                 }
                    657: 
                    658:                 default:
                    659:                        PANIC("RTE frame=$%x not supported", frame >> 12);
                    660:                        break;
1.1       root      661:                }
1.1.1.2   root      662:        } catch (int vector2) {
                    663:                assertmsg(vector2 == M68K_EXCEP_BUSERR, "vector2=%d", vector2);
1.1       root      664: 
1.1.1.2   root      665:                // RTE 処理中のバスエラーはダブルバスフォールト。
                    666:                m68030_double_bus_fault(cpu, "bus/address error handling");
1.1       root      667:        }
                    668: }
                    669: 
                    670: static const char * const exception_name_table[] = {
1.1.1.3   root      671:                        //   0123456789012345678 <- 例外履歴欄の横幅
1.1       root      672:        /*  0 */        "Reset",
                    673:        /*  1 */        NULL,
                    674:        /*  2 */        "Bus Error",
                    675:        /*  3 */        "Address Error",
                    676:        /*  4 */        "Illegal Instruction",
1.1.1.3   root      677:        /*  5 */        "Zero Divide",
                    678:        /*  6 */        "CHK/CHK2 Insn",
                    679:        /*  7 */        "TRAPV, *TRAPcc Insn",
                    680:        /*  8 */        "PriviledgeViolation",
1.1       root      681:        /*  9 */        "Trace",
1.1.1.3   root      682:        /* 10 */        "Line 1010 emulator",
                    683:        /* 11 */        "Line 1111 emulator",
1.1       root      684:        /* 12 */        NULL,
1.1.1.3   root      685:        /* 13 */        "CoproProtoViolation",
                    686:        /* 14 */        "Format Error",
                    687:        /* 15 */        "Uninitialized Intr",
                    688:        /* 16 */        NULL, NULL, NULL, NULL,
                    689:        /* 20 */        NULL, NULL, NULL, NULL,
1.1       root      690:        /* 24 */        "Spurious Interrupt",
                    691:        /* 25 */        "Level 1 Interrupt",
                    692:        /* 26 */        "Level 2 Interrupt",
                    693:        /* 27 */        "Level 3 Interrupt",
                    694:        /* 28 */        "Level 4 Interrupt",
                    695:        /* 29 */        "Level 5 Interrupt",
                    696:        /* 30 */        "Level 6 Interrupt",
                    697:        /* 31 */        "Level 7 Interrupt",
                    698:        /* 32 */        "Trap #0",
                    699:        /* 33 */        "Trap #1",
                    700:        /* 34 */        "Trap #2",
                    701:        /* 35 */        "Trap #3",
                    702:        /* 36 */        "Trap #4",
                    703:        /* 37 */        "Trap #5",
                    704:        /* 38 */        "Trap #6",
                    705:        /* 39 */        "Trap #7",
                    706:        /* 40 */        "Trap #8",
                    707:        /* 41 */        "Trap #9",
                    708:        /* 42 */        "Trap #10",
                    709:        /* 43 */        "Trap #11",
                    710:        /* 44 */        "Trap #12",
                    711:        /* 45 */        "Trap #13",
                    712:        /* 46 */        "Trap #14",
                    713:        /* 47 */        "Trap #15",
1.1.1.3   root      714:                        //   0123456789012345678
1.1       root      715:        /* 48 */        "FPCP Branch",
1.1.1.3   root      716:        /* 49 */        "FPCP InexcactResult",
                    717:        /* 50 */        "FPCP Divide by Zero",
1.1       root      718:        /* 51 */        "FPCP UnderFlow",
1.1.1.3   root      719:        /* 52 */        "FPCP Operand Error",
1.1       root      720:        /* 53 */        "FPCP OverFlow",
1.1.1.3   root      721:        /* 54 */        "FPCP Signaling NAN",
1.1       root      722:        /* 55 */        NULL,
1.1.1.3   root      723:        /* 56 */        "MMU Config Error",
1.1       root      724:        /* 57 */        NULL,
                    725:        /* 58 */        NULL,
                    726:        /* 59 */        NULL,
                    727:        /* 60 */        NULL,
                    728:        /* 61 */        NULL,
                    729:        /* 62 */        NULL,
                    730:        /* 63 */        NULL,
1.1.1.3   root      731:                        //   0123456789012345678
                    732:        /* $40 */       "MFP Alarm",
                    733:        /* $41 */       "MFP EXPON",
                    734:        /* $42 */       "MFP POWSW",
                    735:        /* $43 */       "MFP FM IRQ",
                    736:        /* $44 */       "MFP Timer-D",
                    737:        /* $45 */       "MFP Timer-C",
                    738:        /* $46 */       "MFP V-Disp",
                    739:        /* $47 */       "MFP GPIP5",
                    740:        /* $48 */       "MFP Timer-B",
                    741:        /* $49 */       "MFP TX Error",
                    742:        /* $4a */       "MFP TX Empty",
                    743:        /* $4b */       "MFP RX Error",
                    744:        /* $4c */       "MFP RX Full",
                    745:        /* $4d */       "MFP Timer-A",
                    746:        /* $4e */       "MFP CRTC IRQ",
                    747:        /* $4f */       "MFP H-Sync",
                    748:        /* $50 */       "SCC#B TX Empty",
                    749:        /* $51 */       "SCC#B TX Empty",
                    750:        /* $52 */       "SCC#B",
                    751:        /* $53 */       "SCC#B",
                    752:        /* $54 */       "SCC#B",
                    753:        /* $55 */       "SCC#B",
                    754:        /* $56 */       "SCC#B",
                    755:        /* $57 */       "SCC#B",
                    756:        /* $58 */       "SCC#A TX Empty",
                    757:        /* $59 */       "SCC#A TX Empty",
                    758:        /* $5a */       "SCC#A",
                    759:        /* $5b */       "SCC#A",
                    760:        /* $5c */       "SCC#A",
                    761:        /* $5d */       "SCC#A",
                    762:        /* $5e */       "SCC#A",
                    763:        /* $5f */       "SCC#A",
                    764: 
                    765:                        //   0123456789012345678
                    766:        /* $60 */       "I/O FDC Intr",
                    767:        /* $61 */       "I/O FDD Intr",
                    768:        /* $62 */       "I/O HDC Intr",
                    769:        /* $63 */       "I/O PRN Intr",
                    770:        /* $64 */       "DMAC#0 Complete",
                    771:        /* $65 */       "DMAC#0 Error",
                    772:        /* $66 */       "DMAC#1 Complete",
                    773:        /* $67 */       "DMAC#1 Error",
                    774:        /* $68 */       "DMAC#2 Complete",
                    775:        /* $69 */       "DMAC#2 Error",
                    776:        /* $6a */       "DMAC#3 Complete",
                    777:        /* $6b */       "DMAC#3 Error",
                    778:        /* $6c */       "SPC Interrupt",
                    779:        /* $6d */       NULL,
                    780:        /* $6e */       NULL,
                    781:        /* $6f */       NULL,
                    782: 
                    783:        /* $70 */       NULL, NULL, NULL, NULL,
                    784:        /* $74 */       NULL, NULL, NULL, NULL,
                    785:        /* $78 */       NULL, NULL, NULL, NULL,
                    786:        /* $7c */       NULL, NULL, NULL, NULL,
                    787:        /* $80 */       NULL, NULL, NULL, NULL, // MIDI
                    788:        /* $84 */       NULL, NULL, NULL, NULL, // MIDI
                    789:        /* $88 */       NULL, NULL, NULL, NULL, // MIDI
                    790:        /* $8c */       NULL, NULL, NULL, NULL, // MIDI
                    791:        /* $90 */       NULL, NULL, NULL, NULL,
                    792:        /* $94 */       NULL, NULL, NULL, NULL,
                    793:        /* $98 */       NULL, NULL, NULL, NULL,
                    794:        /* $9c */       NULL, NULL, NULL, NULL,
                    795:        /* $a0 */       NULL, NULL, NULL, NULL, // MIDI
                    796:        /* $a4 */       NULL, NULL, NULL, NULL, // MIDI
                    797:        /* $a8 */       NULL, NULL, NULL, NULL, // MIDI
                    798:        /* $ac */       NULL, NULL, NULL, NULL, // MIDI
                    799:        /* $b0 */       NULL, NULL, NULL, NULL, // RS-232C
                    800:        /* $b4 */       NULL, NULL, NULL, NULL, // RS-232C
                    801:        /* $b8 */       NULL, NULL, NULL, NULL, // RS-232C
                    802:        /* $bc */       NULL, NULL, NULL, NULL, // RS-232C
                    803:        /* $c0 */       NULL, NULL, NULL, NULL, // RS-232C
                    804:        /* $c4 */       NULL, NULL, NULL, NULL, // RS-232C
                    805:        /* $c8 */       NULL, NULL, NULL, NULL, // RS-232C
                    806:        /* $cc */       NULL, NULL, NULL, NULL, // RS-232C
                    807:        /* $d0 */       NULL, NULL, NULL, NULL,
                    808:        /* $d4 */       NULL, NULL, NULL, NULL,
                    809:        /* $d8 */       NULL, NULL, NULL, NULL,
                    810:        /* $dc */       NULL, NULL, NULL, NULL,
                    811:        /* $e0 */       NULL, NULL, NULL, NULL,
                    812:        /* $e4 */       NULL, NULL, NULL, NULL,
                    813:        /* $e8 */       NULL, NULL, NULL, NULL,
                    814:        /* $ec */       NULL, NULL, NULL, NULL,
                    815: 
                    816:                        //   0123456789012345678
                    817:        /* $f0 */       "PSX16x50 Interrupt",
                    818:        /* $f1 */       NULL,
                    819:        /* $f2 */       NULL,
                    820:        /* $f3 */       NULL,
                    821:        /* $f4 */       NULL,
                    822:        /* $f5 */       NULL,
                    823:        /* $f6 */       "ExSPC Interrupt",
                    824:        /* $f7 */       NULL,   // TS-6BSI
                    825:        /* $f8 */       "Nereid#1 Interrupt",
                    826:        /* $f9 */       "Neptune-X Interrupt",
                    827:        /* $fa */       "Nereid#1 USB",
                    828:        /* $fb */       "Nereid#0 USB",
                    829:        /* $fc */       NULL,
                    830:        /* $fd */       NULL,
                    831:        /* $fe */       NULL,
                    832:        /* $ff */       NULL,
1.1       root      833: };
                    834: 
                    835: // ベクタ番号から表示名を返す
                    836: const char *
                    837: m68030_get_exception_name(int vector)
                    838: {
                    839:        const char *name = NULL;
                    840:        if (vector < countof(exception_name_table)) {
                    841:                name = exception_name_table[vector];
                    842:        }
                    843:        if (name == NULL) {
                    844:                name = "(reserved?)";
                    845:        }
                    846:        return name;
                    847: }

unix.superglobalmegacorp.com

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