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