--- nono/m680x0/m68030core.cpp 2026/04/29 17:05:22 1.1.1.10 +++ nono/m680x0/m68030core.cpp 2026/04/29 17:05:26 1.1.1.11 @@ -5,8 +5,10 @@ // #include "mpu680x0.h" +#include "m68030cache.h" #include "debugger.h" #include "interrupt.h" +#include "mainbus.h" #include "scheduler.h" #include "vectortable.h" @@ -26,7 +28,7 @@ MPU680x0Device::ExecShort(Event& ev) ppc = reg.pc; flag_pi = 0; flag_pd = 0; - ir = fetch_16(); + ir = fetch_2(); // uint16 を 6ビット右シフトしたら 1024 以上になるはずは // ないのだが、デフォルトでは gcc/clang どちらも律儀に @@ -41,11 +43,11 @@ MPU680x0Device::ExecShort(Event& ev) #include "m68030switch.h" } - if (__predict_false(icache_enable == false)) { + if (__predict_false(icache->enable == false)) { used_cycle += cycle_nocache; cycle_nocache = 0; } - } catch (int vector) { + } catch (uint vector) { // ここで(C++の)例外スローをキャッチするのは // - メモリ空間をアクセスした先でのバスエラー例外 // - EA パース中の不当命令例外 @@ -124,12 +126,123 @@ MPU680x0Device::SetSR(uint16 data) } // FC2-0 - fc_inst.Set(0, busaddr::Fetch, reg.s); - fc_data.Set(0, busaddr::D, reg.s); + fc_inst = BusAddr::Fetch | busaddr::SU(reg.s); + fc_data = BusAddr::D | busaddr::SU(reg.s); // XXX 他に何か状態変えないといけないことあったっけか。 } +// CACR レジスタ書き込み +void +MPU680x0Device::SetCACR(uint32 newval) +{ + newval &= M68K::CACR_MASK; + uint32 oldval = reg.cacr; + uint32 chgval = oldval ^ newval; + + // EI (命令キャッシュ有効) + if ((chgval & M68K::CACR_EI) != 0) { + if ((newval & M68K::CACR_EI) != 0) { + // 命令キャッシュ有効 + icache->enable = true; + icache->hist.Clear(); + putlog(1, "I-Cache enabled"); + } else { + // 命令キャッシュ無効 + icache->enable = false; + putlog(1, "I-Cache disabled"); + // 命令キャッシュが有効だった期間 nocache は使われずに + // 積算され続けているが、キャッシュ無効になるとこれを加算 + // しようとするのでここでリセット。 + cycle_nocache = 0; + } + } + + // FI (命令キャッシュ凍結) + if ((chgval & M68K::CACR_FI) != 0) { + putlog(0, "CACR:FI Not Implemented"); + icache->freeze = (newval & M68K::CACR_FI); + } + + // CEI (命令キャッシュの指定エントリをクリア) + if ((chgval & M68K::CACR_CEI) != 0) { + // CAAR の b7-2 で示されるロングワードを無効にする。 + uint32 idx = (reg.caar & 0x000000f0) >> 4; + uint32 sel = (reg.caar & 0x0000000c) >> 2; + auto& l = icache->line[idx]; + l.valid[sel] = 0; + + newval &= ~M68K::CACR_CEI; + } + + // CI (命令キャッシュクリア) + if ((chgval & M68K::CACR_CI) != 0) { + for (auto& l : icache->line) { + l.valid_all = 0; + } + + newval &= ~M68K::CACR_CI; + } + + // IBE (命令バースト有効) + if ((chgval & M68K::CACR_IBE) != 0) { + icache->burst_enable = (newval & M68K::CACR_IBE) && has_burst_access; + } + + // ED (データキャッシュ有効) + if ((chgval & M68K::CACR_ED) != 0) { + if ((newval & M68K::CACR_ED) != 0) { + // データキャッシュ有効。 + dcache->enable = true; + dcache->hist.Clear(); + putlog(1, "D-Cache enabled"); + } else { + // データキャッシュ無効。 + dcache->enable = false; + putlog(1, "D-Cache disabled"); + } + } + + // FD (データキャッシュ凍結) + if ((chgval & M68K::CACR_FD) != 0) { + dcache->freeze = (newval & M68K::CACR_FD); + putlog(1, "CACR:FD -> %u", dcache->freeze); + } + + // CED (データキャッシュの指定エントリをクリア) + if ((chgval & M68K::CACR_CED) != 0) { + // CAAR の b7-2 で示されるロングワードを無効にする。 + uint32 idx = (reg.caar & 0x000000f0) >> 4; + uint32 sel = (reg.caar & 0x0000000c) >> 2; + auto& l = dcache->line[idx]; + l.valid[sel] = 0; + + newval &= ~M68K::CACR_CED; + } + + // CD (データキャッシュクリア) + if ((chgval & M68K::CACR_CD) != 0) { + for (auto& l : dcache->line) { + l.valid_all = 0; + } + + newval &= ~M68K::CACR_CD; + } + + // DBE (データバースト有効) + if ((chgval & M68K::CACR_DBE) != 0) { + dcache->burst_enable = (newval & M68K::CACR_DBE) && has_burst_access; + } + + // WA (ライトアロケート) + if ((chgval & M68K::CACR_WA) != 0) { + dcache->wa = (newval & M68K::CACR_WA); + } + + // とりあえずレジスタイメージも保存。 + reg.cacr = newval; +} + // 命令中に (An)+ で変化したアドレスレジスタを命令実行前の状態に巻き戻す。 // flag_pi は bit7..0 が save_pi[7..0] の A7..A0 に対応している。 void @@ -158,14 +271,13 @@ MPU680x0Device::restore_reg_pd() // vector にジャンプする。vector はベクタ番号(アドレスではない)。 void -MPU680x0Device::JumpVector(int vector, bool from_buserr) +MPU680x0Device::JumpVector(uint vector, bool from_buserr) { uint32 vecaddr; uint32 newpc; vecaddr = reg.vbr + vector * 4; - reg.pc = vecaddr; - newpc = fetch_32(); + newpc = read_4(vecaddr); // VBR 込みのジャンプ先が確定したところで今度はブランチ履歴に記録。 // この時のブランチ元はベクタアドレス // (reg.pc は fetch によって進んでしまうので先に保存) @@ -189,7 +301,7 @@ MPU680x0Device::JumpVector(int vector, b // なるケースはここでバスエラーが出なければいけないが、まだ // キャッシュを実装していないので、ここで1ワードフェッチしてみて // PC を戻すあほっぽい方法を取る。 - fetch_16(); + fetch_2(); reg.pc -= 2; } @@ -199,23 +311,23 @@ MPU680x0Device::JumpVector(int vector, b // 次の命令位置かが異なる)。 // sr は例外発生時の SR。 inline void -MPU680x0Device::GenerateExframe0(int vector, uint32 pc, uint16 sr) +MPU680x0Device::GenerateExframe0(uint vector, uint32 pc, uint16 sr) { // 例外スタックフレーム $0 // SP+$00.W STATUS REGISTER // +$02.L PROGRAM COUNTER ; 例外ごとに異なる // +$06.W %0000 | VECTOR - push_16((0 << 12) | (vector * 4)); - push_32(pc); - push_16(sr); + push_2((0 << 12) | (vector << 2)); + push_4(pc); + push_2(sr); } // 例外スタックフレーム $2 を生成する。 // vector はベクタ番号。 // スタックに積む PC は常に次の命令。 inline void -MPU680x0Device::GenerateExframe2(int vector, uint16 sr) +MPU680x0Device::GenerateExframe2(uint vector, uint16 sr) { // 例外スタックフレーム $2 // SP+$00.W STATUS REGISTER @@ -223,15 +335,15 @@ MPU680x0Device::GenerateExframe2(int vec // +$06.W %0010 | VECTOR // +$08.L INSTRUCTION ADDRESS ; 例外を起こした命令のアドレス - push_32(ppc); // 例外を起こした命令のアドレス - push_16((2 << 12) | (vector * 4)); - push_32(reg.pc); // 次の命令位置 - push_16(sr); + push_4(ppc); // 例外を起こした命令のアドレス + push_2((2 << 12) | (vector << 2)); + push_4(reg.pc); // 次の命令位置 + push_2(sr); } // 例外スタックフレーム $B を生成する。 inline void -MPU680x0Device::GenerateExframeB(int vector, uint16 sr) +MPU680x0Device::GenerateExframeB(uint vector, uint16 sr) { uint16 ssw; uint32 fault_addr; @@ -239,7 +351,7 @@ MPU680x0Device::GenerateExframeB(int vec stageBaddr = reg.pc + 2; // この後のスタック操作で bus が変化する前に保存 - fault_addr = (uint32)bus.laddr; + fault_addr = bus.laddr.Addr(); // DF は常に立てる必要がある?? ssw = bus.GetSSW() | M68K::SSW_DF; @@ -281,28 +393,28 @@ MPU680x0Device::GenerateExframeB(int vec // 一方、ポストインクリメントのケースはこの少し下の // ExceptionBuserr() 内のコメント参照。 for (int i = 7; i >= 0; i--) { - push_32(save_pd[i]); + push_4(save_pd[i]); } - push_16(flag_pd); + push_2(flag_pd); reg.A[7] -= 2; reg.A[7] -= 2; // VERSION# reg.A[7] -= 6; - push_32(0); // DATA INPUT BUFFER + push_4(0); // DATA INPUT BUFFER reg.A[7] -= 4; - push_32(stageBaddr); // STAGE B ADDRESS + push_4(stageBaddr); // STAGE B ADDRESS reg.A[7] -= 8; - push_32(0); // DATA OUTPUT BUFFER + push_4(0); // DATA OUTPUT BUFFER reg.A[7] -= 4; - push_32(fault_addr); // DATA CYCLE FAULT ADDRESS - push_16(0); // INSTRUCTION PIPE STAGE B - push_16(0); // INSTRUCTION PIPE STAGE C - push_16(ssw); + push_4(fault_addr); // DATA CYCLE FAULT ADDRESS + push_2(0); // INSTRUCTION PIPE STAGE B + push_2(0); // INSTRUCTION PIPE STAGE C + push_2(ssw); reg.A[7] -= 2; - push_16(0xb000 | (vector << 2)); + push_2(0xb000 | (vector << 2)); // 本当は現在の PC だが、再実行のため PPC を積む。 - push_32(ppc); // PC - push_16(sr); // 例外入り口で保存した SR + push_4(ppc); // PC + push_2(sr); // 例外入り口で保存した SR } // 例外処理について。 @@ -359,6 +471,7 @@ MPU680x0Device::ExceptionReset() // m68k では今の所リセット例外発生時の PC にはあまり意味がないけど、 // 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); // デバッガに通知 (例外ブレーク用)。こっちのベクタは 0 のままでよい。 @@ -378,16 +491,21 @@ MPU680x0Device::ExceptionReset() // ここは SetSR を使わずに設定する。 reg.s = true; reg.m = false; - fc_inst = busaddr::S | busaddr::Fetch; - fc_data = busaddr::S | busaddr::D; + fc_inst = BusAddr::S | BusAddr::Fetch; + fc_data = BusAddr::S | BusAddr::D; // ここは割り込みレベル変化のチェックは不要でセットだけでいい。 reg.intr_mask = 7; // 4. VBR をクリア reg.vbr = 0; - // 5. キャッシュ - SetCACR(0); - // 6. キャッシュエントリクリア + + // 5. キャッシュの EI|ED, FI|FD, IBE|DBE, WA をクリア + // 6. キャッシュエントリをすべてクリア (CI|CD) + SetCACR(M68K::CACR_CD | M68K::CACR_CI); + cycle_nocache = 0; + icache->hist.Clear(); + dcache->hist.Clear(); + // 7. TC:E、TTn:E をクリア SetTC(GetTC() & ~m68030TC::TC_E); SetTT(0, GetTT(0) & ~m68030TT::E); @@ -398,14 +516,14 @@ MPU680x0Device::ExceptionReset() // 10. PC をロード try { reg.pc = 0; - reg.A[7] = fetch_32(); - uint32 pc = fetch_32(); - // 大丈夫のはずだけど fetch_32() が reg.pc を書き換えるので一応 + reg.A[7] = fetch_4(); + uint32 pc = fetch_4(); + // 大丈夫のはずだけど fetch_4() が reg.pc を書き換えるので一応 reg.pc = pc; // リセットベクタは常に 0, 4 番地から取得したことになっている uint32 inst = BranchHistory_m680x0::VectorJump; brhist.AddEntry(0x00000004 | 1, reg.pc, inst); - } catch (int) { + } catch (uint) { DoubleBusFault("reset exception"); } @@ -426,7 +544,7 @@ MPU680x0Device::ExceptionReset() // o TRAP#15 例外は ExceptionTrap15() // o バスエラー・アドレスエラーは ExceptionBuserr() void -MPU680x0Device::Exception(int vector) +MPU680x0Device::Exception(uint vector) { uint32 inst = BranchHistory_m680x0::Exception | vector; ExceptionGeneric(vector, inst); @@ -455,9 +573,9 @@ MPU680x0Device::ExceptionTrap15() // 今の所 68030/MMU有り しかサポートしていないので。 // だめならまた考える。 - const int vector = M68K::EXCEP_TRAP15; + const uint vector = M68K::EXCEP_TRAP15; uint32 inst; - if (mainbus->Peek8(0xcbc) == 0x03 && mainbus->Peek8(0xcbe) == 0xff) { + if (mainbus->Peek1(0xcbc) == 0x03 && mainbus->Peek1(0xcbe) == 0xff) { // IOCS コールっぽい inst = BranchHistory_m680x0::IOCSCall | (reg.D[0] & 0xff); } else { @@ -469,9 +587,10 @@ MPU680x0Device::ExceptionTrap15() // 汎用の例外処理本体。 void -MPU680x0Device::ExceptionGeneric(int vector, uint32 inst) +MPU680x0Device::ExceptionGeneric(uint vector, uint32 inst) { // 例外履歴に記録 (例外発生はブランチ履歴にも記録) + excep_counter[vector]++; uint32 from = ppc | (IsSuper() ? 1 : 0); exhist.AddEntry(from, 0, inst); brhist.AddEntry(from, 0, inst); @@ -508,14 +627,14 @@ MPU680x0Device::ExceptionGeneric(int vec break; default: - PANIC("$%08x exception vector %d ?", ppc, vector); + PANIC("$%08x exception vector %u ?", ppc, vector); break; } // ベクタにジャンプ JumpVector(vector, false); - } catch (int vector2) { - assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector=%d", vector); + } catch (uint vector2) { + assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector=%u", vector); // バスエラー処理へ ExceptionBuserr(vector2); @@ -525,12 +644,13 @@ MPU680x0Device::ExceptionGeneric(int vec // バスエラー・アドレスエラー例外処理を行う。 // 他の例外とは違いが多いので分けた。 void -MPU680x0Device::ExceptionBuserr(int vector) +MPU680x0Device::ExceptionBuserr(uint vector) { assertmsg((vector == M68K::EXCEP_BUSERR || vector == M68K::EXCEP_ADDRERR), - "vector=%d", vector); + "vector=%u", vector); // 例外履歴に記録 (例外発生はブランチ履歴にも記録) + excep_counter[vector]++; uint32 from = ppc | (IsSuper() ? 1 : 0); uint32 inst = BranchHistory_m680x0::Exception | vector; exhist.AddEntry(from, 0, inst); @@ -560,10 +680,10 @@ MPU680x0Device::ExceptionBuserr(int vect GenerateExframeB(vector, sr); // ベクタにジャンプ JumpVector(vector, true); - } catch (int vector2) { + } catch (uint vector2) { // ここに来るのはバスエラーかアドレスエラーだけのはず assertmsg(vector2 == M68K::EXCEP_BUSERR || - vector2 == M68K::EXCEP_ADDRERR, "vector=%d", vector); + vector2 == M68K::EXCEP_ADDRERR, "vector=%u", vector); // バスエラー・アドレスエラー処理中のバスエラーは // ダブルバスフォールト。 @@ -578,7 +698,7 @@ uint64 MPU680x0Device::ExceptionInterrupt() { uint64 cycle_start = used_cycle; - int level = intr_level; + uint level = intr_level; // ユーザーズマニュアル(日本語) p.399 図8-5 の中ほど // 「/IPEND をネゲート、割り込みアクノリッジサイクルを実行」 @@ -603,6 +723,7 @@ MPU680x0Device::ExceptionInterrupt() } // 例外履歴に記録 (例外発生はブランチ履歴にも記録) + excep_counter[vector]++; uint32 from = ppc | (IsSuper() ? 1 : 0); uint32 inst = BranchHistory_m680x0::Exception | vector; exhist.AddEntry(from, 0, inst); @@ -627,8 +748,8 @@ MPU680x0Device::ExceptionInterrupt() // ベクタにジャンプ JumpVector(vector, false); - } catch (int vector2) { - assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector=%d", vector); + } catch (uint vector2) { + assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector=%u", vector); // バスエラー処理へ ExceptionBuserr(vector2); @@ -647,9 +768,9 @@ MPU680x0Device::ops_rte() uint16 frame; try { - sr = pop_16(); - pc = pop_32(); - frame = pop_16(); + sr = pop_2(); + pc = pop_4(); + frame = pop_2(); switch (frame >> 12) { case 0: CYCLE2(18, 20); @@ -672,14 +793,14 @@ MPU680x0Device::ops_rte() CYCLE(76); reg.A[7] += 2; // $08.W - ssw = pop_16(); // $0a.W SSW + ssw = pop_2(); // $0a.W SSW reg.A[7] += 4 * 6; // $0c.L*6 - stage_b = pop_32(); // $24.L Stage B + stage_b = pop_4(); // $24.L Stage B reg.A[7] += 2 * 9; // $28.W*9 // $3a..$58 ここが save_pd の取り出し - flag_pd = pop_16(); + flag_pd = pop_2(); for (int i = 0; i < 8; i++) { - save_pd[i] = pop_32(); + save_pd[i] = pop_4(); } // A7 レジスタをリストアするかもしれない前に Super/User を // 復帰しておかないといけない @@ -702,8 +823,8 @@ MPU680x0Device::ops_rte() PANIC("RTE frame=$%x not supported", frame >> 12); break; } - } catch (int vector2) { - assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector2=%d", vector2); + } catch (uint vector2) { + assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector2=%u", vector2); // RTE 処理中のバスエラーはダブルバスフォールト。 DoubleBusFault("bus/address error handling"); @@ -714,7 +835,7 @@ MPU680x0Device::ops_rte() void MPU680x0Device::ops_stop() { - uint32 data = fetch_16(); + uint32 data = fetch_2(); SetSR(data); ChangeState(CPU_STATE_STOP);