--- nono/m680x0/m68030core.cpp 2026/04/29 17:05:19 1.1.1.9 +++ nono/m680x0/m68030core.cpp 2026/04/29 17:05:22 1.1.1.10 @@ -14,12 +14,13 @@ // 1命令実行する。 // 割り込みチェックなどを省いたショート版。 -// 戻り値は消費したサイクル数。 void MPU680x0Device::ExecShort(Event& ev) { uint64 cycle_start = used_cycle; + buswait = 0; + try { // 1命令版では switch-case を使うしかない。 ppc = reg.pc; @@ -40,8 +41,10 @@ MPU680x0Device::ExecShort(Event& ev) #include "m68030switch.h" } - used_cycle += cycle_nocache; - cycle_nocache = 0; + if (__predict_false(icache_enable == false)) { + used_cycle += cycle_nocache; + cycle_nocache = 0; + } } catch (int vector) { // ここで(C++の)例外スローをキャッチするのは // - メモリ空間をアクセスした先でのバスエラー例外 @@ -65,7 +68,7 @@ MPU680x0Device::ExecShort(Event& ev) // 外部割り込みの起動は VM 側で処理している。 int cycle = used_cycle - cycle_start; - ev.time = cycle * clock_nsec; + ev.time = cycle * clock_nsec + buswait; scheduler->StartEvent(ev); } @@ -120,8 +123,9 @@ MPU680x0Device::SetSR(uint16 data) reg.A[7] = reg.msp; } - // バスの FC2 を変更 - bus.SetFC2(reg.s); + // FC2-0 + fc_inst.Set(0, busaddr::Fetch, reg.s); + fc_data.Set(0, busaddr::D, reg.s); // XXX 他に何か状態変えないといけないことあったっけか。 } @@ -154,7 +158,7 @@ MPU680x0Device::restore_reg_pd() // vector にジャンプする。vector はベクタ番号(アドレスではない)。 void -MPU680x0Device::JumpVector(int vector) +MPU680x0Device::JumpVector(int vector, bool from_buserr) { uint32 vecaddr; uint32 newpc; @@ -170,7 +174,12 @@ MPU680x0Device::JumpVector(int vector) // 奇数番地ならアドレスエラー if (__predict_false((newpc & 1) != 0)) { - ExceptionBuserr(M68K::EXCEP_ADDRERR); + if (from_buserr) { + // バスエラー処理中ならダブルバスフォールト。 + throw M68K::EXCEP_ADDRERR; + } else { + ExceptionBuserr(M68K::EXCEP_ADDRERR); + } return; } reg.pc = newpc; @@ -230,9 +239,14 @@ MPU680x0Device::GenerateExframeB(int vec stageBaddr = reg.pc + 2; // この後のスタック操作で bus が変化する前に保存 - fault_addr = bus.laddr; - // DF ビットを立てておくと RTE した後この命令を再実行。 - ssw = bus.ssw | M68K::SSW_DF; + fault_addr = (uint32)bus.laddr; + + // DF は常に立てる必要がある?? + ssw = bus.GetSSW() | M68K::SSW_DF; + if (mmu_enable && (ssw & M68K::FC_DATA) != 0) { + // 命令アクセスなら RB をセット。 + ssw |= M68K::SSW_RB; + } // 例外スタックフレーム $B // SP+$00.W STATUS REGISTER @@ -299,8 +313,8 @@ MPU680x0Device::GenerateExframeB(int vec // 1. バスエラー例外 // MMU による論理アドレスでのバスエラーは (Translate*() が false を返した後) // m68030bus.cpp ルーチンが (C++の) 例外をスローする。 -// 物理アドレス空間アクセス後のバスエラーは (VM側の read*()/write*() が -// (int64)-1 を返した後) m68030bus.cpp ルーチンが (C++) の例外をスローする。 +// 物理アドレス空間アクセス後のバスエラーは (VM側の Read*()/Write*() が +// BusErr を返した後) m68030bus.cpp ルーチンが (C++) の例外をスローする。 // どちらのケースも m68030core.cpp のメインループで catch し、その catch // ブロック内で ExceptionBuserr() を呼び出す。 // @@ -364,14 +378,15 @@ MPU680x0Device::ExceptionReset() // ここは SetSR を使わずに設定する。 reg.s = true; reg.m = false; - bus.SetFC2(reg.s); + fc_inst = busaddr::S | busaddr::Fetch; + fc_data = busaddr::S | busaddr::D; // ここは割り込みレベル変化のチェックは不要でセットだけでいい。 reg.intr_mask = 7; // 4. VBR をクリア reg.vbr = 0; // 5. キャッシュ - reg.cacr = 0; // XXX + SetCACR(0); // 6. キャッシュエントリクリア // 7. TC:E、TTn:E をクリア SetTC(GetTC() & ~m68030TC::TC_E); @@ -498,7 +513,7 @@ MPU680x0Device::ExceptionGeneric(int vec } // ベクタにジャンプ - JumpVector(vector); + JumpVector(vector, false); } catch (int vector2) { assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector=%d", vector); @@ -544,10 +559,11 @@ MPU680x0Device::ExceptionBuserr(int vect // 使えればショートを使うのだが、ここでは全部ロングを使う。 GenerateExframeB(vector, sr); // ベクタにジャンプ - JumpVector(vector); + JumpVector(vector, true); } catch (int vector2) { - // ここに来るのはバスエラーだけのはず - assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector=%d", vector); + // ここに来るのはバスエラーかアドレスエラーだけのはず + assertmsg(vector2 == M68K::EXCEP_BUSERR || + vector2 == M68K::EXCEP_ADDRERR, "vector=%d", vector); // バスエラー・アドレスエラー処理中のバスエラーは // ダブルバスフォールト。 @@ -557,10 +573,11 @@ MPU680x0Device::ExceptionBuserr(int vect // 割り込み例外処理を行う。 // 割り込みの受け付けとレベルのチェック等の後、次命令境界で呼ばれるやつ。 -int +// この処理にかかる時間 [nsec] を返す。 +uint64 MPU680x0Device::ExceptionInterrupt() { - int cycle_start = used_cycle; + uint64 cycle_start = used_cycle; int level = intr_level; // ユーザーズマニュアル(日本語) p.399 図8-5 の中ほど @@ -571,9 +588,18 @@ MPU680x0Device::ExceptionInterrupt() ChangeState(CPU_STATE_NORMAL); // 割り込みアクノリッジサイクルを実行 - int vector = interruptdev->InterruptAcknowledge(level); - if (vector == -1) { - vector = 24 + level; + uint32 vector; + busdata bd = interruptdev->InterruptAcknowledge(level); + if (__predict_false(bd.IsBusErr())) { + // 外部回路がバスエラーを返すと Spurious を発行する。(7.4.1.3) + vector = M68K::EXCEP_SPURIOUS; + } else { + vector = bd.Data(); + if ((int32)vector < 0) { + // オートベクタ要求 (7.4.1.2) + // (負数(-1)ならオートベクタということにしている) + vector = M68K::EXCEP_LEVEL_BASE + level; + } } // 例外履歴に記録 (例外発生はブランチ履歴にも記録) @@ -600,7 +626,7 @@ MPU680x0Device::ExceptionInterrupt() GenerateExframe0(vector, reg.pc, oldsr); // ベクタにジャンプ - JumpVector(vector); + JumpVector(vector, false); } catch (int vector2) { assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector=%d", vector); @@ -608,7 +634,7 @@ MPU680x0Device::ExceptionInterrupt() ExceptionBuserr(vector2); } - return used_cycle - cycle_start; + return (used_cycle - cycle_start) * clock_nsec + bd.GetWait(); } // RTE 命令。