--- nono/m680x0/m68030subr.cpp 2026/04/29 17:04:40 1.1.1.4 +++ nono/m680x0/m68030subr.cpp 2026/04/29 17:05:08 1.1.1.9 @@ -8,20 +8,19 @@ #include "m68030bus.h" #include "m68030fpu.h" #include "debugger.h" +#include "mpu680x0.h" -static void m68030_change_intr(m68kcpu *, int); -static void m68030_set_intr(m68kcpu *, int); static void m68030_double_bus_fault(m68kcpu *, const char *); // CPU コアの領域を確保して初期化 -// reset_vector はリセット例外時に 0 番地に見せる(通常ROMの)アドレス。 m68kcpu * -m68030_init(uint32 reset_vector) +m68030_init(MPU680x0Device *dev_) { m68kcpu *cpu; cpu = new m68kcpu(); fpu_init(cpu); + cpu->dev = dev_; for (int i = 0; i < 16; i++) { RegR(i) = 0xcccccccc; @@ -30,17 +29,25 @@ m68030_init(uint32 reset_vector) // あるため、A6 を概ね RAM のあるあたりに指定しておく…。 RegA(6) = 0x000ccccc; - // 手抜きのためリセットベクタを知っている - cpu->reset_vector = reset_vector; - return cpu; } +// CPU の状態 (通常/STOP/HALT) を変更する +static void +m68030_change_state(m68kcpu *cpu, uint32 new_state) +{ + if (cpu->state != new_state) { + cpu->state = new_state; + // スケジューラに通知 + cpu->dev->NotifyCPUMode(cpu->state); + } +} + // 二重バスフォールト static void m68030_double_bus_fault(m68kcpu *cpu, const char *where) { - cpu->atomic_reqflag |= CPU_REQ_RELEASE | CPU_REQ_HALT; + m68030_change_state(cpu, m68kcpu::CPU_STATE_HALT); // コールバックがあれば呼び出す if (cpu->halt_callback) { @@ -48,121 +55,24 @@ m68030_double_bus_fault(m68kcpu *cpu, co } } -// リセット例外を発生させる。 -// 各レジスタを所定の状態にして、リセットベクタを読み込む。 -// リセットベクタが読み込めなければ HALT 状態に移行。 +// 電源オン void -m68030_exception_reset(m68kcpu *cpu) +m68030_power_on(m68kcpu *cpu) { - // 履歴を初期化。リセット前の履歴いらんよな? + // サイクルを初期化。 + cpu->used_cycle = 0; + + // 履歴を初期化。電源(再)投入時のみ行う。 cpu->exhist.Clear(); cpu->brhist.Clear(); - // 例外履歴に記録 (例外発生はブランチ履歴にも記録) - // リセット例外発生時の PC にはあまり意味がないので 0 にするか。 - // 履歴のリセットベクタは 0 の代わりに 1 を使う仕様になっている。 - const uint vector = 0; - cpu->exhist.AddEntry(0, 0, 0x8000 | (vector + 1)); - cpu->brhist.AddEntry(0, 0, 0x8000 | (vector + 1)); - // デバッガに通知 (例外ブレーク用)。こっちのベクタは 0 のままでよい。 - debugger_notify_exception(vector); - - // 1. T0, T1 クリア - // 2. S をセット、M をクリア - // 3. 割り込みレベルを 7 - - // 受け付け中だった割り込みをクリア - cpu->intrmtx.lock(); - memset(&cpu->intr_vector, 0, sizeof(cpu->intr_vector)); - cpu->intrmtx.unlock(); - - // ここは set_sr を使わずに設定する。 - cpu->reg.s = true; - cpu->reg.m = false; - cpu->bus.SetFC2(cpu->reg.s); - // ここは割り込みレベル変化のチェックは不要でセットだけでいい。 - m68030_set_intr(cpu, 7); - - // 4. VBR をクリア - RegVBR = 0; - // 5. キャッシュ - RegCACR = 0; // XXX - // 6. キャッシュエントリクリア - // 7. TC:E、TTn:E をクリア - cpu->SetTC(cpu->GetTC() & ~m68030TC::TC_E); - cpu->SetTT(0, cpu->GetTT(0) & ~m68030TT::E); - cpu->SetTT(1, cpu->GetTT(1) & ~m68030TT::E); - // 8. リセットベクタ生成 - - // 9. SP をロード - // 10. PC をロード - - // 手抜き。 - // XXX 本当は ROM を 0番地に見せかけてから 0番地からロードするのだが - // ぶっちゃけそれを外部から観測する手段もないのでなー。 - // XXX FC を気にしないといけない - // XXX 読めなければ二重バスフォールト - // 本当はアドレスエラーもチェックするのだが、起きないので省略。 - try { - RegA(7) = m68030_read_32(cpu, cpu->reset_vector); - RegPC = m68030_read_32(cpu, cpu->reset_vector + 4); - // リセットベクタは常に 0, 4 番地から取得したことになっている - cpu->brhist.AddEntry(0x00000004, RegPC, 0x8000); - } catch (int) { - m68030_double_bus_fault(cpu, "reset exception"); - } -} - -// MPU 外部からの割り込み受付。 -// オートベクタの場合は vector にオートベクタの例外ベクタを指定のこと。 -void -m68030_interrupt(m68kcpu *cpu, int level, int vector) -{ - std::unique_lock lock(cpu->intrmtx); - - // この割り込みレベルがすでにペンディングなら何もしない - if ((int8)(cpu->intr_pending << level) < 0) { - return; - } - - // 割り込みを受理 - cpu->intr_pending |= (0x80U >> level); - cpu->intr_vector[level] = vector; - cpu->atomic_reqflag |= CPU_REQ_INTR; -} - -// 割り込みレベルの設定のみを行う。 -// 割り込みチェックは行わない。 -static void -m68030_set_intr(m68kcpu *cpu, int level) -{ - cpu->reg.intr_level = level; - cpu->intr_mask = 0x7f >> level; + // この後起きるリセット例外で PC を初期化する前に参照することになるので + // これだけここでも初期化しておく。 + RegPC = 0; } -// 割り込みのチェックとレベルの変更。 -// ステータスレジスタの割り込みレベルを変更し、必要な割り込みチェックを行う。 -static void -m68030_change_intr(m68kcpu *cpu, int level) -{ - int oldlevel = cpu->reg.intr_level; - - if (oldlevel < 7 && level == 7) { - // レベル 7 に引き上げられたら割り込み確認 - cpu->atomic_reqflag |= CPU_REQ_INTR; - } else if (oldlevel == 7 && level < 7) { - // レベル 7 から引き下げられたら割り込み確認 - cpu->atomic_reqflag |= CPU_REQ_INTR; - } else if (oldlevel != level) { - // それ以外でレベルが変わったら割り込み確認? - cpu->atomic_reqflag |= CPU_REQ_INTR; - } - m68030_set_intr(cpu, level); -} - -// SR (と CCR) に data を代入する。 -// リセット例外時には呼ばれないのであっちで必要に応じて似た処理をする必要が -// ある。XXX なんとかしたほうがいい +// SR (と CCR) をセットする。 +// リセット例外以外から使う (リセット例外はやや異なるため)。 void m68030_set_sr(m68kcpu *cpu, uint16 data) { @@ -181,7 +91,15 @@ m68030_set_sr(m68kcpu *cpu, uint16 data) CCR.Set(data); cpu->reg.s = ((data & M68K_SR_S) != 0); cpu->reg.m = ((data & M68K_SR_M) != 0); - m68030_change_intr(cpu, (data >> 8) & 7); + + // 割り込みマスクレジスタを更新して.. + uint new_mask = (data >> 8) & 7; + if (cpu->reg.intr_mask != new_mask) { + cpu->reg.intr_mask = new_mask; + + // 次の命令境界で割り込みをチェックさせる + cpu->dev->CheckIntr(); + } // 新しい SP を用意 if (cpu->reg.s == false) { @@ -224,49 +142,6 @@ m68030_restore_reg_pd(m68kcpu *cpu) } } -// 例外処理について。 -// -// 0. リセット例外 -// リセット例外は外部から m68030_exception_reset() を呼び出す。 -// -// 1. バスエラー例外 -// MMU による論理アドレスでのバスエラーは (m68030_mmu_translate_*() が -// false を返した後) m68030bus.cpp ルーチンが (C++の) 例外をスローする。 -// 物理アドレス空間アクセス後のバスエラーは (VM側の read*()/write*() が -// (int64)-1 を返した後) m68030bus.cpp ルーチンが (C++) の例外をスローする。 -// どちらのケースも m68030core.cpp のメインループで catch し、その catch -// ブロック内で m68030_exception() を呼び出す。 -// -// 2. アドレスエラー例外 -// アドレスエラーは m68030_jump() 内でのみ発生するはずで、その場で -// m68030_exception() を呼んで処理する。 -// -// 3. 命令中で起きる例外 -// 命令途中で起きる(確定的な)例外は m68030_exception() を呼び出す。 -// これに該当するのは -// o 特権違反 -// o A系列/F系列命令 -// o TRAP* 系命令、CHK/CHK2 命令 -// o トレース例外 (未実装) -// o ゼロ除算? -// o MMU 構成例外 -// o 不当命令 (*) -// である。 -// ただし、不当命令についてはどこで不当命令と判定されるかによって -// フローが複数存在することに注意。 -// o 1ワード目が不当命令 -// -> 命令がそれぞれ m68030_exception() で処理。 -// o 1ワード目の EA が不当命令 -// -> (C++の)例外をスローして catch 内で m68030_exception() を実行。 -// o 2ワード目が不当命令 -// -> 命令がそれぞれ m68030_exception() で処理。 -// -// 4. 割り込み例外 -// 外部デバイスは m68030_interrpt() を呼び出すことで MPU に割り込みを要求 -// する。その結果 MPU は直後の命令境界で割り込みをチェックし、 -// m68030_exception_interrupt() を呼び出す。 -// - // vector にジャンプする。vector はベクタ番号(アドレスではない)。 static inline void m68030_jump_vector(m68kcpu *cpu, int vector) @@ -280,7 +155,7 @@ m68030_jump_vector(m68kcpu *cpu, int vec // VBR 込みのジャンプ先が確定したところで今度はブランチ履歴に記録。 // この時のブランチ元はベクタアドレス // (RegPC は fetch によって進んでしまうので先に保存) - cpu->brhist.AddEntry(vecaddr, newpc, 0x8000); + cpu->brhist.AddEntry(vecaddr | (cpu->reg.s ? 1 : 0), newpc, 0x8000); CHECK_ADDRESS_ERROR(newpc); RegPC = newpc; @@ -401,6 +276,119 @@ m68030_generate_exframe_b(m68kcpu *cpu, m68030_push_16(cpu, sr); // 例外入り口で保存した SR } +// 例外処理について。 +// +// 0. リセット例外 +// リセット例外は外部から m68030_exception_reset() を呼び出す。 +// +// 1. バスエラー例外 +// MMU による論理アドレスでのバスエラーは (m68030_mmu_translate_*() が +// false を返した後) m68030bus.cpp ルーチンが (C++の) 例外をスローする。 +// 物理アドレス空間アクセス後のバスエラーは (VM側の read*()/write*() が +// (int64)-1 を返した後) m68030bus.cpp ルーチンが (C++) の例外をスローする。 +// どちらのケースも m68030core.cpp のメインループで catch し、その catch +// ブロック内で m68030_exception() を呼び出す。 +// +// 2. アドレスエラー例外 +// アドレスエラーは m68030_jump() 内でのみ発生するはずで、その場で +// m68030_exception() を呼んで処理する。 +// +// 3. 命令中で起きる例外 +// 命令途中で起きる(確定的な)例外は m68030_exception() を呼び出す。 +// これに該当するのは +// o 特権違反 +// o A系列/F系列命令 +// o TRAP* 系命令、CHK/CHK2 命令 +// o トレース例外 (未実装) +// o ゼロ除算? +// o MMU 構成例外 +// o 不当命令 (*) +// である。 +// ただし、不当命令についてはどこで不当命令と判定されるかによって +// フローが複数存在することに注意。 +// o 1ワード目が不当命令 +// -> 命令がそれぞれ m68030_exception() で処理。 +// o 1ワード目の EA が不当命令 +// -> (C++の)例外をスローして catch 内で m68030_exception() を実行。 +// o 2ワード目が不当命令 +// -> 命令がそれぞれ m68030_exception() で処理。 +// +// 4. 割り込み例外 +// 別コメント(下のほう)参照。 +// + +// リセット例外処理。 +// 各レジスタを所定の状態にして、リセットベクタを読み込む。 +// リセットベクタが読み込めなければ HALT 状態に移行。 +// 戻り値は消費したサイクル数。 +int +m68030_exception_reset(m68kcpu *cpu) +{ + uint64 cycle_start = cpu->used_cycle; + + // 例外履歴に記録 (例外発生はブランチ履歴にも記録) + // m68k では今の所リセット例外発生時の PC にはあまり意味がないけど、 + // m88k と動作を揃えておく。 + // 履歴のリセットベクタは 0 の代わりに 1 を使う仕様になっている。 + const uint vector = 0; + cpu->exhist.AddEntry(RegPC | 1, 0, 0x8000 | (vector + 1)); + cpu->brhist.AddEntry(RegPC | 1, 0, 0x8000 | (vector + 1)); + // デバッガに通知 (例外ブレーク用)。こっちのベクタは 0 のままでよい。 + debugger_notify_exception(vector); + + // RESET 信号線をネゲートしてから SP の読み込み開始まで 4クロック + // (Section 7.8, Figure 7-64) + cpu->used_cycle += 4; + + // STOP 状態とホールト状態を解除。 + m68030_change_state(cpu, m68kcpu::CPU_STATE_NORMAL); + + // 1. T0, T1 クリア + // 2. S をセット、M をクリア + // 3. 割り込みレベルを 7 + + // ここは set_sr を使わずに設定する。 + cpu->reg.s = true; + cpu->reg.m = false; + cpu->bus.SetFC2(cpu->reg.s); + // ここは割り込みレベル変化のチェックは不要でセットだけでいい。 + cpu->reg.intr_mask = 7; + + // 4. VBR をクリア + RegVBR = 0; + // 5. キャッシュ + RegCACR = 0; // XXX + // 6. キャッシュエントリクリア + // 7. TC:E、TTn:E をクリア + cpu->SetTC(cpu->GetTC() & ~m68030TC::TC_E); + cpu->SetTT(0, cpu->GetTT(0) & ~m68030TT::E); + cpu->SetTT(1, cpu->GetTT(1) & ~m68030TT::E); + // 8. リセットベクタ生成 + + // 9. SP をロード + // 10. PC をロード + try { + RegPC = 0; + RegA(7) = m68030_fetch_32(cpu); + uint32 pc = m68030_fetch_32(cpu); + // 大丈夫のはずだけど m68030_fetch_32() が RegPC を書き換えるので一応 + RegPC = pc; + // リセットベクタは常に 0, 4 番地から取得したことになっている + cpu->brhist.AddEntry(0x00000004 | 1, RegPC, 0x8000); + } catch (int) { + m68030_double_bus_fault(cpu, "reset exception"); + } + + // SP のアドレスエラーはリセット例外ではチェックしないようだ。 + // PC のアドレスエラーは本来ならここにあるはずの3ワードのプリフェッチで + // 行われるのだが、それがないので、とりあえずここで。 + if ((RegPC & 1) != 0) { + m68030_double_bus_fault(cpu, "reset exception"); + } + + return cpu->used_cycle - cycle_start; +} + // 例外処理 (リセット・割り込み以外) を行う。 // vector はベクタ番号。 void @@ -413,8 +401,9 @@ m68030_exception(m68kcpu *cpu, int vecto } // 例外履歴に記録 (例外発生はブランチ履歴にも記録) - cpu->exhist.AddEntry(RegPPC, 0, 0x8000 | vector); - cpu->brhist.AddEntry(RegPPC, 0, 0x8000 | vector); + uint32 from = RegPPC | (cpu->reg.s ? 1 : 0); + cpu->exhist.AddEntry(from, 0, 0x8000 | vector); + cpu->brhist.AddEntry(from, 0, 0x8000 | vector); // デバッガに通知 (例外ブレーク用) debugger_notify_exception(vector); @@ -471,8 +460,9 @@ m68030_exception_buserr(m68kcpu *cpu, in "vector=%d", vector); // 例外履歴に記録 (例外発生はブランチ履歴にも記録) - cpu->exhist.AddEntry(RegPPC, 0, 0x8000 | vector); - cpu->brhist.AddEntry(RegPPC, 0, 0x8000 | vector); + uint32 from = RegPPC | (cpu->reg.s ? 1 : 0); + cpu->exhist.AddEntry(from, 0, 0x8000 | vector); + cpu->brhist.AddEntry(from, 0, 0x8000 | vector); // デバッガに通知 (例外ブレーク用) debugger_notify_exception(vector); @@ -508,31 +498,119 @@ m68030_exception_buserr(m68kcpu *cpu, in } } -// 割り込み例外処理を行う。 -// intrmtx なしで呼び出すこと。 -// 割り込みチェックは m68030core.cpp::m68030_flush_interrupt() で判定している。 -void -m68030_exception_interrupt(m68kcpu *cpu, int level, int vector) +// 割り込み処理。 +// +// 割り込みは、本来命令境界ごとにチェックして条件を満たせば割り込み例外が +// 起動するのだが、割り込み例外が起きうる要因は +// o 割り込み信号線が変化した時 +// o 割り込みマスクを変更した時 +// しかないはずなので、この時だけチェックすればよいはず。 +// +// 外部割り込み信号線が変化した時 m68030_interrupt(level) が VM から呼ばれる。 +// m68030_interrupt() は割り込みレベルがマスクより高いか、レベルが下位から 7 +// に変化すれば true を返す。 +// これにより VM から割り込み処理 m68030_exception_interrupt() が呼ばれる。 +// +// 命令によって割り込みマスクを変更する場合、命令は m68030_change_intrmask() +// を呼ぶ。これが VM 側で次の命令実行コールバックを差し替えるため、 +// 次命令境界で割り込みのチェックが呼ばれる。これが m68030_check_interrupt()。 +// こちらは割り込みレベルがマスクより高いかどうかだけをチェックする (レベルは +// 変化していないので下位から 7 に変化したかは調べない)。レベルのほうが高く +// なっていれば true を返す。 +// これにより VM から割り込み処理 m68030_exception_interrupt() が呼ばれる。 + +// 割り込みレベル変更の受け付け。 +// 発生している最も高い割り込みレベルが変化した時にここに通知される。 +// 全員が下ろしたことによって 0 に遷移したことも通知されることに留意。 +// 割り込み例外を起動するなら true を返す。 +bool +m68030_interrupt(m68kcpu *cpu, int level) +{ + int mask = cpu->reg.intr_mask; + + // 信号線が 2 クロック期間安定していること云々は省略 + + // ホールトなら何もしない + if (cpu->state == m68kcpu::CPU_STATE_HALT) { + return false; + } + + // 割り込みを起こすかどうかに関わらずここで更新 + cpu->intr_level = level; + + // 割り込み例外を起動するのは + // o レベルがマスクより高い + // o マスクに関係なく、レベルが下位から 7 に変化した場合 + // (ここは変化した時だけ呼ばれるのと 7 より上はないので + // level==7 なら必ず「下位から 7 に変化」のはず) + if (level > mask || level == 7) { + return true; + } + + return false; +} + +// 割り込みをチェックする。 +// 割り込みマスク変更後の命令境界で VM 側から呼ばれる。 +// 割り込みを起こすなら true を返す。 +bool +m68030_check_interrupt(m68kcpu *cpu) { + int mask = cpu->reg.intr_mask; + int level = cpu->intr_level; + + // こちらは HALT では呼び出されない + + // 割り込みレベルは変化していないので、ここでは Level 7 の特別処理は不要 + if (level > mask) { + return true; + } + return false; +} + +// 割り込み例外処理を行う。 +// 割り込みの受け付けとレベルのチェック等の後、次命令境界で呼ばれるやつ。 +int +m68030_exception_interrupt(m68kcpu *cpu) +{ + int cycle_start = cpu->used_cycle; + int level = cpu->intr_level; + + // ユーザーズマニュアル(日本語) p.399 図8-5 の中ほど + // 「/IPEND をネゲート、割り込みアクノリッジサイクルを実行」 + // 以降に相当。 + + // STOP なら解除 + m68030_change_state(cpu, m68kcpu::CPU_STATE_NORMAL); + + // 割り込みアクノリッジサイクルを実行 + int vector = m68030_interrupt_acknowledge(level); + if (vector == -1) { + vector = 24 + level; + } + // 例外履歴に記録 (例外発生はブランチ履歴にも記録) - cpu->exhist.AddEntry(RegPPC, 0, 0x8000 | (level << 8) | vector); - cpu->brhist.AddEntry(RegPPC, 0, 0x8000 | (level << 8) | vector); + uint32 from = RegPPC | (cpu->reg.s ? 1 : 0); + uint32 inst = 0x8000 | (level << 8) | vector; + cpu->exhist.AddEntry(from, 0, inst); + cpu->brhist.AddEntry(from, 0, inst); // デバッガに通知 (例外ブレーク用) debugger_notify_exception(vector); // 状態を保存 - uint16 sr = RegSR; + uint16 oldsr = RegSR; - // S を立てて T1,T0 を落とす - m68030_set_sr(cpu, (RegSR | M68K_SR_S) & ~M68K_SR_T); - // 割り込みレベルを変更 - m68030_change_intr(cpu, level); + // S を立てて T1,T0 を落とす。割り込みレベルも変更。 + uint16 newsr = RegSR & ~(M68K_SR_T | M68K_SR_IMASK); + newsr |= M68K_SR_S; + newsr |= level << 8; + m68030_set_sr(cpu, newsr); try { // 例外スタックフレーム $0 を生成。 // スタックに積む PC は次の命令位置。 // M ビットは未実装なのでスローアウェイとか無視 - m68030_generate_exframe_0(cpu, vector, RegPC, sr); + m68030_generate_exframe_0(cpu, vector, RegPC, oldsr); // ベクタにジャンプ m68030_jump_vector(cpu, vector); @@ -542,6 +620,8 @@ m68030_exception_interrupt(m68kcpu *cpu, // バスエラー処理へ m68030_exception_buserr(cpu, vector2); } + + return cpu->used_cycle - cycle_start; } // RTE 命令。 @@ -617,181 +697,14 @@ m68030_rte(m68kcpu *cpu) } } -static const char * const exception_name_table[] = { - // 0123456789012345678 <- 例外履歴欄の横幅 - /* 0 */ "Reset", - /* 1 */ NULL, - /* 2 */ "Bus Error", - /* 3 */ "Address Error", - /* 4 */ "Illegal Instruction", - /* 5 */ "Zero Divide", - /* 6 */ "CHK/CHK2 Insn", - /* 7 */ "TRAPV, *TRAPcc Insn", - /* 8 */ "PriviledgeViolation", - /* 9 */ "Trace", - /* 10 */ "Line 1010 emulator", - /* 11 */ "Line 1111 emulator", - /* 12 */ NULL, - /* 13 */ "CoproProtoViolation", - /* 14 */ "Format Error", - /* 15 */ "Uninitialized Intr", - /* 16 */ NULL, NULL, NULL, NULL, - /* 20 */ NULL, NULL, NULL, NULL, - /* 24 */ "Spurious Interrupt", - /* 25 */ "Level 1 Interrupt", - /* 26 */ "Level 2 Interrupt", - /* 27 */ "Level 3 Interrupt", - /* 28 */ "Level 4 Interrupt", - /* 29 */ "Level 5 Interrupt", - /* 30 */ "Level 6 Interrupt", - /* 31 */ "Level 7 Interrupt", - /* 32 */ "Trap #0", - /* 33 */ "Trap #1", - /* 34 */ "Trap #2", - /* 35 */ "Trap #3", - /* 36 */ "Trap #4", - /* 37 */ "Trap #5", - /* 38 */ "Trap #6", - /* 39 */ "Trap #7", - /* 40 */ "Trap #8", - /* 41 */ "Trap #9", - /* 42 */ "Trap #10", - /* 43 */ "Trap #11", - /* 44 */ "Trap #12", - /* 45 */ "Trap #13", - /* 46 */ "Trap #14", - /* 47 */ "Trap #15", - // 0123456789012345678 - /* 48 */ "FPCP Branch", - /* 49 */ "FPCP InexcactResult", - /* 50 */ "FPCP Divide by Zero", - /* 51 */ "FPCP UnderFlow", - /* 52 */ "FPCP Operand Error", - /* 53 */ "FPCP OverFlow", - /* 54 */ "FPCP Signaling NAN", - /* 55 */ NULL, - /* 56 */ "MMU Config Error", - /* 57 */ NULL, - /* 58 */ NULL, - /* 59 */ NULL, - /* 60 */ NULL, - /* 61 */ NULL, - /* 62 */ NULL, - /* 63 */ NULL, - // 0123456789012345678 - /* $40 */ "MFP Alarm", - /* $41 */ "MFP EXPON", - /* $42 */ "MFP POWSW", - /* $43 */ "MFP FM IRQ", - /* $44 */ "MFP Timer-D", - /* $45 */ "MFP Timer-C", - /* $46 */ "MFP V-Disp", - /* $47 */ "MFP GPIP5", - /* $48 */ "MFP Timer-B", - /* $49 */ "MFP TX Error", - /* $4a */ "MFP TX Empty", - /* $4b */ "MFP RX Error", - /* $4c */ "MFP RX Full", - /* $4d */ "MFP Timer-A", - /* $4e */ "MFP CRTC IRQ", - /* $4f */ "MFP H-Sync", - /* $50 */ "SCC#B TX Empty", - /* $51 */ "SCC#B TX Empty", - /* $52 */ "SCC#B", - /* $53 */ "SCC#B", - /* $54 */ "SCC#B", - /* $55 */ "SCC#B", - /* $56 */ "SCC#B", - /* $57 */ "SCC#B", - /* $58 */ "SCC#A TX Empty", - /* $59 */ "SCC#A TX Empty", - /* $5a */ "SCC#A", - /* $5b */ "SCC#A", - /* $5c */ "SCC#A", - /* $5d */ "SCC#A", - /* $5e */ "SCC#A", - /* $5f */ "SCC#A", - - // 0123456789012345678 - /* $60 */ "I/O FDC Intr", - /* $61 */ "I/O FDD Intr", - /* $62 */ "I/O HDC Intr", - /* $63 */ "I/O PRN Intr", - /* $64 */ "DMAC#0 Complete", - /* $65 */ "DMAC#0 Error", - /* $66 */ "DMAC#1 Complete", - /* $67 */ "DMAC#1 Error", - /* $68 */ "DMAC#2 Complete", - /* $69 */ "DMAC#2 Error", - /* $6a */ "DMAC#3 Complete", - /* $6b */ "DMAC#3 Error", - /* $6c */ "SPC Interrupt", - /* $6d */ NULL, - /* $6e */ NULL, - /* $6f */ NULL, - - /* $70 */ NULL, NULL, NULL, NULL, - /* $74 */ NULL, NULL, NULL, NULL, - /* $78 */ NULL, NULL, NULL, NULL, - /* $7c */ NULL, NULL, NULL, NULL, - /* $80 */ NULL, NULL, NULL, NULL, // MIDI - /* $84 */ NULL, NULL, NULL, NULL, // MIDI - /* $88 */ NULL, NULL, NULL, NULL, // MIDI - /* $8c */ NULL, NULL, NULL, NULL, // MIDI - /* $90 */ NULL, NULL, NULL, NULL, - /* $94 */ NULL, NULL, NULL, NULL, - /* $98 */ NULL, NULL, NULL, NULL, - /* $9c */ NULL, NULL, NULL, NULL, - /* $a0 */ NULL, NULL, NULL, NULL, // MIDI - /* $a4 */ NULL, NULL, NULL, NULL, // MIDI - /* $a8 */ NULL, NULL, NULL, NULL, // MIDI - /* $ac */ NULL, NULL, NULL, NULL, // MIDI - /* $b0 */ NULL, NULL, NULL, NULL, // RS-232C - /* $b4 */ NULL, NULL, NULL, NULL, // RS-232C - /* $b8 */ NULL, NULL, NULL, NULL, // RS-232C - /* $bc */ NULL, NULL, NULL, NULL, // RS-232C - /* $c0 */ NULL, NULL, NULL, NULL, // RS-232C - /* $c4 */ NULL, NULL, NULL, NULL, // RS-232C - /* $c8 */ NULL, NULL, NULL, NULL, // RS-232C - /* $cc */ NULL, NULL, NULL, NULL, // RS-232C - /* $d0 */ NULL, NULL, NULL, NULL, - /* $d4 */ NULL, NULL, NULL, NULL, - /* $d8 */ NULL, NULL, NULL, NULL, - /* $dc */ NULL, NULL, NULL, NULL, - /* $e0 */ NULL, NULL, NULL, NULL, - /* $e4 */ NULL, NULL, NULL, NULL, - /* $e8 */ NULL, NULL, NULL, NULL, - /* $ec */ NULL, NULL, NULL, NULL, - - // 0123456789012345678 - /* $f0 */ "PSX16x50 Interrupt", - /* $f1 */ NULL, - /* $f2 */ NULL, - /* $f3 */ NULL, - /* $f4 */ NULL, - /* $f5 */ NULL, - /* $f6 */ "ExSPC Interrupt", - /* $f7 */ NULL, // TS-6BSI - /* $f8 */ "Nereid#1 Interrupt", - /* $f9 */ "Neptune-X Interrupt", - /* $fa */ "Nereid#1 USB", - /* $fb */ "Nereid#0 USB", - /* $fc */ NULL, - /* $fd */ NULL, - /* $fe */ NULL, - /* $ff */ NULL, -}; - -// ベクタ番号から表示名を返す -const char * -m68030_get_exception_name(int vector) -{ - const char *name = NULL; - if (vector < countof(exception_name_table)) { - name = exception_name_table[vector]; - } - if (name == NULL) { - name = "(reserved?)"; - } - return name; +// STOP 命令。 +// 動作制御が必要なのでこっちに置いておくほうが便利。 +void +m68030_stop(m68kcpu *cpu) +{ + uint32 data = m68030_fetch_16(cpu); + m68030_set_sr(cpu, data); + m68030_change_state(cpu, m68kcpu::CPU_STATE_STOP); + + cpu->dev->MakeNextFull(); }