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

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

unix.superglobalmegacorp.com

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