--- nono/m680x0/m680x0core.cpp 2026/04/29 17:05:35 1.1.1.2 +++ nono/m680x0/m680x0core.cpp 2026/04/29 17:05:48 1.1.1.4 @@ -7,17 +7,21 @@ #include "mpu680x0.h" #include "bitops.h" #include "debugger.h" +#include "event.h" #include "interrupt.h" #include "mainbus.h" #include "scheduler.h" #include "vectortable.h" +#define M680X0_CYCLE_TABLE +#include "m680x0cycle.h" + #define OP_FUNC(name) __CONCAT(op_,name)() // 1命令実行する。 // 割り込みチェックなどを省いたショート版。 void -MPU680x0Device::ExecShort(Event& ev) +MPU680x0Device::ExecShort(Event *ev) { uint64 cycle_start = used_cycle; @@ -42,11 +46,6 @@ MPU680x0Device::ExecShort(Event& ev) switch (ir6) { #include "m680x0switch.h" } - - if (__predict_false(icache_enable == false)) { - used_cycle += cycle_nocache; - cycle_nocache = 0; - } } catch (uint vector) { // ここで(C++の)例外スローをキャッチするのは // - メモリ空間をアクセスした先でのバスエラー例外 @@ -72,7 +71,7 @@ MPU680x0Device::ExecShort(Event& ev) // 外部割り込みの起動は VM 側で処理している。 int cycle = used_cycle - cycle_start; - ev.time = cycle * clock_nsec + buswait; + ev->time = cycle * clock_nsec + buswait; scheduler->StartEvent(ev); } @@ -172,8 +171,9 @@ MPU680x0Device::JumpVector(uint vector, // VBR 込みのジャンプ先が確定したところで今度はブランチ履歴に記録。 // この時のブランチ元はベクタアドレス // (reg.pc は fetch によって進んでしまうので先に保存) - uint32 inst = BranchHistory_m680x0::VectorJump; - brhist.AddEntry(vecaddr | (IsSuper() ? 1 : 0), newpc, inst); + uint32 from = vecaddr | (IsSuper() ? 1 : 0); + uint32 info = BranchHistory_m680x0::InfoVectorJump(); + brhist.AddEntry(from, newpc, info); // 奇数番地ならアドレスエラー if (__predict_false((newpc & 1) != 0)) { @@ -488,8 +488,9 @@ MPU680x0Device::ExceptionReset() // m88k と動作を揃えておく。 const uint vector = 0; excep_counter[0]++; - exhist.AddEntry(reg.pc | 1, 0, BranchHistory_m680x0::Exception | 0); - brhist.AddEntry(reg.pc | 1, 0, BranchHistory_m680x0::Exception | 0); + constexpr uint32 info = BranchHistory_m680x0::InfoException(vector); + exhist.AddEntry(reg.pc | 1, 0, info); + brhist.AddEntry(reg.pc | 1, 0, info); // デバッガに通知 (例外ブレーク用)。こっちのベクタは 0 のままでよい。 debugger->NotifyExceptionMain(vector); @@ -517,9 +518,13 @@ MPU680x0Device::ExceptionReset() // 5. キャッシュの EI|ED, FI|FD, IBE|DBE, WA をクリア // 6. キャッシュエントリをすべてクリア (CI|CD) - cycle_nocache = 0; ResetCache(); + // キャッシュ状態が変わったので、サイクル表も更新。 + if (GetMPUType() == m680x0MPUType::M68030) { + cycle_table = cycle_table_030ncc; + } + // 7. TC:E、TTn:E をクリア ResetMMU(); @@ -536,8 +541,8 @@ MPU680x0Device::ExceptionReset() // 大丈夫のはずだけど fetch_4() が reg.pc を書き換えるので一応 reg.pc = pc; // リセットベクタは常に 0, 4 番地から取得したことになっている - uint32 inst = BranchHistory_m680x0::VectorJump; - brhist.AddEntry(0x00000004 | 1, reg.pc, inst); + uint32 from = 0x00000004 | 1; + brhist.AddEntry(from, reg.pc, BranchHistory_m680x0::InfoVectorJump()); } catch (uint) { DoubleBusFault("reset exception"); } @@ -561,13 +566,13 @@ MPU680x0Device::ExceptionReset() void MPU680x0Device::Exception(uint vector) { - uint32 inst = BranchHistory_m680x0::Exception | vector; - ExceptionGeneric(vector, inst); + uint32 info = BranchHistory_m680x0::InfoException(vector); + ExceptionGeneric(vector, info); } // TRAP #15 の例外処理を行う。 // 処理自体は汎用の Exception() とまったく同じだが、 -// IOCS コールの時には分岐履歴の出力が変わるため入口を分けてある。 +// IOCS コールの時に分岐履歴の内容を変えるため入口を分けてある。 void MPU680x0Device::ExceptionTrap15() { @@ -581,38 +586,64 @@ MPU680x0Device::ExceptionTrap15() // 区別したい。 // // IOCS コールかどうかは厳密には分からないが、これが呼ばれた時点で - // ワークエリアの $cbc == 0x03、$cbe == 0xff であれば IOCS コールと + // ワークエリアの $cb6 == 0x02、$cb7 == 0x03 であれば IOCS コールと // 判定することにする。 - // $cbc は MPU 種別で 3:68030。 - // $cbe は MMU 有無で 0xff:有り。 - // 今の所 68030/MMU有り しかサポートしていないので。 + // $cb6、$cb7 はシステムポートの機種とクロック数 (を加工したもの) + // なので、本体が X68030 であれば常に 0x02、0x03 になるはず。 // だめならまた考える。 const uint vector = M68K::EXCEP_TRAP15; - uint32 inst; - if (mainbus->Peek1(0xcbc) == 0x03 && mainbus->Peek1(0xcbe) == 0xff) { + uint32 info; + if (mainbus->Peek1(0xcb6) == 0x02 && mainbus->Peek1(0xcb7) == 0x03) { // IOCS コールっぽい - inst = BranchHistory_m680x0::IOCSCall | (reg.D[0] & 0xff); + info = BranchHistory_m680x0::InfoIOCSCall(reg.D[0] & 0xff); } else { // TRAP#15 っぽい - inst = BranchHistory_m680x0::Exception | vector; + info = BranchHistory_m680x0::InfoException(vector); + } + ExceptionGeneric(vector, info); +} + +// F ライン例外処理を行う。 +// 処理自体は Exception() とまったく同じだが、 +// DOS コールの時に分岐履歴の内容を変えるため入口を分けてある。 +void +MPU680x0Device::ExceptionFLine() +{ + // 今発生した F ライン例外が DOS コールっぽいかどうか調べる。 + // といいつつ今のところ IOCS ワークで判定している。 + // DOS コールは本来 Human68k が起動しているかどうかなので、 + // IOCS ワークがあるかどうかとは違うが、とりあえず。 + // このすぐ上の ExceptionTrap15() のコメントも参照。 + + const uint vector = M68K::EXCEP_FLINE; + uint32 info; + if ((ir & 0xff00) == 0xff00 && + mainbus->Peek1(0xcb6) == 0x02 && mainbus->Peek1(0xcb7) == 0x03) + { + // DOS コールっぽい。 + info = BranchHistory_m680x0::InfoDOSCall(ir); + } else { + // F ライン例外っぽい。 + info = BranchHistory_m680x0::InfoException(vector); } - ExceptionGeneric(vector, inst); + ExceptionGeneric(vector, info); } // 汎用の例外処理本体。 // ext_vector は下位8ビットがベクタ番号、 // 8ビット目が %1 なら浮動小数点未実装命令例外 (vector は F ライン)。 +// info は履歴に記録するやつ。 void -MPU680x0Device::ExceptionGeneric(uint ext_vector, uint32 inst) +MPU680x0Device::ExceptionGeneric(uint ext_vector, uint32 info) { uint vector = ext_vector & 0xff; // 例外履歴に記録 (例外発生はブランチ履歴にも記録) excep_counter[vector]++; uint32 from = ppc | (IsSuper() ? 1 : 0); - exhist.AddEntry(from, 0, inst); - brhist.AddEntry(from, 0, inst); + exhist.AddEntry(from, 0, info); + brhist.AddEntry(from, 0, info); // デバッガに通知 (例外ブレーク用) debugger->NotifyExceptionMain(vector); @@ -678,12 +709,15 @@ MPU680x0Device::ExceptionBuserr(uint vec // 例外履歴に記録 (例外発生はブランチ履歴にも記録) excep_counter[vector]++; uint32 from = ppc | (IsSuper() ? 1 : 0); - uint32 inst = BranchHistory_m680x0::Exception | vector; - exhist.AddEntry(from, 0, inst); - brhist.AddEntry(from, 0, inst); + uint32 info = BranchHistory_m680x0::InfoException(vector); + exhist.AddEntry(from, 0, info); + brhist.AddEntry(from, 0, info); // デバッガに通知 (例外ブレーク用) debugger->NotifyExceptionMain(vector); + // 現状 68030 のバスエラーに short/long の区別はないので全部 long 相当。 + CYCLE3(busfault); + // 状態を保存 uint16 sr = GetSR(); @@ -770,9 +804,9 @@ MPU680x0Device::ExceptionInterrupt() // 例外履歴に記録 (例外発生はブランチ履歴にも記録) excep_counter[vector]++; uint32 from = ppc | (IsSuper() ? 1 : 0); - uint32 inst = BranchHistory_m680x0::Exception | vector; - exhist.AddEntry(from, 0, inst); - brhist.AddEntry(from, 0, inst); + uint32 info = BranchHistory_m680x0::InfoException(vector); + exhist.AddEntry(from, 0, info); + brhist.AddEntry(from, 0, info); // デバッガに通知 (例外ブレーク用) debugger->NotifyExceptionMain(vector); @@ -808,13 +842,13 @@ void MPU680x0Device::ExceptionFPLC(uint32 ea) { const uint vector = M68K::EXCEP_FLINE; - const uint32 inst = BranchHistory_m680x0::Exception | vector; // 例外履歴に記録 (例外発生はブランチ履歴にも記録) excep_counter[vector]++; uint32 from = ppc | (IsSuper() ? 1 : 0); - exhist.AddEntry(from, 0, inst); - brhist.AddEntry(from, 0, inst); + constexpr uint32 info = BranchHistory_m680x0::InfoException(vector); + exhist.AddEntry(from, 0, info); + brhist.AddEntry(from, 0, info); // デバッガに通知 (例外ブレーク用) debugger->NotifyExceptionMain(vector); @@ -854,13 +888,13 @@ MPU680x0Device::ops_rte() type = frame >> 12; switch (type) { case 0: - CYCLE2(18, 20); + CYCLE3(rte_frame0); SetSR(sr); Jump(pc); break; case 2: - CYCLE2(18, 20); + CYCLE3(rte_frame2); // +08.L (INSTRUCTION) ADDRESS を読み捨てる。 reg.A[7] += 4; SetSR(sr); @@ -874,6 +908,7 @@ MPU680x0Device::ops_rte() Exception(M68K::EXCEP_FORMAT); return; } + CYCLE(15); reg.A[7] += 8; SetSR(sr); Jump(pc); @@ -887,6 +922,7 @@ MPU680x0Device::ops_rte() Exception(M68K::EXCEP_FORMAT); return; } + CYCLE(23); uint16 ssw; reg.A[7] += 4; ssw = pop_2();