--- nono/m680x0/m68030core.cpp 2026/04/29 17:05:15 1.1.1.8 +++ nono/m680x0/m68030core.cpp 2026/04/29 17:05:19 1.1.1.9 @@ -55,7 +55,11 @@ MPU680x0Device::ExecShort(Event& ev) putlogn("vector 0x%x", vector); } } - Exception(vector); + if (vector == M68K::EXCEP_BUSERR) { + ExceptionBuserr(vector); + } else { + Exception(vector); + } } // 外部割り込みの起動は VM 側で処理している。 @@ -161,11 +165,12 @@ MPU680x0Device::JumpVector(int vector) // VBR 込みのジャンプ先が確定したところで今度はブランチ履歴に記録。 // この時のブランチ元はベクタアドレス // (reg.pc は fetch によって進んでしまうので先に保存) - brhist.AddEntry(vecaddr | (IsSuper() ? 1 : 0), newpc, 0x8000); + uint32 inst = BranchHistory_m680x0::VectorJump; + brhist.AddEntry(vecaddr | (IsSuper() ? 1 : 0), newpc, inst); // 奇数番地ならアドレスエラー if (__predict_false((newpc & 1) != 0)) { - Exception(M68K::EXCEP_ADDRERR); + ExceptionBuserr(M68K::EXCEP_ADDRERR); return; } reg.pc = newpc; @@ -297,11 +302,11 @@ MPU680x0Device::GenerateExframeB(int vec // 物理アドレス空間アクセス後のバスエラーは (VM側の read*()/write*() が // (int64)-1 を返した後) m68030bus.cpp ルーチンが (C++) の例外をスローする。 // どちらのケースも m68030core.cpp のメインループで catch し、その catch -// ブロック内で Exception() を呼び出す。 +// ブロック内で ExceptionBuserr() を呼び出す。 // // 2. アドレスエラー例外 // アドレスエラーは Jump() 内でのみ発生するはずで、その場で -// Exception() を呼んで処理する。 +// ExceptionBuserr() を呼んで処理する。 // // 3. 命令中で起きる例外 // 命令途中で起きる(確定的な)例外は Exception() を呼び出す。 @@ -339,10 +344,9 @@ MPU680x0Device::ExceptionReset() // 例外履歴に記録 (例外発生はブランチ履歴にも記録) // m68k では今の所リセット例外発生時の PC にはあまり意味がないけど、 // m88k と動作を揃えておく。 - // 履歴のリセットベクタは 0 の代わりに 1 を使う仕様になっている。 const uint vector = 0; - exhist.AddEntry(reg.pc | 1, 0, 0x8000 | (vector + 1)); - brhist.AddEntry(reg.pc | 1, 0, 0x8000 | (vector + 1)); + exhist.AddEntry(reg.pc | 1, 0, BranchHistory_m680x0::Exception | 0); + brhist.AddEntry(reg.pc | 1, 0, BranchHistory_m680x0::Exception | 0); // デバッガに通知 (例外ブレーク用)。こっちのベクタは 0 のままでよい。 debugger->NotifyExceptionMain(vector); @@ -384,7 +388,8 @@ MPU680x0Device::ExceptionReset() // 大丈夫のはずだけど fetch_32() が reg.pc を書き換えるので一応 reg.pc = pc; // リセットベクタは常に 0, 4 番地から取得したことになっている - brhist.AddEntry(0x00000004 | 1, reg.pc, 0x8000); + uint32 inst = BranchHistory_m680x0::VectorJump; + brhist.AddEntry(0x00000004 | 1, reg.pc, inst); } catch (int) { DoubleBusFault("reset exception"); } @@ -399,21 +404,62 @@ MPU680x0Device::ExceptionReset() return used_cycle - cycle_start; } -// 例外処理 (リセット・割り込み以外) を行う。 -// vector はベクタ番号。 +// 汎用の例外処理を行う。vector はベクタ番号。 +// ただし以下の例外はここではなくそれぞれ固有のを呼ぶこと。 +// o リセット例外は ExceptionReset() +// o 割り込み例外は ExceptionInterrupt() +// o TRAP#15 例外は ExceptionTrap15() +// o バスエラー・アドレスエラーは ExceptionBuserr() void MPU680x0Device::Exception(int vector) { - // バスエラー・アドレスエラーは別で処理。 - if (vector <= M68K::EXCEP_ADDRERR) { - ExceptionBuserr(vector); - return; + uint32 inst = BranchHistory_m680x0::Exception | vector; + ExceptionGeneric(vector, inst); +} + +// TRAP #15 の例外処理を行う。 +// 処理自体は汎用の Exception() とまったく同じだが、 +// IOCS コールの時には分岐履歴の出力が変わるため入口を分けてある。 +void +MPU680x0Device::ExceptionTrap15() +{ + // 今発生した TRAP #15 が IOCS コールっぽいかどうか調べる。 + // + // Human68k 方面をやってる時は TRAP #15 は IOCS コールで表示してほしい。 + // 一方、NetBSD のカーネル内では TRAP #15 は IOCS コールではない別用途 + // なので IOCS コールかのように表示されるのは紛らわしい。さらに言えば + // NetBSD でもブートローダの時点はまだ IOCS コールを使うので、出来れば + // 今呼ばれたこれが IOCS コールなのか、そうでない TRAP #15 なのかは + // 区別したい。 + // + // IOCS コールかどうかは厳密には分からないが、これが呼ばれた時点で + // ワークエリアの $cbc == 0x03、$cbe == 0xff であれば IOCS コールと + // 判定することにする。 + // $cbc は MPU 種別で 3:68030。 + // $cbe は MMU 有無で 0xff:有り。 + // 今の所 68030/MMU有り しかサポートしていないので。 + // だめならまた考える。 + + const int vector = M68K::EXCEP_TRAP15; + uint32 inst; + if (mainbus->Peek8(0xcbc) == 0x03 && mainbus->Peek8(0xcbe) == 0xff) { + // IOCS コールっぽい + inst = BranchHistory_m680x0::IOCSCall | (reg.D[0] & 0xff); + } else { + // TRAP#15 っぽい + inst = BranchHistory_m680x0::Exception | vector; } + ExceptionGeneric(vector, inst); +} +// 汎用の例外処理本体。 +void +MPU680x0Device::ExceptionGeneric(int vector, uint32 inst) +{ // 例外履歴に記録 (例外発生はブランチ履歴にも記録) uint32 from = ppc | (IsSuper() ? 1 : 0); - exhist.AddEntry(from, 0, 0x8000 | vector); - brhist.AddEntry(from, 0, 0x8000 | vector); + exhist.AddEntry(from, 0, inst); + brhist.AddEntry(from, 0, inst); // デバッガに通知 (例外ブレーク用) debugger->NotifyExceptionMain(vector); @@ -471,8 +517,9 @@ MPU680x0Device::ExceptionBuserr(int vect // 例外履歴に記録 (例外発生はブランチ履歴にも記録) uint32 from = ppc | (IsSuper() ? 1 : 0); - exhist.AddEntry(from, 0, 0x8000 | vector); - brhist.AddEntry(from, 0, 0x8000 | vector); + uint32 inst = BranchHistory_m680x0::Exception | vector; + exhist.AddEntry(from, 0, inst); + brhist.AddEntry(from, 0, inst); // デバッガに通知 (例外ブレーク用) debugger->NotifyExceptionMain(vector); @@ -531,7 +578,7 @@ MPU680x0Device::ExceptionInterrupt() // 例外履歴に記録 (例外発生はブランチ履歴にも記録) uint32 from = ppc | (IsSuper() ? 1 : 0); - uint32 inst = 0x8000 | (level << 8) | vector; + uint32 inst = BranchHistory_m680x0::Exception | vector; exhist.AddEntry(from, 0, inst); brhist.AddEntry(from, 0, inst); // デバッガに通知 (例外ブレーク用)