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