--- nono/m680x0/m68030mmu.cpp 2026/04/29 17:05:31 1.1.1.11 +++ nono/m680x0/m68030mmu.cpp 2026/04/29 17:05:35 1.1.1.12 @@ -191,7 +191,7 @@ MPU68030Device::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); @@ -273,7 +273,7 @@ MPU68030Device::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); @@ -488,7 +488,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]; @@ -504,7 +504,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]; @@ -584,7 +584,9 @@ m68030ATCTable::Flush() { for (int i = 0; i < LINES; i++) { Invalidate(&line[i]); + line[i].age = 0; } + latest_age = 0; } // この ATC テーブルから addr が一致するエントリをすべてフラッシュする。 @@ -604,6 +606,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; + } } // このテーブルのうち最も古い要素を差し出す。 @@ -617,8 +627,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; @@ -637,7 +646,7 @@ m68030ATCTable::RemoveTail() // a からハッシュを作成する。 void -m68030ATCTable::MakeHash(m68030ATCLine *a) +m68030ATCTable::MakeHash(const m68030ATCLine *a) { uint32 addr4k = a->GetLAddr() >> 12; int idx = a - &line[0]; @@ -837,7 +846,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(); @@ -850,26 +859,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--; @@ -905,7 +911,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; @@ -947,7 +953,7 @@ m68030MMU::search(int level, busaddr lad m_lastsize = m_descsize; m_descsize = 1 << 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; @@ -1023,7 +1029,7 @@ m68030MMU::fetch_desc(uint32 tableaddr, m_berr = false; // ディスクリプタを取得 - if (m_debugger) { + if (__predict_false(m_debugger)) { // デバッガアクセス uint64 data; data = cpu->mainbus->Peek4(descaddr); @@ -1043,12 +1049,12 @@ m68030MMU::fetch_desc(uint32 tableaddr, busdata bd; bd = cpu->read_phys_4(descaddr); - if (bd.IsBusErr()) { + if (__predict_false(bd.IsBusErr())) { goto buserr; } m_desc1 = bd.Data(); - if (m_descsize == 8) { + if (__predict_false(m_descsize == 8)) { bd = cpu->read_phys_4(descaddr + 4); if (bd.IsBusErr()) { goto buserr; @@ -1088,17 +1094,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 = cpu->write_phys_4(descaddr, m_desc1); - if (bd.IsBusErr()) { + if (__predict_false(bd.IsBusErr())) { goto buserr; } // バス動作正常終了 @@ -1320,41 +1329,34 @@ MPU68030Device::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); } } @@ -1392,35 +1394,37 @@ MPU68030Device::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 でマッチした @@ -1453,74 +1457,71 @@ MPU68030Device::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; } } @@ -1579,6 +1580,7 @@ MPU68030Device::mmu_op_pflush_ea() uint32 fc; ea = cea_copro(); + ea &= mmu_tc.lmask; mask = (ir2 >> 5) & 7; fc = get_fc(); atc.flush(fc, mask, ea); @@ -1608,36 +1610,38 @@ MPU68030Device::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; } } @@ -1671,25 +1675,26 @@ MPU68030Device::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; } } }