--- nono/m680x0/m68030mmu.cpp 2026/04/29 17:05:26 1.1.1.10 +++ nono/m680x0/m68030mmu.cpp 2026/04/29 17:05:48 1.1.1.14 @@ -78,7 +78,7 @@ indent_format(int indent, const char *fm class m68030MMU final { public: - m68030MMU(MPU680x0Device *, int loglevel_); + m68030MMU(MPU68030Device *, int loglevel_); ~m68030MMU(); // サーチを実行 @@ -97,12 +97,6 @@ class m68030MMU final // ディスクリプタを取得 bool fetch_desc(uint32, int); - // MMU による物理メモリ読み込み - busdata phys_read_4(uint32 addr); - - // MMU による物理メモリ書き込み - busdata phys_write_4(uint32 addr, uint32 data); - // ディスクリプタを表示用に (デバッグ用) std::string sprintf_desc(); @@ -133,13 +127,13 @@ class m68030MMU final int loglevel {}; - MPU680x0Device *cpu; + MPU68030Device *cpu; }; // 現在の TC:E、TT:E の状態に応じてアドレス変換の有無を切り替える。 // mmu_enable ならアドレス変換ありのバスアクセスを使う。see m68030bus.cpp void -MPU680x0Device::mmu_enable_changed() +MPU68030Device::mmu_enable_changed() { bool enable; @@ -164,7 +158,7 @@ MPU680x0Device::mmu_enable_changed() // bool -MPU680x0Device::SetSRP(uint32 h, uint32 l) +MPU68030Device::SetSRP(uint32 h, uint32 l) { if ((h & m68030RP::DT_MASK) == 0) { return false; @@ -175,7 +169,7 @@ MPU680x0Device::SetSRP(uint32 h, uint32 } bool -MPU680x0Device::SetCRP(uint32 h, uint32 l) +MPU68030Device::SetCRP(uint32 h, uint32 l) { if ((h & m68030RP::DT_MASK) == 0) { return false; @@ -186,7 +180,7 @@ MPU680x0Device::SetCRP(uint32 h, uint32 } void -MPU680x0Device::SetTT(int n, uint32 data) +MPU68030Device::SetTT(int n, uint32 data) { uint32 lbase; uint32 lmask; @@ -197,7 +191,7 @@ MPU680x0Device::SetTT(int n, uint32 data if (mmu_tt[n].e) { // 変更前の TT#n にマッチして、現在の TT#(1-n) にマッチしない // アドレスブロックに対応する 4096 エントリをクリア。 - for (int fc = 0; fc < 8; fc++) { + for (int fc = 1; fc <= 6; fc++) { auto *table = atc.fctables[fc]; if (table) { busaddr laddr = busaddr(0) | busaddr::FC(fc); @@ -268,7 +262,7 @@ MPU680x0Device::SetTT(int n, uint32 data sbase |= (data & m68030TT::FCBASE_MASK) >> 3; smask = m68030TT::E; if ((data & m68030TT::RWM) == 0) { - smask |= M68K::SSW_RW; + smask |= M68030::SSW_RW; } smask |= (~data & m68030TT::FCMASK_MASK) << 1; @@ -279,7 +273,7 @@ MPU680x0Device::SetTT(int n, uint32 data if (mmu_tt[n].e) { // この TT#n にマッチするアドレスブロックに対応する 4096 エントリを // TT 印にする。 - for (uint fc = 0; fc < 8; fc++) { + for (uint fc = 1; fc <= 6; fc++) { auto *table = atc.fctables[fc]; if (table) { busaddr laddr = busaddr(0) | busaddr::FC(fc); @@ -314,7 +308,7 @@ m68030TT::Match(busaddr laddr) const // 成功すれば true、MMU 構成例外が起きる場合は false を返す。 // 呼び出し側で例外を起こすこと。 bool -MPU680x0Device::SetTC(uint32 data) +MPU68030Device::SetTC(uint32 data) { // マスクしてレジスタイメージにセット reg.tc = data & m68030TC::MASK; @@ -345,7 +339,6 @@ MPU680x0Device::SetTC(uint32 data) // TC:E が変更されていればスイッチ更新 mmu_enable_changed(); return true; - } // TC レジスタへの書き込み値を m68030TC クラスにセットする。 @@ -398,9 +391,9 @@ m68030TC::MakeMask() // +--------+--------+--------+--------+ // lmask = 00000000 11111111 11100000 00000000 // pgmask = 00000000 00000000 00011111 11111111 - lmask = (1 << (tia + tib + tic + tid)) - 1; + lmask = (1U << (tia + tib + tic + tid)) - 1; lmask <<= ps; - pgmask = (1 << ps) - 1; + pgmask = (1U << ps) - 1; // アドレスを (IS,) TIA 〜 TID に分解。 // @@ -417,28 +410,37 @@ m68030TC::MakeMask() for (int i = TID; i >= TIA; i--) { if (tix[i] > 0) { shift[i] = sh; - mask[i] = (1 << tix[i]) - 1; + mask[i] = (1U << tix[i]) - 1; sh += tix[i]; } } } void -MPU680x0Device::SetMMUSR(uint16 data) +MPU68030Device::SetMMUSR(uint16 data) { reg.mmusr = data & m68030MMUSR::MASK; } +// リセット例外の CPU 固有部分。 +void +MPU68030Device::ResetMMU() +{ + SetTC(GetTC() & ~m68030TC::TC_E); + SetTT(0, GetTT(0) & ~m68030TT::E); + SetTT(1, GetTT(1) & ~m68030TT::E); +} + // // ATC // // 今となっては独立したクラスである必要はなくなっているが、これを -// MPU680x0Device にマージするとパフォーマンスが下がるので維持してある。 +// MPU68030Device にマージするとパフォーマンスが下がるので維持してある。 // // コンストラクタ -m68030ATC::m68030ATC(MPU680x0Device *cpu_) +m68030ATC::m68030ATC(MPU68030Device *cpu_) { cpu = cpu_; @@ -485,7 +487,7 @@ m68030ATC::flush() void m68030ATC::flush(uint32 fc, uint32 mask) { - for (uint i = 0; i < 8; i++) { + for (uint i = 1; i <= 6; i++) { if (((i ^ fc) & mask) == 0) { // FC が一致したテーブルを全フラッシュ auto *table = fctables[i]; @@ -501,7 +503,7 @@ m68030ATC::flush(uint32 fc, uint32 mask) void m68030ATC::flush(uint32 fc, uint32 mask, uint32 addr) { - for (uint i = 0; i < 8; i++) { + for (uint i = 1; i <= 6; i++) { if (((i ^ fc) & mask) == 0) { // FC が一致したテーブルから addr が一致したエントリをフラッシュ auto *table = fctables[i]; @@ -559,7 +561,7 @@ m68030ATC::flush(uint32 fc, uint32 mask, // フラッシュが起きるんじゃないかな… // コンストラクタ -m68030ATCTable::m68030ATCTable(MPU680x0Device *cpu_, uint fc_) +m68030ATCTable::m68030ATCTable(MPU68030Device *cpu_, uint fc_) { cpu = cpu_; fc = fc_; @@ -581,7 +583,9 @@ m68030ATCTable::Flush() { for (int i = 0; i < LINES; i++) { Invalidate(&line[i]); + line[i].age = 0; } + latest_age = 0; } // この ATC テーブルから addr が一致するエントリをすべてフラッシュする。 @@ -601,6 +605,14 @@ inline void m68030ATCTable::MoveHead(m68030ATCLine *a) { a->age = ++latest_age; + + if (__predict_false(a->age == 0)) { + // latest_age が1周したので、一旦全部リセット。 + for (int i = 0; i < LINES; i++) { + line[i].age = 0; + } + a->age = ++latest_age; + } } // このテーブルのうち最も古い要素を差し出す。 @@ -614,8 +626,7 @@ m68030ATCTable::RemoveTail() // 最後に使われたの (あるいは空き) を探す。 for (int i = 0; i < LINES; i++) { if (line[i].IsInvalid()) { - a = &line[i]; - break; + return &line[i]; } if (line[i].age < min) { min = line[i].age; @@ -634,7 +645,7 @@ m68030ATCTable::RemoveTail() // a からハッシュを作成する。 void -m68030ATCTable::MakeHash(m68030ATCLine *a) +m68030ATCTable::MakeHash(const m68030ATCLine *a) { uint32 addr4k = a->GetLAddr() >> 12; int idx = a - &line[0]; @@ -642,7 +653,7 @@ m68030ATCTable::MakeHash(m68030ATCLine * if (__predict_true(ps4k == 0)) { hash[addr4k] = idx; } else if (ps4k > 0) { - for (int i = 0; i < (1 << ps4k); i++) { + for (int i = 0; i < (1U << ps4k); i++) { hash[addr4k + i] = idx; } } else { @@ -760,7 +771,7 @@ m68030ATCTable::LineToStr(const m68030AT // // コンストラクタ -m68030MMU::m68030MMU(MPU680x0Device *cpu_, int loglevel_) +m68030MMU::m68030MMU(MPU68030Device *cpu_, int loglevel_) { cpu = cpu_; loglevel = loglevel_; @@ -834,7 +845,7 @@ m68030MMU::search(int level, busaddr lad // ここから図9-25。 // 使用するルートポインタを決定 - if (cpu->mmu_tc.sre && is_super) { + if (__predict_true(cpu->mmu_tc.sre) && is_super) { rpname = "SRP"; m_desc1 = cpu->GetSRPh(); m_desc2 = cpu->GetSRPl(); @@ -847,26 +858,23 @@ m68030MMU::search(int level, busaddr lad // ルートポインタの DT をチェック dt = GET_DT(m_desc1); MMULOG(3, 2, "%s: %s dt=%s", lam_func, rpname, dtname(dt)); - switch (dt) { - case DT_INVALID: - // 無効は設定できないはずなので、ここに来ないはず - PANIC("%s.DT==Invalid", rpname); - break; - - case DT_PAGE: // ページディスクリプタ + if (__predict_true(dt == DT_VALID4)) { + // 有効 4 バイト。基本的にはこれしか使われないので優先。 + m_descsize = 4; + m_lastsize = 8; + } else if (dt == DT_VALID8) { // 有効 (8バイト) + m_descsize = 8; + m_lastsize = 8; + } else if (dt == DT_PAGE) { // ページディスクリプタ m_type = EARLY; return; - - case DT_VALID4: // 有効(4バイト) - case DT_VALID8: // 有効(8バイト) - // descsize は DT=$2 なら 4、DT=$3 なら 8 になる - m_descsize = 1 << dt; - m_lastsize = 8; - break; + } else { + // 無効は設定できないはずなので、ここには来ないはず。 + PANIC("%s.DT==Invalid", rpname); } // 必要ならファンクションコード・ルックアップ - if (cpu->mmu_tc.fcl) { + if (__predict_false(cpu->mmu_tc.fcl)) { x = FCL; // たぶん検索レベルを1つ消費するはず。未確認。 level--; @@ -893,7 +901,7 @@ m68030MMU::search(int level, busaddr lad case DT_VALID4: // 有効4バイト case DT_VALID8: // 有効8バイト m_lastsize = m_descsize; - m_descsize = 1 << dt; + m_descsize = 1U << dt; break; } } @@ -902,7 +910,7 @@ m68030MMU::search(int level, busaddr lad for (x = TIA; x < level; x++) { // リミットチェック - if (m_lastsize == 8 && limitcheck() == false) { + if (__predict_false(m_lastsize == 8) && limitcheck() == false) { m_type = INVALID; m_lim = true; return; @@ -942,9 +950,9 @@ m68030MMU::search(int level, busaddr lad case DT_VALID4: // 有効4バイト case DT_VALID8: // 有効8バイト m_lastsize = m_descsize; - m_descsize = 1 << dt; + m_descsize = 1U << dt; - if (x == TID || cpu->mmu_tc.tix[x + 1] == 0) { + if (__predict_false(x == TID || cpu->mmu_tc.tix[x + 1] == 0)) { // 間接 m_type = INDIRECT; @@ -1020,7 +1028,7 @@ m68030MMU::fetch_desc(uint32 tableaddr, m_berr = false; // ディスクリプタを取得 - if (m_debugger) { + if (__predict_false(m_debugger)) { // デバッガアクセス uint64 data; data = cpu->mainbus->Peek4(descaddr); @@ -1039,14 +1047,14 @@ m68030MMU::fetch_desc(uint32 tableaddr, } else { busdata bd; - bd = phys_read_4(descaddr); - if (bd.IsBusErr()) { + bd = cpu->read_phys_4(descaddr); + if (__predict_false(bd.IsBusErr())) { goto buserr; } m_desc1 = bd.Data(); - if (m_descsize == 8) { - bd = phys_read_4(descaddr + 4); + if (__predict_false(m_descsize == 8)) { + bd = cpu->read_phys_4(descaddr + 4); if (bd.IsBusErr()) { goto buserr; } @@ -1085,17 +1093,20 @@ m68030MMU::fetch_desc(uint32 tableaddr, // U ビットを更新 UPDATE_DESC(MMU_DESC_U); break; + + default: + __unreachable(); } // デバッガ自身がアドレス変換を実施している時は書き込みは行わない - if (m_debugger) { + if (__predict_false(m_debugger)) { do_write = false; } // ライトライクルの実行 if (do_write) { - busdata bd = phys_write_4(descaddr, m_desc1); - if (bd.IsBusErr()) { + busdata bd = cpu->write_phys_4(descaddr, m_desc1); + if (__predict_false(bd.IsBusErr())) { goto buserr; } // バス動作正常終了 @@ -1215,54 +1226,6 @@ m68030MMU::make_atc_debugger() const return paddr; } -// 物理メモリからの読み込み。 -busdata -m68030MMU::phys_read_4(uint32 addr) -{ - m68kbus backup; - busdata bd; - - // バス情報を一旦退避 - backup = cpu->bus; - - // 物理バスアクセス - cpu->bus.laddr = busaddr(addr) | BusAddr::SRead | BusAddr::Size4; - cpu->bus.paddr = cpu->bus.laddr; - bd = cpu->read_phys(); - if (__predict_false(bd.IsBusErr())) { - cpu->bus.size = M68K::SSW_SIZE_LONG; - return bd; - } - - // バス情報を復元 - cpu->bus = backup; - return bd; -} - -// 物理メモリへの書き込み。 -busdata -m68030MMU::phys_write_4(uint32 addr, uint32 data) -{ - m68kbus backup; - busdata bd; - - // バス情報を一旦退避 - backup = cpu->bus; - - // 物理バスアクセス - cpu->bus.laddr = busaddr(addr) | BusAddr::SWrite | BusAddr::Size4; - cpu->bus.paddr = cpu->bus.laddr; - bd = cpu->write_phys(data); - if (__predict_false(bd.IsBusErr())) { - cpu->bus.size = M68K::SSW_SIZE_LONG; - return bd; - } - - // バス情報を復元 - cpu->bus = backup; - return bd; -} - // ディスクリプタ表示用の文字列を返す。 // m_descsize によって m_desc1, m_desc2 を適切に文字列にする。 std::string @@ -1320,7 +1283,7 @@ const char * const m68030MMU::m_lvname[M // 論理アドレスが TT0/TT1 どちらかと一致すれば (bus.ci を更新して) true を返す。 // 一致しなければ false を返す。 bool -MPU680x0Device::CheckTT() +MPU68030Device::CheckTT() { bool ci; int match; @@ -1351,7 +1314,7 @@ MPU680x0Device::CheckTT() // リード/フェッチ用のアドレス変換を行う。 // 変換できれば true、バスエラーなら false を返す。 bool -MPU680x0Device::TranslateRead() +MPU68030Device::TranslateRead() { m68030ATCLine *a; busaddr& laddr = bus.laddr; @@ -1365,41 +1328,34 @@ MPU680x0Device::TranslateRead() IsSuper() ? 'S' : 'U', ppc); - m68030ATCTable *table = atc.fctables[fc]; uint8 n = table->hash[addr >> 12]; if (__predict_true((int8)n >= 0)) { // ATC #(n) table->atcstat.total++; a = &table->line[n]; - } else { - if (n == m68030ATCTable::HASH_NONE) { - if (__predict_true(mmu_tc.e)) { - // TC.E 有効で対応なしなら、テーブルサーチ。 - table->atcstat.total++; - table->atcstat.miss++; - a = table->MMUSearch(laddr); - } else { - // TC.E 無効。(total もカウントしない) - return true; - } - } else if (n == m68030ATCTable::HASH_TT) { - // TT。CheckTT で外れたかどうかはカウントしない。ほぼ 0 なので。 + } else if (n == m68030ATCTable::HASH_NONE) { + if (__predict_true(mmu_tc.e)) { + // TC.E 有効で対応なしなら、テーブルサーチ。 table->atcstat.total++; - table->atcstat.tthit++; - if (__predict_true(CheckTT())) { - return true; - } else { - return false; - } + table->atcstat.miss++; + a = table->MMUSearch(laddr); } else { - // PS<4KB でマッチしたので再検査。 - table->atcstat.total++; - a = table->FindSub(laddr); - if (a == NULL) { - table->atcstat.miss++; - a = table->MMUSearch(laddr); - } + // TC.E 無効。(total もカウントしない) + return true; + } + } else if (n == m68030ATCTable::HASH_TT) { + // TT。CheckTT で外れたかどうかはカウントしない。ほぼ 0 なので。 + table->atcstat.total++; + table->atcstat.tthit++; + return CheckTT(); + } else { + // PS<4KB でマッチしたので再検査。 + table->atcstat.total++; + a = table->FindSub(laddr); + if (a == NULL) { + table->atcstat.miss++; + a = table->MMUSearch(laddr); } } @@ -1417,7 +1373,7 @@ MPU680x0Device::TranslateRead() // ライト用のアドレス変換を行う。 // 変換できれば true、バスエラーなら false を返す。 bool -MPU680x0Device::TranslateWrite() +MPU68030Device::TranslateWrite() { m68030ATCLine *a; busaddr& laddr = bus.laddr; @@ -1437,37 +1393,39 @@ MPU680x0Device::TranslateWrite() // ATC #(n) table->atcstat.total++; a = &table->line[n]; - } else { - if (n == m68030ATCTable::HASH_NONE) { - if (__predict_true(mmu_tc.e)) { - // TC.E 有効で対応なしなら、テーブルサーチ。 - table->atcstat.total++; - table->atcstat.miss++; - a = table->MMUSearch(laddr); - } else { - // TC.E 無効。(total もカウントしない) - return true; - } - } else if (n == m68030ATCTable::HASH_TT) { - // TT。CheckTT で外れたかどうかはカウントしない。ほぼ 0 なので。 + } else if (n == m68030ATCTable::HASH_NONE) { + if (__predict_true(mmu_tc.e)) { + // TC.E 有効で対応なしなら、テーブルサーチ。 table->atcstat.total++; - table->atcstat.tthit++; - if (__predict_true(CheckTT())) { - return true; - } else { - return false; - } + goto tablesearch; } else { - // PS<4KB でマッチしたので再検査。 - table->atcstat.total++; - a = table->FindSub(laddr); - if (a == NULL) { - table->atcstat.miss++; - a = table->MMUSearch(laddr); - } + // TC.E 無効。(total もカウントしない) + return true; + } + } else if (n == m68030ATCTable::HASH_TT) { + // TT。CheckTT で外れたかどうかはカウントしない。ほぼ 0 なので。 + table->atcstat.total++; + table->atcstat.tthit++; + return CheckTT(); + } else { + // PS<4KB でマッチしたので再検査。 + table->atcstat.total++; + a = table->FindSub(laddr); + if (a == NULL) { + goto tablesearch; } } + // ライトアクセスなので、WP でなく Modified == 0 なら + // Modified を立てるため、このエントリを破棄して改めて + // テーブルサーチを実行する。 + if (a->IsWProtect() == false && a->IsModified() == false) { + table->Invalidate(a); + tablesearch: + table->atcstat.miss++; + a = table->MMUSearch(laddr); + } + // ATC a でマッチした table->MoveHead(a); @@ -1490,7 +1448,7 @@ MPU680x0Device::TranslateWrite() // 変換できれば対応する物理アドレスを、バスエラーなら BusErr を返す。 // テーブルサーチを行ったら TableSearched ビットを立てる。 busaddr -MPU680x0Device::TranslatePeek(busaddr laddr) +MPU68030Device::TranslatePeek(busaddr laddr) { const m68030ATCLine *a; busaddr paddr; @@ -1498,74 +1456,71 @@ MPU680x0Device::TranslatePeek(busaddr la uint32 fc = laddr.GetFC(); // 状態表示 - putlog(3, "%s: enter %c:$%08x", __func__, + putlog(5, "%s: enter %c:$%08x", __func__, (laddr.IsSuper() ? 'S' : 'U'), addr); m68030ATCTable *table = atc.fctables[fc]; uint8 n = table->hash[addr >> 12]; + // PS<4KB のケースを先に解決する。 + if (__predict_false(n == m68030ATCTable::HASH_SUB)) { + a = table->FindSub(laddr); + if (a) { + n = a - &table->line[0]; + } else { + n = m68030ATCTable::HASH_NONE; + } + } if (__predict_true((int8)n >= 0)) { // ATC #(n) a = &table->line[n]; - atc_found: paddr = busaddr(a->GetPAddr()); paddr |= addr & mmu_tc.pgmask; - putlog(3, "%s: result $%08x (match atc)", __func__, paddr.Addr()); + putlog(5, "%s: result $%08x (match atc)", __func__, paddr.Addr()); return paddr; - } else { - if (++n == 0) { - if (__predict_true(mmu_tc.e)) { - table_search: - // TC.E 有効で対応なしなら、こっそりテーブルサーチ。 - - // mmu.search() はさすがに bus を使うので事前に退避。 - m68kbus backup = bus; - - m68030MMU mmu(this, loglevel); - mmu.m_debugger = true; - mmu.search(7, laddr); - paddr = mmu.make_atc_debugger(); - // リストア - bus = backup; - - if (paddr.IsBusErr()) { - // TC が有効だがヒットしなかったらバスエラー - putlog(3, "%s: result BusErr", __func__); - } else { - paddr |= addr & mmu_tc.pgmask; - putlog(3, "%s: result $%08x (table search)", - __func__, paddr.Addr()); - } - return paddr; + } else if (n == m68030ATCTable::HASH_NONE) { + if (__predict_true(mmu_tc.e)) { + // TC.E 有効で対応なしなら、こっそりテーブルサーチ。 + + // mmu.search() はさすがに bus を使うので事前に退避。 + m68kbus backup = bus; + + m68030MMU mmu(this, loglevel); + mmu.m_debugger = true; + mmu.search(7, laddr); + paddr = mmu.make_atc_debugger(); + // リストア + bus = backup; + + if (paddr.IsBusErr()) { + // TC が有効だがヒットしなかったらバスエラー + putlog(5, "%s: result BusErr", __func__); } else { - // TC.E 無効 - paddr = laddr; - putlog(3, "%s: result $%08x (no translation)", + paddr |= addr & mmu_tc.pgmask; + putlog(5, "%s: result $%08x (table search)", __func__, paddr.Addr()); - return paddr; - } - } else if (++n == 0) { - // TT をこっそりチェック。 - for (int i = 0; i < 2; i++) { - m68030TT& tt = mmu_tt[i]; - if (tt.Match(laddr)) { - // 一致した。 - // CI はここでは使わないため、一致したことだけわかればよい - putlog(3, "%s: result $%08x (match tt)", - __func__, paddr.Addr()); - return paddr; - } } - return BusAddr::BusErr; + return paddr; } else { - // PS<4KB でマッチしたので再検査。 - a = table->FindSub(laddr); - if (a) { - goto atc_found; - } else { - goto table_search; + // TC.E 無効 + paddr = laddr; + putlog(5, "%s: result $%08x (no translation)", + __func__, paddr.Addr()); + return paddr; + } + } else { + // TT をこっそりチェック。 + for (int i = 0; i < 2; i++) { + m68030TT& tt = mmu_tt[i]; + if (tt.Match(laddr)) { + // 一致した。 + // CI はここでは使わないため、一致したことだけわかればよい + putlog(5, "%s: result $%08x (match tt)", + __func__, paddr.Addr()); + return paddr; } } + return BusAddr::BusErr; } } @@ -1576,7 +1531,7 @@ MPU680x0Device::TranslatePeek(busaddr la // ir2 の下位5ビットから FC を返す。 // 不当パターンなら C++ の例外をスローする。 uint32 -MPU680x0Device::get_fc() +MPU68030Device::get_fc() { uint fcfield = ir2 & 0x1f; @@ -1597,7 +1552,7 @@ MPU680x0Device::get_fc() // MMU 不当命令 (2ワード目で確定) void -MPU680x0Device::mmu_op_illg2() +MPU68030Device::mmu_op_illg2() { putlog(1, "MMU illegal instruction %04x %04x", ir, ir2); Exception(M68K::EXCEP_FLINE); @@ -1605,7 +1560,7 @@ MPU680x0Device::mmu_op_illg2() // PFLUSH fc,#mask 命令 (EA を持たない方) void -MPU680x0Device::mmu_op_pflush() +MPU68030Device::mmu_op_pflush() { uint32 mask; uint32 fc; @@ -1617,13 +1572,14 @@ MPU680x0Device::mmu_op_pflush() // PFLUSH fc,#mask,ea 命令 void -MPU680x0Device::mmu_op_pflush_ea() +MPU68030Device::mmu_op_pflush_ea() { uint32 ea; uint32 mask; uint32 fc; ea = cea_copro(); + ea &= mmu_tc.lmask; mask = (ir2 >> 5) & 7; fc = get_fc(); atc.flush(fc, mask, ea); @@ -1631,7 +1587,7 @@ MPU680x0Device::mmu_op_pflush_ea() // PLOADR/PLOADW 命令 void -MPU680x0Device::mmu_op_pload() +MPU68030Device::mmu_op_pload() { uint32 ea; uint32 fc; @@ -1653,42 +1609,44 @@ MPU680x0Device::mmu_op_pload() } m68030ATCTable *table = atc.fctables[fc]; + m68030ATCLine *a; uint8 n = table->hash[laddr.Addr() >> 12]; - if ((int8)n >= 0) { - // すでにエントリがある場合 - if (laddr.IsWrite() == false) { - return; - } - // 命令が ploadw でエントリが WProtect==0 && Modified==0 なら、 - // 一回破棄して書き込み用に作り直すため下に合流。 - m68030ATCLine *a = &table->line[n]; - if (a->IsWProtect() == false && a->IsModified() == false) { - table->Invalidate(a); - n = m68030ATCTable::HASH_NONE; - // FALLTHORUGH + // PS<4KB のケースを先に解決する。 + if (__predict_false(n == m68030ATCTable::HASH_SUB)) { + a = table->FindSub(laddr); + if (a) { + n = a - &table->line[0]; } else { - return; + n = m68030ATCTable::HASH_NONE; } } - if (n == m68030ATCTable::HASH_NONE || n == m68030ATCTable::HASH_SUB) { + if ((int8)n >= 0) { + // すでにエントリがある場合 + if (laddr.IsWrite()) { + // 命令が ploadw でエントリが WProtect==0 && Modified==0 なら、 + // 一回破棄して書き込み用に作り直す。 + a = &table->line[n]; + if (a->IsWProtect() == false && a->IsModified() == false) { + table->Invalidate(a); + table->MMUSearch(laddr); + } + } + } else if (n == m68030ATCTable::HASH_NONE) { if (__predict_true(mmu_tc.e)) { // TC.E 有効で対応なしなら、テーブルサーチを行って // ATC を作成。 - m68030ATCLine *a __unused; - a = table->MMUSearch(laddr); + table->MMUSearch(laddr); } else { // TC.E 無効なら何もしない? - return; } } else if (n == m68030ATCTable::HASH_TT) { // TT の領域なら何もしてはいけない。 - return; } } // PTESTR/PTESTW 命令 void -MPU680x0Device::mmu_op_ptest() +MPU68030Device::mmu_op_ptest() { uint level = (ir2 >> 10) & 7; busaddr rw = (ir2 & 0x0200) ? BusAddr::R : BusAddr::W; @@ -1707,6 +1665,7 @@ MPU680x0Device::mmu_op_ptest() mmu_op_illg2(); return; } + CYCLE(22); // laddr は IS と PS のところを落としたもの。 // ssw_laddr のアドレスは IS を落とさないもの (PSは不問)。 @@ -1716,25 +1675,26 @@ MPU680x0Device::mmu_op_ptest() m68030ATCTable *table = atc.fctables[fc]; m68030ATCLine *a = NULL; uint8 n = table->hash[addr >> 12]; + // PS<4KB のケースを先に解決する。 + if (__predict_false(n == m68030ATCTable::HASH_SUB)) { + a = table->FindSub(laddr); + if (a) { + n = a - &table->line[0]; + } else { + n = m68030ATCTable::HASH_NONE; + } + } if (__predict_true((int8)n >= 0)) { // ATC #(n) で見付かった。 a = &table->line[n]; - } else { - if (n == m68030ATCTable::HASH_NONE) { - // ATC に見付からなかった。Invalid を立てる。 - mmusr = m68030MMUSR::I; - } else if (n == m68030ATCTable::HASH_TT) { - for (int i = 0; i < 2; i++) { - m68030TT& tt = mmu_tt[i]; - if (tt.Match(laddr)) { - mmusr |= m68030MMUSR::T; - } - } - } else { - // PS<4KB - a = table->FindSub(laddr); - if (a == NULL) { - mmusr = m68030MMUSR::I; + } else if (n == m68030ATCTable::HASH_NONE) { + // ATC に見付からなかった。Invalid を立てる。 + mmusr = m68030MMUSR::I; + } else if (n == m68030ATCTable::HASH_TT) { + for (int i = 0; i < 2; i++) { + m68030TT& tt = mmu_tt[i]; + if (tt.Match(laddr)) { + mmusr |= m68030MMUSR::T; } } } @@ -1751,6 +1711,7 @@ MPU680x0Device::mmu_op_ptest() } } else { // レベル 1-7 ならテーブルサーチを実行。 + CYCLE(88); m68030MMU mmu(this, loglevel); mmu.m_ptest = true;