Annotation of nono/m680x0/m680x0core.cpp, revision 1.1.1.5

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: #include "mpu680x0.h"
                      8: #include "bitops.h"
                      9: #include "debugger.h"
1.1.1.4   root       10: #include "event.h"
1.1       root       11: #include "interrupt.h"
                     12: #include "mainbus.h"
                     13: #include "scheduler.h"
                     14: #include "vectortable.h"
                     15: 
1.1.1.3   root       16: #define M680X0_CYCLE_TABLE
                     17: #include "m680x0cycle.h"
                     18: 
1.1       root       19: #define OP_FUNC(name)  __CONCAT(op_,name)()
                     20: 
                     21: // 1命令実行する。
                     22: // 割り込みチェックなどを省いたショート版。
                     23: void
1.1.1.4   root       24: MPU680x0Device::ExecShort(Event *ev)
1.1       root       25: {
                     26:        uint64 cycle_start = used_cycle;
                     27: 
                     28:        buswait = 0;
                     29: 
                     30:        try {
                     31:                // 1命令版では switch-case を使うしかない。
                     32:                ppc = reg.pc;
                     33:                flag_pi = 0;
                     34:                flag_pd = 0;
                     35:                ir = fetch_2();
                     36: 
                     37:                // uint16 を 6ビット右シフトしたら 1024 以上になるはずは
                     38:                // ないのだが、デフォルトでは gcc/clang どちらも律儀に
                     39:                // 1024 以上かどうか比較して分岐しようとする。
                     40:                // gcc は __assume() を入れることでこの比較・分岐を出力
                     41:                // しないようにすることが出来た(がパフォーマンスの差は
                     42:                // 見えない程度でしかなかった)。
                     43:                // clang ではどうやったら効くか不明。
                     44:                uint16 ir6 = ir >> 6;
                     45:                __assume(ir6 < 1024);
                     46:                switch (ir6) {
                     47: #include "m680x0switch.h"
                     48:                }
                     49:        } catch (uint vector) {
                     50:                // ここで(C++の)例外スローをキャッチするのは
                     51:                // - メモリ空間をアクセスした先でのバスエラー例外
                     52:                // - EA パース中の不当命令例外
                     53:                // のみ。それ以外の命令途中例外はその場で処理できる。
                     54:                if (__predict_false(loglevel >= 2)) {
                     55:                        const char *name = vectortable->GetExceptionName(vector);
                     56:                        if (__predict_true(name)) {
                     57:                                putlogn("%s", name);
                     58:                        } else {
                     59:                                putlogn("vector 0x%x", vector);
                     60:                        }
                     61:                }
                     62:                if (vector == M68K::EXCEP_BUSERR) {
                     63:                        ExceptionBuserr(vector);
                     64:                } else if (vector == M68K::EXCEP_ILLEGAL) {
                     65:                        op_illegal();
                     66:                } else {
                     67:                        Exception(vector);
                     68:                }
                     69:        }
                     70: 
                     71:        // 外部割り込みの起動は VM 側で処理している。
                     72: 
                     73:        int cycle = used_cycle - cycle_start;
1.1.1.5 ! root       74:        ev->time = cycle * clock_tsec + buswait;
1.1       root       75:        scheduler->StartEvent(ev);
                     76: }
                     77: 
                     78: // 二重バスフォールト
                     79: void
                     80: MPU680x0Device::DoubleBusFault(const char *where)
                     81: {
                     82:        // where をログに出す?
                     83: 
                     84:        // ホールト状態へ移行
                     85:        Halt();
                     86: }
                     87: 
                     88: // SR (と CCR) をセットする。
                     89: // リセット例外以外から使う (リセット例外はやや異なるため)。
                     90: //
                     91: // 割り込みマスクが変わる場合は、ここで次の命令実行コールバックを差し替える。
                     92: void
                     93: MPU680x0Device::SetSR(uint16 data)
                     94: {
                     95:        bool oldS = reg.s;
                     96:        bool oldM = reg.m;
                     97: 
                     98:        // 現在の SP を保存
                     99:        if (oldS == false) {
                    100:                reg.usp = reg.A[7];
                    101:        } else if (oldM == false) {
                    102:                reg.isp = reg.A[7];
                    103:        } else {
                    104:                reg.msp = reg.A[7];
                    105:        }
                    106: 
                    107:        reg.ccr.Set(data);
                    108:        reg.s = ((data & M68K::SR_S) != 0);
                    109:        reg.m = ((data & M68K::SR_M) != 0);
                    110: 
                    111:        // 割り込みマスクレジスタを更新して..
                    112:        uint new_mask = (data >> 8) & 7;
                    113:        if (reg.intr_mask != new_mask) {
                    114:                reg.intr_mask = new_mask;
                    115: 
                    116:                // 次の命令境界で割り込みをチェックさせる
                    117:                MakeNextFull();
                    118:        }
                    119: 
                    120:        // 新しい SP を用意
                    121:        if (reg.s == false) {
                    122:                reg.A[7] = reg.usp;
                    123:        } else if (reg.m == false) {
                    124:                reg.A[7] = reg.isp;
                    125:        } else {
                    126:                reg.A[7] = reg.msp;
                    127:        }
                    128: 
                    129:        // FC2-0
                    130:        fc_inst = BusAddr::Fetch | busaddr::SU(reg.s);
                    131:        fc_data = BusAddr::D     | busaddr::SU(reg.s);
                    132: 
                    133:        // XXX 他に何か状態変えないといけないことあったっけか。
                    134: }
                    135: 
                    136: // 命令中に (An)+ で変化したアドレスレジスタを命令実行前の状態に巻き戻す。
                    137: // flag_pi は bit7..0 が save_pi[7..0] の A7..A0 に対応している。
                    138: void
                    139: MPU680x0Device::restore_reg_pi()
                    140: {
                    141:        for (int i = 7; flag_pi; i--) {
                    142:                if ((int8)flag_pi < 0) {
                    143:                        reg.A[i] = save_pi[i];
                    144:                }
                    145:                flag_pi <<= 1;
                    146:        }
                    147: }
                    148: 
                    149: // 命令中に -(An) で変化したアドレスレジスタを命令実行前の状態に巻き戻す。
                    150: // flag_pd は bit7..0 が save_pd[7..0] の A7..A0 に対応している。
                    151: void
                    152: MPU680x0Device::restore_reg_pd()
                    153: {
                    154:        for (int i = 7; flag_pd; i--) {
                    155:                if ((int8)flag_pd < 0) {
                    156:                        reg.A[i] = save_pd[i];
                    157:                }
                    158:                flag_pd <<= 1;
                    159:        }
                    160: }
                    161: 
                    162: // vector にジャンプする。vector はベクタ番号(アドレスではない)。
                    163: void
                    164: MPU680x0Device::JumpVector(uint vector, bool from_buserr)
                    165: {
                    166:        uint32 vecaddr;
                    167:        uint32 newpc;
                    168: 
                    169:        vecaddr = reg.vbr + vector * 4;
                    170:        newpc = read_4(vecaddr);
                    171:        // VBR 込みのジャンプ先が確定したところで今度はブランチ履歴に記録。
                    172:        // この時のブランチ元はベクタアドレス
                    173:        // (reg.pc は fetch によって進んでしまうので先に保存)
1.1.1.3   root      174:        uint32 from = vecaddr | (IsSuper() ? 1 : 0);
                    175:        uint32 info = BranchHistory_m680x0::InfoVectorJump();
                    176:        brhist.AddEntry(from, newpc, info);
1.1       root      177: 
                    178:        // 奇数番地ならアドレスエラー
                    179:        if (__predict_false((newpc & 1) != 0)) {
                    180:                if (from_buserr) {
                    181:                        // バスエラー処理中ならダブルバスフォールト。
                    182:                        throw M68K::EXCEP_ADDRERR;
                    183:                } else {
                    184:                        ExceptionBuserr(M68K::EXCEP_ADDRERR);
                    185:                }
                    186:                return;
                    187:        }
                    188:        reg.pc = newpc;
                    189: 
                    190:        // 実際はここでパイプライン充填のために3ワードフェッチするので、
                    191:        // ベクタテーブルはフェッチ出来たけどそのジャンプ先がバスエラーに
                    192:        // なるケースはここでバスエラーが出なければいけないが、まだ
                    193:        // キャッシュを実装していないので、ここで1ワードフェッチしてみて
                    194:        // PC を戻すあほっぽい方法を取る。
                    195:        fetch_2();
                    196:        reg.pc -= 2;
                    197: }
                    198: 
                    199: // 例外スタックフレーム $0 を生成する。
                    200: // vector はベクタ番号。
                    201: // sr は例外発生時の SR。
                    202: // pc はスタックに積むプログラムカウンタの値 (例外によって、この命令位置か
                    203: // 次の命令位置かが異なる)。
                    204: inline void
                    205: MPU680x0Device::GenerateExframe0(uint vector, uint16 sr, uint32 pc)
                    206: {
                    207:        // 例外スタックフレーム $0
                    208:        // SP+$00.W STATUS REGISTER
                    209:        //   +$02.L PROGRAM COUNTER             ; 例外ごとに異なる
                    210:        //   +$06.W %0000 | VECTOR
                    211: 
                    212:        push_2((0 << 12) | (vector << 2));
                    213:        push_4(pc);
                    214:        push_2(sr);
                    215: }
                    216: 
                    217: // 例外スタックフレーム $2 を生成する。
                    218: // vector はベクタ番号。
                    219: // 例外によって pc と addr の内容が異なるので呼び出す側で適切にセットすること。
                    220: //
                    221: // - CHK*、TRAP*、ゼロ除算:
                    222: //             PC   = 次の命令
                    223: //             Addr = 例外を起こした命令
                    224: // - 68040 のアドレスエラー:
                    225: //             PC   = アドレスエラーを起こした命令
                    226: //             Addr = 参照したアドレス - 1
                    227: inline void
                    228: MPU680x0Device::GenerateExframe2(uint vector, uint16 sr,
                    229:        uint32 pc, uint32 addr)
                    230: {
                    231:        // 例外スタックフレーム $2
                    232:        // SP+$00.W STATUS REGISTER
                    233:        //   +$02.L PROGRAM COUNTER             ; こっちが pc
                    234:        //   +$06.W %0010 | VECTOR
                    235:        //   +$08.L ADDRESS                             ; こっちが addr
                    236: 
                    237:        push_4(addr);                   // ADDRESS
                    238:        push_2((2 << 12) | (vector << 2));
                    239:        push_4(pc);                             // PROGRAM COUNTER
                    240:        push_2(sr);
                    241: }
                    242: 
1.1.1.2   root      243: // 例外スタックフレーム $4 を生成する。(68LC040 only)
                    244: inline void
                    245: MPU680x0Device::GenerateExframe4(uint vector, uint16 sr, uint32 ea)
                    246: {
                    247:        // 公式の図 (のオフセット) が雑すぎる。
                    248:        //
                    249:        //  SP->| STATUS REGISTER
                    250:        // +$02 | PROGRAM COUNTER (H)                   ; こっちは次の命令
                    251:        // +$04 |                 (L)
                    252:        // +$06 | %0100 | VECTOR OFFSET
                    253:        // +$08 | EFFECTIVE ADDRESS (H)
                    254:        // +$0a |                   (L)
                    255:        // +$0c | PC OF FAULTED INSTRUCTION (H)
                    256:        // +$0e |                           (L)
                    257: 
                    258:        push_4(ppc);
                    259:        push_4(ea);
                    260:        push_2((4 << 12) | (vector << 2));
                    261:        push_4(reg.pc);
                    262:        push_2(sr);
                    263: }
                    264: 
1.1       root      265: // 例外スタックフレーム $7 を生成する。(68040 only)
                    266: inline void
                    267: MPU680x0Device::GenerateExframe7(uint vector, uint16 sr)
                    268: {
                    269:        uint16 ssw;
                    270:        uint32 pc;
                    271:        uint32 ea = 0;
                    272:        uint16 wb1s = 0;
                    273:        uint16 wb2s = 0;
                    274:        uint32 wb1a = 0;
                    275:        uint32 wb2a = 0;
                    276:        uint32 wb1d = 0;
                    277:        uint32 wb2d = 0;
                    278: 
                    279:        // 再実行について。
                    280:        //
                    281:        // MOVEM の途中でバスエラーが起きた場合、
                    282:        // 本来は RTE が SSW の CM ビットを見て途中の状態から処理を再開した上で
                    283:        // 次の命令に戻る、らしいが、
                    284:        // ここでは再アクセスに副作用はないものとして、CM ビットは立てず、RTE でも
                    285:        // 何もせずに MOVEM 自体を再実行する。
                    286:        //
                    287:        // それ以外の命令でバスエラーが起きた場合も、単に命令を再実行する。
                    288:        // そのため -(An), (An)+ は例外発生時に常に巻き戻してある。
                    289: 
                    290:        // 例外スタックフレーム $7
                    291:        // SP+$00.W   STATUS REGISTER
                    292:        //   +$02.L   PROGRAM COUNTER
                    293:        //   +$06.W   %0111 | VECTOR
                    294:        //   +$08.L   EFFECTIVE ADDRESS (EA)
                    295:        //   +$0c.W   SPECIAL STATUS REGISTER (SSW)
                    296:        //   +$0e.W   $00 | WRITE-BACK 3 STATUS (WB3S)
                    297:        //   +$10.W   $00 | WRITE-BACK 2 STATUS (WB2S)
                    298:        //   +$12.W   $00 | WRITE-BACK 1 STATUS (WB1S)
                    299:        //   +$14.L   FAULT ADDRESS (FA)
                    300:        //   +$18.L   WRITE-BACK 3 ADDRESS (WB3A)
                    301:        //   +$1c.L   WRITE-BACK 3 DATA    (WB3D)
                    302:        //   +$20.L   WRITE-BACK 2 ADDRESS (WB2A)
                    303:        //   +$24.L   WRITE-BACK 2 DATA    (WB2D)
                    304:        //   +$28.L   WRITE-BACK 1 ADDRESS (WB1A)
                    305:        //   +$2c.L   WRITE-BACK 1 DATA / PUSH DATA LW0 (WB1D/PD0)
                    306:        //   +$30.L   PUSH DATA LW1 (PD1)
                    307:        //   +$34.L   PUSH DATA LW2 (PD2)
                    308:        //   +$38.L   PUSH DATA LW3 (PD3)
1.1.1.5 ! root      309:        //   +$3c
1.1       root      310:        //      こっちから上に向かって PUSH
                    311: 
                    312:        // SSW
                    313:        //  15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
                    314:        // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
                    315:        // |CP |CU |CT |CM |MA |ATC|LK |RW | - | SIZE  |  TT   |    TM     |
                    316:        // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
                    317: 
                    318:        // この後のスタック操作で bus が変化する前に保存。
1.1.1.5 ! root      319:        const busaddr fault = bus.laddr;
1.1       root      320: 
1.1.1.5 ! root      321:        ssw  = fault.GetFC();                           // TM(=FC)
        !           322:        ssw |= (fault.GetSize() & 3) << 5;      // Size の下位2ビット
        !           323:        if (fault.IsRead()) {
1.1       root      324:                ssw |= M68040::SSW_RW;
                    325:        }
                    326:        if (bus.atcfault) {
                    327:                ssw |= M68040::SSW_ATC;
                    328:                bus.atcfault = false;
                    329: 
                    330:                if (bus.atcfault2) {
                    331:                        ssw |= M68040::SSW_MA;
                    332:                        bus.atcfault2 = false;
                    333:                }
                    334:        }
                    335:        // 再実行のため、例外を発生した命令に戻る。
                    336:        pc = ppc;
                    337: 
                    338:        push_4(0);              // PD3
                    339:        push_4(0);              // PD2
                    340:        push_4(0);              // PD1
                    341:        push_4(wb1d);   // WB1D
                    342:        push_4(wb1a);   // WB1A
                    343:        push_4(wb2d);   // WB2D
                    344:        push_4(wb2a);   // WB2A
                    345:        push_4(0);              // WB3D
                    346:        push_4(0);              // WB3A
1.1.1.5 ! root      347:        push_4(fault.Addr());
1.1       root      348:        push_2(wb1s);   // WB1S
                    349:        push_2(wb2s);   // WB2S
                    350:        push_2(0);              // WB3S
                    351:        push_2(ssw);
                    352:        push_4(ea);
1.1.1.5 ! root      353:        push_2(0x7000 | (vector << 2));
1.1       root      354:        push_4(pc);
                    355:        push_2(sr);
                    356: }
                    357: 
                    358: // 例外スタックフレーム $B を生成する。(68030 only)
                    359: inline void
                    360: MPU680x0Device::GenerateExframeB(uint vector, uint16 sr)
                    361: {
                    362:        uint16 ssw;
                    363:        uint32 stageBaddr;
                    364: 
                    365:        stageBaddr = reg.pc + 2;
1.1.1.5 ! root      366: 
1.1       root      367:        // この後のスタック操作で bus が変化する前に保存
1.1.1.5 ! root      368:        const busaddr fault = bus.laddr;
        !           369: 
        !           370:        // SSW
        !           371:        //  15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
        !           372:        // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
        !           373:        // |FC |FB |RC |RB | X | X | X |DF |RM |RW | SIZE  | X |    FC     |
        !           374:        // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1.1       root      375: 
1.1.1.5 ! root      376:        ssw  = (fault.Get() >> 33) & 0x47;      // R/W+FC
        !           377:        ssw |= (fault.GetSize() & 3) << 4;      // Size の下位2ビット
        !           378:        ssw |= M68030::SSW_DF;                          // DF は常に立てる必要がある??
1.1       root      379:        if (mmu_enable && (ssw & M68K::FC_DATA) != 0) {
                    380:                // 命令アクセスなら RB をセット。
                    381:                ssw |= M68030::SSW_RB;
                    382:        }
                    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 時点まで行えない。
                    414:        // 一方、ポストインクリメントのケースはこの少し下の
                    415:        // ExceptionBuserr() 内のコメント参照。
                    416:        for (int i = 7; i >= 0; i--) {
                    417:                push_4(save_pd[i]);
                    418:        }
                    419:        push_2(flag_pd);
                    420:        reg.A[7] -= 2;
                    421: 
                    422:        reg.A[7] -= 2;                                  // VERSION#
                    423:        reg.A[7] -= 6;
                    424:        push_4(0);                                              // DATA INPUT BUFFER
                    425:        reg.A[7] -= 4;
                    426:        push_4(stageBaddr);                             // STAGE B ADDRESS
                    427:        reg.A[7] -= 8;
                    428:        push_4(0);                                              // DATA OUTPUT BUFFER
                    429:        reg.A[7] -= 4;
1.1.1.5 ! root      430:        push_4(fault.Addr());                   // DATA CYCLE FAULT ADDRESS
1.1       root      431:        push_2(0);                                              // INSTRUCTION PIPE STAGE B
                    432:        push_2(0);                                              // INSTRUCTION PIPE STAGE C
                    433:        push_2(ssw);
                    434:        reg.A[7] -= 2;
                    435:        push_2(0xb000 | (vector << 2));
                    436:        // 本当は現在の PC だが、再実行のため PPC を積む。
                    437:        push_4(ppc);                                    // PC
                    438:        push_2(sr);                                             // 例外入り口で保存した SR
                    439: }
                    440: 
                    441: // 例外処理について。
                    442: //
                    443: // 0. リセット例外
                    444: //     リセット例外は外部から ExceptionReset() を呼び出す。
                    445: //
                    446: // 1. バスエラー例外
                    447: //     MMU による論理アドレスでのバスエラーは (Translate*() が false を返した後)
                    448: //     m68030bus.cpp ルーチンが (C++の) 例外をスローする。
                    449: //     物理アドレス空間アクセス後のバスエラーは (VM側の Read*()/Write*() が
                    450: //     BusErr を返した後) m68030bus.cpp ルーチンが (C++) の例外をスローする。
                    451: //     どちらのケースも m68030core.cpp のメインループで catch し、その catch
                    452: //     ブロック内で ExceptionBuserr() を呼び出す。
                    453: //
                    454: // 2. アドレスエラー例外
                    455: //     アドレスエラーは Jump() 内でのみ発生するはずで、その場で
                    456: //     ExceptionBuserr() を呼んで処理する。
                    457: //
                    458: // 3. 命令中で起きる例外
                    459: //     命令途中で起きる(確定的な)例外は基本的に Exception() を呼び出す。
                    460: //     これに該当するのは
                    461: //       o 特権違反
                    462: //       o A系列/F系列命令
                    463: //       o TRAP* 系命令、CHK/CHK2 命令
                    464: //       o トレース例外 (未実装)
                    465: //       o ゼロ除算?
                    466: //       o MMU 構成例外
                    467: //       o 不当命令 (*)
                    468: //     である。
                    469: //     ただし、不当命令についてはどこで不当命令と判定されるかによって
                    470: //     フローが複数存在することに注意。
                    471: //       o 1ワード目が不当命令
                    472: //             -> 命令がそれぞれ Exception() で処理。
                    473: //       o 1ワード目の EA が不当命令
                    474: //             -> (C++の)例外をスローして catch 内で Exception() を実行。
                    475: //       o 2ワード目が不当命令
                    476: //             -> 命令がそれぞれ Exception() で処理。
                    477: //
                    478: // 4. 割り込み例外
                    479: //     別コメント(下のほう)参照。
                    480: //
                    481: 
                    482: // リセット例外処理。
                    483: // 各レジスタを所定の状態にして、リセットベクタを読み込む。
                    484: // リセットベクタが読み込めなければ HALT 状態に移行。
                    485: // 戻り値は消費したサイクル数。
                    486: int
                    487: MPU680x0Device::ExceptionReset()
                    488: {
                    489:        uint64 cycle_start = used_cycle;
                    490: 
                    491:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
                    492:        // m68k では今の所リセット例外発生時の PC にはあまり意味がないけど、
                    493:        // m88k と動作を揃えておく。
                    494:        const uint vector = 0;
                    495:        excep_counter[0]++;
1.1.1.3   root      496:        constexpr uint32 info = BranchHistory_m680x0::InfoException(vector);
                    497:        exhist.AddEntry(reg.pc | 1, 0, info);
                    498:        brhist.AddEntry(reg.pc | 1, 0, info);
1.1.1.5 ! root      499:        last_vector = vector;
1.1       root      500: 
                    501:        // RESET 信号線をネゲートしてから SP の読み込み開始まで 4クロック
                    502:        // (Section 7.8, Figure 7-64)
                    503:        used_cycle += 4;
                    504: 
                    505:        // STOP 状態とホールト状態を解除。
                    506:        ChangeState(CPU_STATE_NORMAL);
                    507: 
                    508:        // 1. T0, T1 クリア
                    509:        // 2. S をセット、M をクリア
                    510:        // 3. 割り込みレベルを 7
                    511: 
                    512:        // ここは SetSR を使わずに設定する。
                    513:        reg.s = true;
                    514:        reg.m = false;
                    515:        fc_inst = BusAddr::S | BusAddr::Fetch;
                    516:        fc_data = BusAddr::S | BusAddr::D;
                    517:        // ここは割り込みレベル変化のチェックは不要でセットだけでいい。
                    518:        reg.intr_mask = 7;
                    519: 
                    520:        // 4. VBR をクリア
                    521:        reg.vbr = 0;
                    522: 
                    523:        // 5. キャッシュの EI|ED, FI|FD, IBE|DBE, WA をクリア
                    524:        // 6. キャッシュエントリをすべてクリア (CI|CD)
                    525:        ResetCache();
                    526: 
1.1.1.3   root      527:        // キャッシュ状態が変わったので、サイクル表も更新。
                    528:        if (GetMPUType() == m680x0MPUType::M68030) {
                    529:                cycle_table = cycle_table_030ncc;
                    530:        }
                    531: 
1.1       root      532:        // 7. TC:E、TTn:E をクリア
                    533:        ResetMMU();
                    534: 
                    535:        // ところでたぶん FPU もリセットされるはず?
                    536:        ResetFPU(true);
                    537: 
                    538:        // 8. リセットベクタ生成
                    539:        // 9. SP をロード
                    540:        // 10. PC をロード
                    541:        try {
                    542:                reg.pc = 0;
                    543:                reg.A[7] = fetch_4();
                    544:                uint32 pc = fetch_4();
                    545:                // 大丈夫のはずだけど fetch_4() が reg.pc を書き換えるので一応
                    546:                reg.pc = pc;
                    547:                // リセットベクタは常に 0, 4 番地から取得したことになっている
1.1.1.3   root      548:                uint32 from = 0x00000004 | 1;
                    549:                brhist.AddEntry(from, reg.pc, BranchHistory_m680x0::InfoVectorJump());
1.1       root      550:        } catch (uint) {
                    551:                DoubleBusFault("reset exception");
                    552:        }
                    553: 
                    554:        // SP のアドレスエラーはリセット例外ではチェックしないようだ。
                    555:        // PC のアドレスエラーは本来ならここにあるはずの3ワードのプリフェッチで
                    556:        // 行われるのだが、それがないので、とりあえずここで。
                    557:        if ((reg.pc & 1) != 0) {
                    558:                DoubleBusFault("reset exception");
                    559:        }
                    560: 
                    561:        return used_cycle - cycle_start;
                    562: }
                    563: 
                    564: // 汎用の例外処理を行う。vector はベクタ番号。
                    565: // ただし以下の例外はここではなくそれぞれ固有のを呼ぶこと。
                    566: // o リセット例外は ExceptionReset()
                    567: // o 割り込み例外は ExceptionInterrupt()
1.1.1.5 ! root      568: // o TRAP#0  例外は ExceptionTrap0()  .. NetBSD システムコール用
        !           569: // o TRAP#15 例外は ExceptionTrap15() .. IOCS コール用
1.1       root      570: // o バスエラー・アドレスエラーは ExceptionBuserr()
                    571: void
                    572: MPU680x0Device::Exception(uint vector)
                    573: {
1.1.1.3   root      574:        uint32 info = BranchHistory_m680x0::InfoException(vector);
                    575:        ExceptionGeneric(vector, info);
1.1       root      576: }
                    577: 
1.1.1.5 ! root      578: // TRAP #0 の例外処理を行う。
        !           579: // 処理自体は汎用の Exception() とまったく同じだが、
        !           580: // NetBSD システムコールの時に分岐履歴の内容を変えるため入口を分けてある。
        !           581: void
        !           582: MPU680x0Device::ExceptionTrap0()
        !           583: {
        !           584:        // 今発生した TRAP #0 が NetBSD/m68k システムコールっぽいか調べる。
        !           585:        //
        !           586:        // NetBSD/m68k 方面をやってる時は TRAP #0 はシステムコールを表示して
        !           587:        // ほしい。一方 Human68k などでは TRAP #0 は別用途なので、システムコール
        !           588:        // かのように表示されるのは紛らわしいので、
        !           589:        // 出来れば今呼ばれたこれが NetBSD/m68k システムコールなのか、そうでない
        !           590:        // TRAP #0 なのかは区別したい。
        !           591:        //
        !           592:        // NetBSD/m68k カーネルが実行中かどうかは厳密には分からないが、これが
        !           593:        // 呼ばれた時点で、
        !           594:        // 1) MMU がオン。
        !           595:        // 2) カーネルのエントリポイントの最初の命令が move.w #$2700,sr 命令。
        !           596:        // を満たせば NetBSD/m68k システムコールと判定することにする。
        !           597:        // カーネルエントリポイントは機種ごとに固有で、不変ではないものの
        !           598:        // ブートローダ側にも影響があるためおそらくそう簡単には変わらないだろう。
        !           599:        // だめならまた考える。
        !           600: 
        !           601:        const uint vector = M68K::EXCEP_TRAP0;
        !           602:        uint32 info;
        !           603:        if (__predict_true(mmu_enable)) {
        !           604:                // カーネルエントリポイントの最初の命令はどれも move.w #$2700,sr。
        !           605:                if (mainbus->Peek4(netbsd_entrypoint) == 0x46fc2700) {
        !           606:                        // NetBSD/m68k カーネルっぽい。
        !           607:                        info = BranchHistory_m680x0::InfoNetBSDSyscall(reg.D[0] & 0xffff);
        !           608:                        ExceptionGeneric(vector, info);
        !           609:                        return;
        !           610:                }
        !           611:        }
        !           612:        // その他の TRAP#0 っぽい
        !           613:        Exception(vector);
        !           614: }
        !           615: 
1.1       root      616: // TRAP #15 の例外処理を行う。
                    617: // 処理自体は汎用の Exception() とまったく同じだが、
1.1.1.3   root      618: // IOCS コールの時に分岐履歴の内容を変えるため入口を分けてある。
1.1       root      619: void
                    620: MPU680x0Device::ExceptionTrap15()
                    621: {
                    622:        // 今発生した TRAP #15 が IOCS コールっぽいかどうか調べる。
                    623:        //
                    624:        // Human68k 方面をやってる時は TRAP #15 は IOCS コールで表示してほしい。
                    625:        // 一方、NetBSD のカーネル内では TRAP #15 は IOCS コールではない別用途
                    626:        // なので IOCS コールかのように表示されるのは紛らわしい。さらに言えば
                    627:        // NetBSD でもブートローダの時点はまだ IOCS コールを使うので、出来れば
                    628:        // 今呼ばれたこれが IOCS コールなのか、そうでない TRAP #15 なのかは
                    629:        // 区別したい。
                    630:        //
                    631:        // IOCS コールかどうかは厳密には分からないが、これが呼ばれた時点で
1.1.1.3   root      632:        // ワークエリアの $cb6 == 0x02、$cb7 == 0x03 であれば IOCS コールと
1.1       root      633:        // 判定することにする。
1.1.1.3   root      634:        // $cb6、$cb7 はシステムポートの機種とクロック数 (を加工したもの)
                    635:        // なので、本体が X68030 であれば常に 0x02、0x03 になるはず。
1.1       root      636:        // だめならまた考える。
                    637: 
                    638:        const uint vector = M68K::EXCEP_TRAP15;
1.1.1.3   root      639:        uint32 info;
                    640:        if (mainbus->Peek1(0xcb6) == 0x02 && mainbus->Peek1(0xcb7) == 0x03) {
1.1       root      641:                // IOCS コールっぽい
1.1.1.3   root      642:                info = BranchHistory_m680x0::InfoIOCSCall(reg.D[0] & 0xff);
1.1.1.5 ! root      643:                ExceptionGeneric(vector, info);
        !           644:                return;
1.1.1.3   root      645:        }
1.1.1.5 ! root      646: 
        !           647:        // その他の TRAP#15 っぽい
        !           648:        Exception(vector);
1.1.1.3   root      649: }
                    650: 
                    651: // F ライン例外処理を行う。
                    652: // 処理自体は Exception() とまったく同じだが、
                    653: // DOS コールの時に分岐履歴の内容を変えるため入口を分けてある。
                    654: void
                    655: MPU680x0Device::ExceptionFLine()
                    656: {
                    657:        // 今発生した F ライン例外が DOS コールっぽいかどうか調べる。
                    658:        // といいつつ今のところ IOCS ワークで判定している。
                    659:        // DOS コールは本来 Human68k が起動しているかどうかなので、
                    660:        // IOCS ワークがあるかどうかとは違うが、とりあえず。
                    661:        // このすぐ上の ExceptionTrap15() のコメントも参照。
                    662: 
                    663:        const uint vector = M68K::EXCEP_FLINE;
                    664:        uint32 info;
                    665:        if ((ir & 0xff00) == 0xff00 &&
                    666:                mainbus->Peek1(0xcb6) == 0x02 && mainbus->Peek1(0xcb7) == 0x03)
                    667:        {
                    668:                // DOS コールっぽい。
                    669:                info = BranchHistory_m680x0::InfoDOSCall(ir);
                    670:        } else {
                    671:                // F ライン例外っぽい。
                    672:                info = BranchHistory_m680x0::InfoException(vector);
1.1       root      673:        }
1.1.1.3   root      674:        ExceptionGeneric(vector, info);
1.1       root      675: }
                    676: 
                    677: // 汎用の例外処理本体。
                    678: // ext_vector は下位8ビットがベクタ番号、
                    679: // 8ビット目が %1 なら浮動小数点未実装命令例外 (vector は F ライン)。
1.1.1.3   root      680: // info は履歴に記録するやつ。
1.1       root      681: void
1.1.1.3   root      682: MPU680x0Device::ExceptionGeneric(uint ext_vector, uint32 info)
1.1       root      683: {
                    684:        uint vector = ext_vector & 0xff;
                    685: 
                    686:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
1.1.1.5 ! root      687:        last_vector = vector;
1.1       root      688:        excep_counter[vector]++;
                    689:        uint32 from = ppc | (IsSuper() ? 1 : 0);
1.1.1.3   root      690:        exhist.AddEntry(from, 0, info);
                    691:        brhist.AddEntry(from, 0, info);
1.1       root      692: 
                    693:        // 状態を保存
                    694:        uint16 sr = GetSR();
                    695: 
                    696:        // S を立てて T1,T0 を落とす
                    697:        SetSR((GetSR() | M68K::SR_S) & ~M68K::SR_T);
                    698: 
                    699:        try {
                    700:                switch (ext_vector) {
                    701:                 case M68K::EXCEP_ILLEGAL:              // 不当命令
                    702:                 case M68K::EXCEP_PRIV:                 // 特権違反例外
                    703:                 case M68K::EXCEP_ALINE:                // Aライン命令例外
                    704:                 case M68K::EXCEP_FLINE:                // Fライン命令例外
                    705:                 case M68K::EXCEP_FORMAT:               // フォーマットエラー例外
                    706:                        // スタックに積む PC はこの命令のアドレス
                    707:                        GenerateExframe0(vector, sr, ppc);
                    708:                        break;
                    709: 
                    710:                 case M68K::EXCEP_TRAP0                 // TRAP#0
                    711:                  ... M68K::EXCEP_TRAP15:               // TRAP#15
                    712:                        // スタックに積む PC は次の命令
                    713:                        GenerateExframe0(vector, sr, reg.pc);
                    714:                        break;
                    715: 
                    716:                 case M68K::EXCEP_ZERODIV:              // ゼロ除算
                    717:                 case M68K::EXCEP_CHK:                  // CHK
                    718:                 case M68K::EXCEP_TRAPV:                // TRAPV
                    719:                 case M68K::EXCEP_MMU_CONFIG:   // MMU 構成例外
                    720:                        GenerateExframe2(vector, sr, reg.pc, ppc);
                    721:                        break;
                    722: 
                    723:                 case M68K::EXCEP_FP_UNIMPL:    // 68040 の浮動小数点未実装命令例外
                    724:                 case M68K::EXCEP_FP_UNSUPP:    // 68040 の FPU 未実装データ型例外
                    725:                        // スタックに積む PC は次の命令、ADDRESS は計算した EA。
                    726:                        GenerateExframe2(vector, sr, reg.pc, fpu40.ea);
                    727:                        break;
                    728: 
                    729:                 default:
                    730:                        PANIC("$%08x exception vector %u ?", ppc, vector);
                    731:                        break;
                    732:                }
                    733: 
                    734:                // ベクタにジャンプ
                    735:                JumpVector(vector, false);
                    736:        } catch (uint vector2) {
                    737:                assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector=%u", vector);
                    738: 
                    739:                // バスエラー処理へ
                    740:                ExceptionBuserr(vector2);
                    741:        }
                    742: }
                    743: 
                    744: // バスエラー・アドレスエラー例外処理を行う。
                    745: // 他の例外とは違いが多いので分けた。
                    746: void
                    747: MPU680x0Device::ExceptionBuserr(uint vector)
                    748: {
                    749:        assertmsg((vector == M68K::EXCEP_BUSERR || vector == M68K::EXCEP_ADDRERR),
                    750:                "vector=%u", vector);
                    751: 
                    752:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
1.1.1.5 ! root      753:        last_vector = vector;
1.1       root      754:        excep_counter[vector]++;
                    755:        uint32 from = ppc | (IsSuper() ? 1 : 0);
1.1.1.3   root      756:        uint32 info = BranchHistory_m680x0::InfoException(vector);
                    757:        exhist.AddEntry(from, 0, info);
                    758:        brhist.AddEntry(from, 0, info);
1.1       root      759: 
1.1.1.3   root      760:        // 現状 68030 のバスエラーに short/long の区別はないので全部 long 相当。
                    761:        CYCLE3(busfault);
                    762: 
1.1       root      763:        // 状態を保存
                    764:        uint16 sr = GetSR();
                    765: 
                    766:        if (mpu_type == m680x0MPUType::M68030) {
                    767:                // 68030 なら、
                    768:                // ここで (An)+ で変化したレジスタを命令実行前の状態に巻き戻す。
                    769:                // EA 処理の時点で先にインクリメントしているのだが、バスエラーが
                    770:                // 起きたということは実際にはポストインクリメントは発生しないので、
                    771:                // ここで無条件に巻き戻してよい。SR を書き換えると A7 が切り替わって
                    772:                // しまうので、この巻き戻しは SR を書き換える前のここで行うこと。
                    773:                // 一方、プリデクリメントのケースはこの少し上の ExframeB の中の
                    774:                // コメント参照。
                    775:                restore_reg_pi();
                    776:        } else {
                    777:                // 68040 なら、
                    778:                // (An)+, -(An) どちらも命令実行前の状態に巻き戻す。
                    779:                // 少し上の frame7 の中のコメントも参照。
                    780:                restore_reg_pi();
                    781:                restore_reg_pd();
                    782:        }
                    783: 
                    784:        // S を立てて T1,T0 を落とす
                    785:        SetSR((GetSR() | M68K::SR_S) & ~M68K::SR_T);
                    786: 
                    787:        try {
                    788:                // フレームを作成。
                    789:                if (mpu_type == m680x0MPUType::M68030) {
                    790:                        // 実際はショート($A)、ロング($B)の2種類あって、本来ならショートが
                    791:                        // 使えればショートを使うのだが、ここでは全部ロングを使う。
                    792:                        GenerateExframeB(vector, sr);
                    793:                } else {
                    794:                        // 68040 ではバスエラーは $7、アドレスエラーは $2 を使う。
                    795:                        if (__predict_true(vector == M68K::EXCEP_BUSERR)) {
                    796:                                GenerateExframe7(vector, sr);
                    797:                        } else {
                    798:                                uint32 fault_addr = bus.laddr.Addr();
                    799:                                GenerateExframe2(vector, sr, ppc, fault_addr - 1);
                    800:                        }
                    801:                }
                    802:                // ベクタにジャンプ
                    803:                JumpVector(vector, true);
                    804:        } catch (uint vector2) {
                    805:                // ここに来るのはバスエラーかアドレスエラーだけのはず
                    806:                assertmsg(vector2 == M68K::EXCEP_BUSERR ||
                    807:                          vector2 == M68K::EXCEP_ADDRERR, "vector=%u", vector);
                    808: 
                    809:                // バスエラー・アドレスエラー処理中のバスエラーは
                    810:                // ダブルバスフォールト。
                    811:                DoubleBusFault("bus/address error handling");
                    812:        }
                    813: }
                    814: 
                    815: // 割り込み例外処理を行う。
                    816: // 割り込みの受け付けとレベルのチェック等の後、次命令境界で呼ばれるやつ。
                    817: // この処理にかかる時間 [nsec] を返す。
                    818: uint64
                    819: MPU680x0Device::ExceptionInterrupt()
                    820: {
                    821:        uint64 cycle_start = used_cycle;
                    822:        uint level = intr_level;
                    823: 
                    824:        // ユーザーズマニュアル(日本語) p.399 図8-5 の中ほど
                    825:        // 「/IPEND をネゲート、割り込みアクノリッジサイクルを実行」
                    826:        // 以降に相当。
                    827: 
                    828:        // STOP なら解除
                    829:        ChangeState(CPU_STATE_NORMAL);
                    830: 
                    831:        // 割り込みアクノリッジサイクルを実行
                    832:        uint32 vector;
                    833:        busdata bd = interruptdev->InterruptAcknowledge(level);
                    834:        if (__predict_false(bd.IsBusErr())) {
                    835:                // 外部回路がバスエラーを返すと Spurious を発行する。(7.4.1.3)
                    836:                vector = M68K::EXCEP_SPURIOUS;
                    837:        } else {
                    838:                vector = bd.Data();
                    839:                if ((int32)vector < 0) {
                    840:                        // オートベクタ要求 (7.4.1.2)
                    841:                        // (負数(-1)ならオートベクタということにしている)
                    842:                        vector = M68K::EXCEP_LEVEL_BASE + level;
                    843:                }
                    844:        }
                    845: 
                    846:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
1.1.1.5 ! root      847:        last_vector = vector;
1.1       root      848:        excep_counter[vector]++;
                    849:        uint32 from = ppc | (IsSuper() ? 1 : 0);
1.1.1.3   root      850:        uint32 info = BranchHistory_m680x0::InfoException(vector);
                    851:        exhist.AddEntry(from, 0, info);
                    852:        brhist.AddEntry(from, 0, info);
1.1       root      853: 
                    854:        // 状態を保存
                    855:        uint16 oldsr = GetSR();
                    856: 
                    857:        // S を立てて T1,T0 を落とす。割り込みレベルも変更。
                    858:        uint16 newsr = GetSR() & ~(M68K::SR_T | M68K::SR_IMASK);
                    859:        newsr |= M68K::SR_S;
                    860:        newsr |= level << 8;
                    861:        SetSR(newsr);
                    862: 
                    863:        try {
                    864:                // 例外スタックフレーム $0 を生成。
                    865:                // スタックに積む PC は次の命令位置。
                    866:                // M ビットは未実装なのでスローアウェイとか無視
                    867:                GenerateExframe0(vector, oldsr, reg.pc);
                    868: 
                    869:                // ベクタにジャンプ
                    870:                JumpVector(vector, false);
                    871:        } catch (uint vector2) {
                    872:                assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector=%u", vector);
                    873: 
                    874:                // バスエラー処理へ
                    875:                ExceptionBuserr(vector2);
                    876:        }
                    877: 
1.1.1.5 ! root      878:        return (used_cycle - cycle_start) * clock_tsec + bd.GetWait();
1.1       root      879: }
                    880: 
1.1.1.2   root      881: // LC040 の未実装浮動小数点命令例外。
                    882: void
                    883: MPU680x0Device::ExceptionFPLC(uint32 ea)
                    884: {
                    885:        const uint vector = M68K::EXCEP_FLINE;
                    886: 
                    887:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
1.1.1.5 ! root      888:        last_vector = vector;
1.1.1.2   root      889:        excep_counter[vector]++;
                    890:        uint32 from = ppc | (IsSuper() ? 1 : 0);
1.1.1.3   root      891:        constexpr uint32 info = BranchHistory_m680x0::InfoException(vector);
                    892:        exhist.AddEntry(from, 0, info);
                    893:        brhist.AddEntry(from, 0, info);
1.1.1.2   root      894: 
                    895:        // 状態を保存
                    896:        uint16 sr = GetSR();
                    897: 
                    898:        // S を立てて T1,T0 を落とす
                    899:        SetSR((GetSR() | M68K::SR_S) & ~M68K::SR_T);
                    900: 
                    901:        try {
                    902:                GenerateExframe4(vector, sr, ea);
                    903: 
                    904:                // ベクタにジャンプ
                    905:                JumpVector(vector, false);
                    906:        } catch (uint vector2) {
                    907:                assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector=%u", vector);
                    908: 
                    909:                // バスエラー処理へ
                    910:                ExceptionBuserr(vector2);
                    911:        }
                    912: }
                    913: 
1.1       root      914: // RTE 命令。
                    915: // 例外処理の近くに置いておくほうが便利なので。
                    916: void
                    917: MPU680x0Device::ops_rte()
                    918: {
                    919:        uint32 pc;
                    920:        uint16 sr;
                    921:        uint16 frame;
                    922:        uint32 type;
                    923: 
                    924:        try {
                    925:                sr = pop_2();
                    926:                pc = pop_4();
                    927:                frame = pop_2();
                    928:                type = frame >> 12;
                    929:                switch (type) {
                    930:                 case 0:
1.1.1.3   root      931:                        CYCLE3(rte_frame0);
1.1       root      932:                        SetSR(sr);
                    933:                        Jump(pc);
                    934:                        break;
                    935: 
                    936:                 case 2:
1.1.1.3   root      937:                        CYCLE3(rte_frame2);
1.1       root      938:                        // +08.L (INSTRUCTION) ADDRESS を読み捨てる。
                    939:                        reg.A[7] += 4;
                    940:                        SetSR(sr);
                    941:                        Jump(pc);
                    942:                        break;
                    943: 
1.1.1.2   root      944:                 case 0x04:
                    945:                 {
                    946:                        // 68LC040 only
                    947:                        if (GetFPUType().Is4060LC() == false) {
                    948:                                Exception(M68K::EXCEP_FORMAT);
                    949:                                return;
                    950:                        }
1.1.1.3   root      951:                        CYCLE(15);
1.1.1.2   root      952:                        reg.A[7] += 8;
                    953:                        SetSR(sr);
                    954:                        Jump(pc);
                    955:                        break;
                    956:                 }
                    957: 
1.1       root      958:                 case 0x07:
                    959:                 {
                    960:                        // 68040 only
                    961:                        if (mpu_type != m680x0MPUType::M68040) {
                    962:                                Exception(M68K::EXCEP_FORMAT);
                    963:                                return;
                    964:                        }
1.1.1.3   root      965:                        CYCLE(23);
1.1       root      966:                        uint16 ssw;
                    967:                        reg.A[7] += 4;
                    968:                        ssw = pop_2();
                    969:                        putlog(2, "RTE (Frame7): SSW=$%04x", ssw);
                    970:                        reg.A[7] += 46;
                    971:                        SetSR(sr);
                    972:                        Jump(pc);
                    973:                        break;
                    974:                 }
                    975: 
                    976:                 case 0x0b:
                    977:                 {
                    978:                        // 68030 only
                    979:                        if (mpu_type != m680x0MPUType::M68030) {
                    980:                                Exception(M68K::EXCEP_FORMAT);
                    981:                                return;
                    982:                        }
                    983: 
                    984:                        uint32 stage_b;
                    985:                        uint16 ssw;
                    986: 
                    987:                        CYCLE(76);
                    988:                        reg.A[7] += 2;                                          // $08.W
                    989:                        ssw = pop_2();                                          // $0a.W SSW
                    990:                        reg.A[7] += 4 * 6;                                      // $0c.L*6
                    991:                        stage_b = pop_4();                                      // $24.L Stage B
                    992:                        reg.A[7] += 2 * 9;                                      // $28.W*9
                    993:                        // $3a..$58 ここが save_pd の取り出し
                    994:                        flag_pd = pop_2();
                    995:                        for (int i = 0; i < 8; i++) {
                    996:                                save_pd[i] = pop_4();
                    997:                        }
                    998:                        // A7 レジスタをリストアするかもしれない前に Super/User を
                    999:                        // 復帰しておかないといけない。
                   1000:                        SetSR(sr);
                   1001: 
                   1002:                        // DFビットセットなら命令を再実行するため、-(An) で変化
                   1003:                        // したレジスタを巻き戻す。
                   1004:                        // DFビットクリアなら例外要因の命令はハンドラで処理された
                   1005:                        // とみなして、次の命令に進む。
                   1006:                        if ((ssw & M68030::SSW_DF)) {
                   1007:                                restore_reg_pd();
                   1008:                        } else {
                   1009:                                pc = stage_b - 2;
                   1010:                        }
                   1011:                        Jump(pc);
                   1012:                        break;
                   1013:                 }
                   1014: 
                   1015:                 default:
                   1016:                        if (mpu_type == m680x0MPUType::M68030) {
                   1017:                                switch (type) {
                   1018:                                 case 0x01:
                   1019:                                 case 0x08:
                   1020:                                 case 0x09:
                   1021:                                 case 0x0a:
                   1022:                                        // CPU は本来対応しているが、
                   1023:                                        // エミュレータが対応していない (遭遇しないはず)。
                   1024:                                        VMPANIC("RTE frame=$%x not supported", type);
                   1025:                                 default:
                   1026:                                        break;
                   1027:                                }
                   1028:                        } else /* 68040 */ {
                   1029:                                switch (type) {
                   1030:                                 case 0x01:
                   1031:                                 case 0x03:
                   1032:                                        // CPU は本来対応しているが、
                   1033:                                        // エミュレータが対応していない (遭遇しないはず)。
                   1034:                                        VMPANIC("RTE frame=$%x not supported", type);
                   1035:                                 default:
                   1036:                                        break;
                   1037:                                }
                   1038:                        }
                   1039:                        // CPU が対応していないフレームタイプはフォーマットエラー例外。
                   1040:                        Exception(M68K::EXCEP_FORMAT);
                   1041:                        break;
                   1042:                }
                   1043:        } catch (uint vector2) {
                   1044:                assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector2=%u", vector2);
                   1045: 
                   1046:                // RTE 処理中のバスエラーはダブルバスフォールト。
                   1047:                DoubleBusFault("bus/address error handling");
                   1048:        }
                   1049: }
                   1050: 
                   1051: // STOP 命令。
                   1052: void
                   1053: MPU680x0Device::ops_stop()
                   1054: {
                   1055:        uint32 data = fetch_2();
                   1056:        SetSR(data);
                   1057:        ChangeState(CPU_STATE_STOP);
                   1058: 
                   1059:        MakeNextFull();
                   1060: }

unix.superglobalmegacorp.com

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