--- nono/m680x0/m68030mmu.cpp 2026/04/29 17:05:15 1.1.1.8 +++ nono/m680x0/m68030mmu.cpp 2026/04/29 17:05:22 1.1.1.9 @@ -46,7 +46,11 @@ enum ATCtype { #define NIBBLE(x) ( (x) == 0 ? 1 : ((x) + 3) / 4 ) // MMU デバッグモードなら ATC エントリ a を表示 -#define FILL_PRINT(fc, a) cpu->putlogf(3, [&] { return (a)->fill_print(fc); }) +#define FILL_PRINT(fc, a) do { \ + if (__predict_false(loglevel >= 3)) { \ + cpu->putlogf(3, [&] { return (a)->fill_print(fc); }); \ + } \ +} while (0) // インデント付き string_format static std::string indent_format(int indent, const char *fmt, ...) @@ -68,14 +72,20 @@ indent_format(int indent, const char *fm return rv; } -#define MMULOG(lv, indent, arg...) \ - gMPU->putlogf(lv, [&] { return indent_format(indent, arg); }) +#define MMULOG(lv, indent, arg...) do { \ + if (__predict_false(loglevel >= (lv))) { \ + cpu->putlogf(lv, [&, lam_func = __func__] { \ + (void)lam_func; \ + return indent_format(indent, arg); \ + }); \ + } \ +} while (0) // テーブルサーチ操作クラス class m68030MMU final { public: - m68030MMU(MPU680x0Device *); + m68030MMU(MPU680x0Device *, int loglevel_); ~m68030MMU(); // サーチを実行 @@ -85,7 +95,7 @@ class m68030MMU final void make_atc(m68030ATCLine *); // ATC にエントリを作成 (デバッガアクセス用) - uint64 make_atc_debugger(); + busaddr make_atc_debugger() const; private: // リミットチェック @@ -95,10 +105,10 @@ class m68030MMU final bool fetch_desc(uint32, int); // MMU による物理メモリ読み込み - uint64 phys_read_32(uint32 addr); + busdata phys_read_32(uint32 addr); // MMU による物理メモリ書き込み - uint64 phys_write_32(uint32 addr, uint32 data); + busdata phys_write_32(uint32 addr, uint32 data); // ディスクリプタを表示用に (デバッグ用) std::string sprintf_desc(); @@ -107,28 +117,31 @@ class m68030MMU final const char *dtname(uint32 dt); public: - ATCtype m_type; // 状態 - int m_s; // S ビット - int m_wp; // WP ビット - int m_m; // ページディスクリプタの M が立っているか - int m_l; // サーチ中にリミットを越えた - bool m_berr; // テーブルサーチ中にバスエラー - bool m_ptest; // PTEST[RW] 命令中なら真 - bool m_debugger; // デバッガからのアクセスなら true にする - int x; // 段数 TIA〜TID, FCL - uint32 m_lastaddr; // 最後にアクセスしたディスクリプタアドレス(PTEST) + ATCtype m_type {}; // 状態 + bool m_s {}; // S ビット + bool m_wp {}; // WP ビット + bool m_ci {}; // CI ビット + bool m_m {}; // ページディスクリプタの M が立っているか + bool m_lim {}; // サーチ中にリミットを越えた + bool m_berr {}; // テーブルサーチ中にバスエラー + bool m_ptest {}; // PTEST[RW] 命令中なら真 + bool m_debugger {}; // デバッガからのアクセスなら true にする + int x {}; // 段数 TIA〜TID, FCL + uint32 m_lastaddr {}; // 最後にアクセスしたディスクリプタアドレス(PTEST) private: - int m_lv[MAX_LV]; - uint32 m_laddr; - int m_fc; - uint32 m_desc1; // ディスクリプタ - uint32 m_desc2; // ロングディスクリプタの後半部 - int m_descsize; // ディスクリプタサイズ (4 or 8) - int m_lastsize; // 前段のディスクリプタサイズ + int m_lv[MAX_LV] {}; + uint32 m_laddr {}; + int m_fc {}; + uint32 m_desc1 {}; // ディスクリプタ + uint32 m_desc2 {}; // ロングディスクリプタの後半部 + int m_descsize {}; // ディスクリプタサイズ (4 or 8) + int m_lastsize {}; // 前段のディスクリプタサイズ // デバッグ用文字列 static const char * const m_lvname[MAX_LV]; + int loglevel {}; + MPU680x0Device *cpu; }; @@ -225,23 +238,25 @@ MPU680x0Device::SetTT(int n, uint32 data // (0x00000040 の位置)。TT:RW も SSW_RW も Read が %1。 // ・RWM が %1 なら R/W は無視、RWM が %0 なら R/W の一致も検査するので // RWM が %0 の時は RW のマスクビットを立てておく。 + // ・FC は busaddr の配置に合わせて1ビット左シフトしたところを使う。 // ・FCMask は %1 が無視を表しているので NOT しておく。 // - // target 00000000 00000000 00000000 0R000FFF : R はアクセス R/~W + // target 00000000 00000000 00000000 0R00FFFS : R はアクセス R/~W // ^ : F はアクセス FC - // base 00000000 00000000 E0000000 0R000FFF : R は期待する R/~W + // : S は FC2 のコピー + // base 00000000 00000000 E0000000 0R00FFF0 : R は期待する R/~W // & : F は期待する FC // : E は ~TT:E - // mask 00000000 00000000 10000000 0M000CCC : M は R/~W マスク + // mask 00000000 00000000 10000000 0M00CCC0 : M は R/~W マスク // : C は FC マスク sbase = ~data & m68030TT::E; sbase |= (data & m68030TT::RW) >> 3; - sbase |= (data & m68030TT::FCBASE_MASK) >> 4; + sbase |= (data & m68030TT::FCBASE_MASK) >> 3; smask = m68030TT::E; if ((data & m68030TT::RWM) == 0) { smask |= M68K::SSW_RW; } - smask |= ~data & m68030TT::FCMASK_MASK; + smask |= (~data & m68030TT::FCMASK_MASK) << 1; mmu_tt[n].base = lbase | (((uint64)sbase) << 32); mmu_tt[n].mask = lmask | (((uint64)smask) << 32); @@ -262,14 +277,14 @@ MPU680x0Device::SetTT(int n, uint32 data } // アクセスがこの TT とマッチするか調べる。 -// ssw_laddr は上位32ビットが cpu->bus.ssw、下位32ビットが論理アドレス -// (下24ビットは呼び出し側でマスクしなくてよい)。 +// laddr の上位ワードはそのまま使える。 +// 下位32ビットが論理アドレス (下24ビットは呼び出し側でマスクしなくてよい)。 // この TT が有効でアドレスがマッチすれば true を返す。 // (TT:E は演算に織り込んである、このすぐ上の SetTT() のコメント参照) bool -m68030TT::Match(uint64 ssw_laddr) const +m68030TT::Match(busaddr laddr) const { - bool rv = (((ssw_laddr ^ base) & mask) == 0); + bool rv = (((laddr.Get() ^ base) & mask) == 0); return rv; } @@ -289,7 +304,7 @@ MPU680x0Device::SetTC(uint32 data) if (mmu_tc.Check() == false) { // エラーなら E をクリアして MMU 構成例外。 // (例外処理自体は呼び出し側で行う) - mmu_tc.e = 0; + mmu_tc.e = false; mmu_enable_changed(); return false; } @@ -436,6 +451,10 @@ m68030ATCTable::MoveHead(m68030ATCLine * m68030ATC::m68030ATC(MPU680x0Device *cpu_) { cpu = cpu_; + + for (auto& table : tables) { + table.cpu = cpu; + } } // デストラクタ @@ -443,6 +462,17 @@ m68030ATC::~m68030ATC() { } +// ログレベルの設定。 +// これは Object のオーバーライドではないが、同じ使い方をする。 +void +m68030ATC::SetLogLevel(int loglevel_) +{ + loglevel = loglevel_; + for (auto& table : tables) { + table.loglevel = loglevel_; + } +} + #if defined(ATC_SINGLE) // item をリストの先頭に挿入。 void @@ -539,15 +569,15 @@ m68030ATCTable::move_second(m68030ATCLin #endif // ATC_SINGLE // fill_{fetch,read,write}() が各アクセス用の ATC サーチ。 -// 論理アドレス fc:addr が ATC にあればそのエントリを返す。 -// なければ ATC を更新してそのエントリを返す。 +// あらかじめ論理ページにマスクされたアドレス fc:addr が ATC にあれば +// そのエントリを返す。なければ ATC を更新してそのエントリを返す。 // fill_peek() はデバッグ用なので一切状態を更新せず結果だけ返す。 const m68030ATCLine& -m68030ATC::fill_fetch() +m68030ATC::fill_fetch(busaddr addr_) { - uint32 laddr = cpu->bus.laddr & cpu->mmu_tc.lmask; - uint fc = cpu->bus.GetFC(); + uint32 laddr = addr_.Addr(); + uint fc = addr_.GetFC(); m68030ATCTable *table; m68030ATCLine *a; int i; @@ -606,7 +636,7 @@ m68030ATC::fill_fetch() #endif // テーブルサーチして結果を ATC に入れる - m68030MMU mmu(cpu); + m68030MMU mmu(cpu, loglevel); mmu.search(7); mmu.make_atc(a); @@ -615,10 +645,10 @@ m68030ATC::fill_fetch() } const m68030ATCLine& -m68030ATC::fill_read() +m68030ATC::fill_read(busaddr addr_) { - uint32 laddr = cpu->bus.laddr & cpu->mmu_tc.lmask; - uint fc = cpu->bus.GetFC(); + uint32 laddr = addr_.Addr(); + uint fc = addr_.GetFC(); m68030ATCTable *table; m68030ATCLine *a; int i; @@ -677,7 +707,7 @@ m68030ATC::fill_read() #endif // テーブルサーチして結果を ATC に入れる - m68030MMU mmu(cpu); + m68030MMU mmu(cpu, loglevel); mmu.search(7); mmu.make_atc(a); @@ -686,10 +716,10 @@ m68030ATC::fill_read() } const m68030ATCLine& -m68030ATC::fill_write() +m68030ATC::fill_write(busaddr addr_) { - uint32 laddr = cpu->bus.laddr & cpu->mmu_tc.lmask; - uint fc = cpu->bus.GetFC(); + uint32 laddr = addr_.Addr(); + uint fc = addr_.GetFC(); m68030ATCTable *table; m68030ATCLine *a; int i; @@ -704,8 +734,8 @@ m68030ATC::fill_write() // テーブルサーチを実行する。 if (!a->IsWProtect() && !a->IsModified()) { FILL_PRINT(fc, a); - MMULOG(3, 1, "ATC_fill: write access but M is not set, " - "so invalidate it"); + MMULOG(3, 1, "%s: write access but M is not set, " + "so invalidate it", lam_func); a->Invalidate(); goto search; } @@ -721,8 +751,8 @@ m68030ATC::fill_write() // テーブルサーチを実行する。 if (!a->IsWProtect() && !a->IsModified()) { FILL_PRINT(fc, a); - MMULOG(3, 1, "ATC_fill: write access but M is not set, " - "so invalidate it"); + MMULOG(3, 1, "%s: write access but M is not set, " + "so invalidate it", lam_func); a->Invalidate(); break; } @@ -752,8 +782,8 @@ m68030ATC::fill_write() // テーブルサーチを実行する。 if (!a->IsWProtect() && !a->IsModified()) { FILL_PRINT(fc, a); - MMULOG(3, 1, "ATC_fill: write access but M is not set, " - "so invalidate it"); + MMULOG(3, 1, "%s: write access but M is not set, " + "so invalidate it", lam_func); a->Invalidate(); break; } @@ -780,7 +810,7 @@ m68030ATC::fill_write() #endif // テーブルサーチして結果を ATC に入れる - m68030MMU mmu(cpu); + m68030MMU mmu(cpu, loglevel); mmu.search(7); mmu.make_atc(a); @@ -804,7 +834,7 @@ m68030ATC::fill_peek(uint32 laddr, uint a = &table->line[i]; if (a->GetTag() == laddr) { // ヒットした - MMULOG(3, 1, "fill_peek: match %d:$%08x -> $%08x", + MMULOG(3, 1, "%s: match %d:$%08x -> $%08x", lam_func, fc, laddr, (uint32)a->GetPAddr()); return a; } @@ -815,7 +845,7 @@ m68030ATC::fill_peek(uint32 laddr, uint for (a = table->head; a; a = a->next) { if ((a->GetTag() == laddr) && ((a->fc & 4) == fc)) { // ヒットした - MMULOG(3, 1, "fill_peek: match %d:$%08x -> $%08x", + MMULOG(3, 1, "%s: match %d:$%08x -> $%08x", lam_func, a->fc, laddr, (uint32)a->GetPAddr()); return a; } @@ -826,25 +856,24 @@ m68030ATC::fill_peek(uint32 laddr, uint } // デバッグ表示。 -// ATC_SINGLE なら fc は ATCLine に含まれているため、引数はダミーで -// 変数名が衝突するため仮引数名も変えてある。なんだかなあ。 +// ATC_SINGLE なら fc は this に含まれている。 +// !ATC_SINGLE なら引数で渡される。 // XXX print といいつつ string を返す -#if defined(ATC_SINGLE) -std::string -m68030ATCLine::fill_print(uint dummyfc) -#else std::string -m68030ATCLine::fill_print(uint fc) -#endif +m68030ATCLine::fill_print(uint fc_) { +#if !defined(ATC_SINGLE) + uint fc = fc_; +#endif uint32 laddr = GetLAddr(); if (!IsBusError()) { + uint32 ci = IsCInhibit(); uint32 wp = IsWProtect(); uint32 mod = IsModified(); return indent_format(1, - "ATC_fill: match %d:$%08x -> $%08x WP=%d M=%d", - fc, laddr, GetPAddr(), wp, mod); + "ATC_fill: match %d:$%08x -> $%08x CI=%d WP=%d M=%d", + fc, laddr, GetPAddr(), ci, wp, mod); } else { return indent_format(1, "ATC_fill: match %d:$%08x -> BusErr", @@ -867,7 +896,7 @@ m68030ATCTable::Lookup() for (int i = 0; i < countof(line); i++) { m68030ATCLine& a = line[i]; if (a.IsInvalid()) { - MMULOG(3, 1, "ATC_lookup got free entry [%d]", i); + MMULOG(3, 1, "ATC.Lookup got free entry [%d]", i); return &a; } if (a.age < minage) { @@ -876,7 +905,7 @@ m68030ATCTable::Lookup() } } // 空きがなければ、最古のエントリを差し出す - MMULOG(3, 1, "ATC_lookup got oldest entry [%d]", minidx); + MMULOG(3, 1, "ATC.Lookup got oldest entry [%d]", minidx); return &line[minidx]; } #else @@ -890,7 +919,7 @@ m68030ATCTable::lookup() for (int i = 0; i < LINES; i++) { a = &line[i]; if (a->IsInvalid()) { - MMULOG(3, 1, "ATC_lookup got free entry [%d]", i); + MMULOG(3, 1, "ATC.Lookup got free entry [%d]", i); goto found; } } @@ -900,7 +929,7 @@ m68030ATCTable::lookup() while (a->next) { a = a->next; } - MMULOG(3, 1, "ATC_lookup got oldest entry"); + MMULOG(3, 1, "ATC.Lookup got oldest entry"); found: return a; @@ -1014,27 +1043,14 @@ m68030ATCTable::flush(uint32 fc, uint32 // // コンストラクタ -m68030MMU::m68030MMU(MPU680x0Device *cpu_) +m68030MMU::m68030MMU(MPU680x0Device *cpu_, int loglevel_) { cpu = cpu_; + loglevel = loglevel_; m_type = INVALID; - m_s = 0; - m_wp = 0; - m_m = 0; - m_l = 0; - m_berr = false; - m_debugger = false; - m_ptest = false; - x = -1; - memset(m_lv, 0, sizeof(m_lv)); - m_laddr = 0; m_fc = -1; - m_desc1 = 0; - m_desc2 = 0; - m_descsize = 0; - m_lastsize = 0; } // デストラクタ @@ -1052,7 +1068,7 @@ m68030MMU::search(int level) int dt; bool is_super; - m_laddr = cpu->bus.laddr; + m_laddr = cpu->bus.laddr.Addr(); m_fc = cpu->bus.GetFC(); is_super = (m_fc & 0x04); @@ -1095,9 +1111,7 @@ m68030MMU::search(int level) return buf; }); - // サーチ時の初期化処理。図9-26 - m_wp = 0; - m_s = 0; + // この辺に図9-26 の初期化だがコンストラクタで初期化済み。 // ここから図9-25。 @@ -1114,7 +1128,7 @@ m68030MMU::search(int level) // ルートポインタの DT をチェック dt = GET_DT(m_desc1); - MMULOG(3, 2, "search: %s dt=%s", rpname, dtname(dt)); + MMULOG(3, 2, "%s: %s dt=%s", lam_func, rpname, dtname(dt)); switch (dt) { case DT_INVALID: // 無効は設定できないはずなので、ここに来ないはず @@ -1139,7 +1153,7 @@ m68030MMU::search(int level) // たぶん検索レベルを1つ消費するはず。未確認。 level--; - MMULOG(3, 2, "search: %s tableaddr=$%08x idx=$%x", + MMULOG(3, 2, "%s: %s tableaddr=$%08x idx=$%x", lam_func, m_lvname[x], m_desc2, m_lv[x]); // ディスクリプタをフェッチ @@ -1172,7 +1186,7 @@ m68030MMU::search(int level) // リミットチェック if (m_lastsize == 8 && limitcheck() == false) { m_type = INVALID; - m_l = 1; + m_lim = true; return; } @@ -1180,7 +1194,7 @@ m68030MMU::search(int level) uint32 tableaddr; tableaddr = (m_lastsize == 4) ? m_desc1 : m_desc2; tableaddr &= 0xfffffff0; - MMULOG(3, 2, "search: %s tableaddr=$%08x idx=$%x", + MMULOG(3, 2, "%s: %s tableaddr=$%08x idx=$%x", lam_func, m_lvname[x], tableaddr, m_lv[x]); // ディスクリプタをフェッチ @@ -1246,12 +1260,12 @@ m68030MMU::limitcheck() const // 最上位ビットが L/U if ((int32)m_desc1 < 0) { if (m_lv[x] < limit) { - MMULOG(3, 2, "limitcheck: $%04x < $%04x", m_lv[x], limit); + MMULOG(3, 2, "%s: $%04x < $%04x", lam_func, m_lv[x], limit); return false; } } else { if (m_lv[x] > limit) { - MMULOG(3, 2, "limitcheck: $%04x > $%04x", m_lv[x], limit); + MMULOG(3, 2, "%s: $%04x > $%04x", lam_func, m_lv[x], limit); return false; } } @@ -1281,7 +1295,7 @@ m68030MMU::fetch_desc(uint32 tableaddr, // インダイレクトなら idx = 0 でコールしてあるので、 // tableaddr がそのまま PA になるという寸法。 descaddr = tableaddr + idx * m_descsize; - MMULOG(3, 2, "fetch_desc: descsize=%d descaddr=$%08x", + MMULOG(3, 2, "%s: descsize=%d descaddr=$%08x", lam_func, m_descsize, descaddr); // バスエラー発生フラグをクリアしておく @@ -1305,20 +1319,20 @@ m68030MMU::fetch_desc(uint32 tableaddr, m_desc2 = data; } } else { - uint64 data; + busdata bd; - data = phys_read_32(descaddr); - if ((int64)data < 0) { + bd = phys_read_32(descaddr); + if (bd.IsBusErr()) { goto buserr; } - m_desc1 = data; + m_desc1 = bd.Data(); if (m_descsize == 8) { - data = phys_read_32(descaddr + 4); - if ((int64)data < 0) { + bd = phys_read_32(descaddr + 4); + if (bd.IsBusErr()) { goto buserr; } - m_desc2 = data; + m_desc2 = bd.Data(); } m_lastaddr = descaddr; @@ -1328,7 +1342,7 @@ m68030MMU::fetch_desc(uint32 tableaddr, // DT は必ず最初のロングワードの下位2ビット。 do_write = false; dt = GET_DT(m_desc1); - MMULOG(3, 2, "fetch_desc: desc=%s dt=%s", + MMULOG(3, 2, "%s: desc=%s dt=%s", lam_func, sprintf_desc().c_str(), dtname(dt)); switch (dt) { case DT_INVALID: // 無効 @@ -1345,7 +1359,7 @@ m68030MMU::fetch_desc(uint32 tableaddr, // 図にはないけど、ATC 更新のためと PTEST のために // ページディスクリプタの M ビットを記録。 if ((m_desc1 & MMU_DESC_M)) - m_m = 1; + m_m = true; break; case DT_VALID4: // 有効4バイト @@ -1362,21 +1376,20 @@ m68030MMU::fetch_desc(uint32 tableaddr, // ライトライクルの実行 if (do_write) { - int64 berr = phys_write_32(descaddr, m_desc1); - if (berr < 0) { + busdata bd = phys_write_32(descaddr, m_desc1); + if (bd.IsBusErr()) { goto buserr; } // バス動作正常終了 - MMULOG(3, 2, "fetch_desc: desc=%s updated", sprintf_desc().c_str()); + MMULOG(3, 2, "%s: desc=%s updated", lam_func, sprintf_desc().c_str()); } - // ステータス更新 - // XXX Cache Inhibit ビットは未実装なので、ページディスクリプタと - // 有効4/8バイトのケースは同じでよくなる。 + // ステータス更新 (OR していく) // XXX 実際には CI はページディスクリプタにしかないけど - m_wp |= (m_desc1 & MMU_DESC_WP) ? 1 : 0; - if (m_descsize == 8) { - m_s |= (m_desc1 & MMU_DESC_S) ? 1 : 0; + m_wp |= (m_desc1 & MMU_DESC_WP); + m_ci |= (m_desc1 & MMU_DESC_CI); + if (__predict_false(m_descsize == 8)) { + m_s |= (m_desc1 & MMU_DESC_S); } return true; @@ -1400,19 +1413,19 @@ m68030MMU::make_atc(m68030ATCLine *a) switch (m_type) { case INVALID: // 無効 a->data |= m68030ATCLine::BUSERROR; - MMULOG(3, 2, "make_atc: type=INVALID -> BusErr"); + MMULOG(3, 2, "%s: type=INVALID -> BusErr", lam_func); return; case NORMAL: // ノーマル case INDIRECT: // 間接 paddr = (m_descsize == 4) ? m_desc1 : m_desc2; - MMULOG(3, 2, "make_atc: type=NORMAL paddr=$%08x", paddr & 0xffffff00); + MMULOG(3, 2, "%s: type=NORMAL paddr=$%08x", lam_func, + paddr & 0xffffff00); break; case EARLY: // アーリーターミネーション paddr = (m_descsize == 4) ? m_desc1 : m_desc2; - buf = string_format("make_atc: type=EARLY paddr=$%08x", - paddr & 0xffffff00); + buf = string_format("type=EARLY paddr=$%08x", paddr & 0xffffff00); // 残ってるビットも足して返す for (int i = x + 1; i <= TID; i++) { @@ -1421,7 +1434,7 @@ m68030MMU::make_atc(m68030ATCLine *a) buf += string_format(" +%s=%08x", m_lvname[i], paddr); } } - MMULOG(3, 2, "%s", buf.c_str()); + MMULOG(3, 2, "%s: %s", lam_func, buf.c_str()); break; default: PANIC("corrupted m_type=%d", (int)m_type); @@ -1430,7 +1443,8 @@ m68030MMU::make_atc(m68030ATCLine *a) // PS の部分は反映しない a->paddr = paddr & cpu->mmu_tc.lmask; - //if (m_ci) a->data |= m68030ATCLine::CINHIBIT; + if (m_ci) + a->data |= m68030ATCLine::CINHIBIT; if (m_wp) a->data |= m68030ATCLine::WPROTECT; if (m_m) @@ -1438,16 +1452,16 @@ m68030MMU::make_atc(m68030ATCLine *a) } // make_atc() と同様にテーブルサーチの結果から物理ページアドレスを返す。 -// バスエラーになるケースなら (uint64)-1 を返す。 +// バスエラーになるケースなら BusErr を返す。 // デバッガアクセスなので、VM に一切干渉しない。 -uint64 -m68030MMU::make_atc_debugger() +busaddr +m68030MMU::make_atc_debugger() const { uint64 paddr; switch (m_type) { case INVALID: // 無効 - return (uint64)-1; + paddr = busaddr::BusErr; break; case NORMAL: // ノーマル @@ -1466,54 +1480,63 @@ m68030MMU::make_atc_debugger() } } break; + default: PANIC("corrupted m_type=%d", (int)m_type); } + + paddr |= busaddr::TableSearched; return paddr; } // 物理メモリからの読み込み。 // 正常に読み込めれば 32bit の値。バスエラーなら (uint64)-1 を返す。 -uint64 +busdata m68030MMU::phys_read_32(uint32 addr) { m68kbus backup; - uint64 data; + busdata bd; // バス情報を一旦退避 backup = cpu->bus; // 物理バスアクセス - cpu->bus.ssw = M68K::SSW_BUS_R | M68K::FC_SD; - data = cpu->mainbus->Read32(addr); - if ((int64)data < 0) - return data; + cpu->bus.laddr.Set(addr, busaddr::Read | busaddr::S); + cpu->bus.paddr = cpu->bus.laddr; + bd = cpu->mainbus->Read32(cpu->bus.paddr); + if (__predict_false(bd.IsBusErr())) { + cpu->bus.size = M68K::SSW_SIZE_LONG; + return bd; + } // バス情報を復元 cpu->bus = backup; - return data; + return bd; } // 物理メモリへの書き込み。 // 正常に書き込めれば 0、バスエラーなら (uint64)-1 を返す。 -uint64 +busdata m68030MMU::phys_write_32(uint32 addr, uint32 data) { m68kbus backup; - uint64 berr; + busdata bd; // バス情報を一旦退避 backup = cpu->bus; // 物理バスアクセス - cpu->bus.ssw = M68K::SSW_BUS_W | M68K::FC_SD; - berr = cpu->mainbus->Write32(addr, data); - if ((int64)berr < 0) - return berr; + cpu->bus.laddr.Set(addr, busaddr::Write | busaddr::S); + cpu->bus.paddr = cpu->bus.laddr; + bd = cpu->mainbus->Write32(cpu->bus.paddr, data); + if (__predict_false(bd.IsBusErr())) { + cpu->bus.size = M68K::SSW_SIZE_LONG; + return bd; + } // バス情報を復元 cpu->bus = backup; - return 0; + return bd; } // ディスクリプタ表示用の文字列を返す。 @@ -1570,11 +1593,11 @@ const char * const m68030MMU::m_lvname[M // アドレス変換 // -// 論理アドレスが TT0/TT1 どちらかと一致すれば true を返す。 +// 論理アドレスが TT0/TT1 どちらかと一致すれば (bus.ci を更新して) true を返す。 // 一致しなければ false を返す。 // 高速化のため mmu_tt_quick による評価は呼び出し側で行なっている。 bool -MPU680x0Device::CheckTT() const +MPU680x0Device::CheckTT() { bool ci; int match; @@ -1583,22 +1606,20 @@ MPU680x0Device::CheckTT() const ci = false; for (int i = 0; i < 2; i++) { const m68030TT& tt = mmu_tt[i]; - if (tt.Match(bus.ssw_laddr)) { + if (tt.Match(bus.laddr)) { // 一致した match += i + 1; ci |= tt.ci != 0; - MMULOG(3, 1, "%s: TT%d match", __func__, i); + putlog(3, " %s: TT%d match", __func__, i); } } - // CI は計算はするけど現状未実装なので放置 - (void)ci; - // 一致したら PA <- LA if (match != 0) { - MMULOG(3, 0, "%s: result %08x (match TT%s)", __func__, - bus.laddr, + putlog(3, "%s: result %08x (match TT%s)", __func__, + (uint32)bus.laddr, (match == 3) ? "0 and TT1" : ((match == 1) ? "0" : "1")); + bus.ci = ci; return true; } return false; @@ -1609,33 +1630,36 @@ MPU680x0Device::CheckTT() const bool MPU680x0Device::TranslateFetch() { + busaddr baddr = bus.laddr; + uint32 laddr = baddr.Addr(); + // 状態表示 - MMULOG(3, 0, "%s: enter %c:$%08x pc=$%08x", __func__, - (bus.GetFC() & 0x04) ? 'S' : 'U', - bus.laddr, + putlog(3, "%s: enter %c:$%08x pc=$%08x", __func__, + (baddr.IsSuper() ? 'S' : 'U'), + laddr, ppc); // まず TT をチェック - if (__predict_false(mmu_tt_quick[bus.laddr >> 24] != 0)) { + if (__predict_false(mmu_tt_quick[laddr >> 24] != 0)) { if (CheckTT()) { return true; } } // ATC からアドレスを取得 - if (mmu_tc.e) { - const m68030ATCLine& a = atc.fill_fetch(); - if (a.IsBusError()) { - MMULOG(3, 0, "%s: result BusErr (ATC:B)", __func__); + if (__predict_true(mmu_tc.e)) { + baddr &= mmu_tc.lmask; + const m68030ATCLine& a = atc.fill_fetch(baddr); + if (__predict_false(a.IsBusError())) { + putlog(3, "%s: result BusErr (ATC:B)", __func__); return false; } - bus.paddr = a.GetPAddr(); - bus.paddr |= bus.laddr & mmu_tc.pgmask; - //bus.ci = a->ci; + bus.paddr.SetAddr(a.GetPAddr() | (laddr & mmu_tc.pgmask)); + bus.ci = a.data & m68030ATCLine::CINHIBIT; } - MMULOG(3, 0, "%s: result $%08x", __func__, bus.paddr); + putlog(3, "%s: result $%08x", __func__, bus.paddr.Addr()); return true; } @@ -1644,34 +1668,37 @@ MPU680x0Device::TranslateFetch() bool MPU680x0Device::TranslateRead() { + busaddr baddr = bus.laddr; + uint32 laddr = baddr.Addr(); + // 状態表示 - MMULOG(3, 0, "%s: enter %c:$%08x pc=%c:$%08x", __func__, - (bus.GetFC() & 0x04) ? 'S' : 'U', - bus.laddr, + putlog(3, "%s: enter %c:$%08x pc=%c:$%08x", __func__, + (baddr.IsSuper() ? 'S' : 'U'), + laddr, IsSuper() ? 'S' : 'U', ppc); // まず TT をチェック - if (__predict_false(mmu_tt_quick[bus.laddr >> 24] != 0)) { + if (__predict_false(mmu_tt_quick[laddr >> 24] != 0)) { if (CheckTT()) { return true; } } // ATC からアドレスを取得 - if (mmu_tc.e) { - const m68030ATCLine& a = atc.fill_read(); - if (a.IsBusError()) { - MMULOG(3, 0, "%s: result BusErr (ATC:B)", __func__); + if (__predict_true(mmu_tc.e)) { + baddr &= mmu_tc.lmask; + const m68030ATCLine& a = atc.fill_read(baddr); + if (__predict_false(a.IsBusError())) { + putlog(3, "%s: result BusErr (ATC:B)", __func__); return false; } - bus.paddr = a.GetPAddr(); - bus.paddr |= bus.laddr & mmu_tc.pgmask; - //bus.ci = a->ci; + bus.paddr.SetAddr(a.GetPAddr() | (laddr & mmu_tc.pgmask)); + bus.ci = a.data & m68030ATCLine::CINHIBIT; } - MMULOG(3, 0, "%s: result $%08x", __func__, bus.paddr); + putlog(3, "%s: result $%08x", __func__, bus.paddr.Addr()); return true; } @@ -1680,66 +1707,68 @@ MPU680x0Device::TranslateRead() bool MPU680x0Device::TranslateWrite() { + busaddr baddr = bus.laddr; + uint32 laddr = baddr.Addr(); + // 状態表示 - MMULOG(3, 0, "%s: enter %c:$%08x pc=%c:$%08x", __func__, - (bus.GetFC() & 0x04) ? 'S' : 'U', - bus.laddr, + putlog(3, "%s: enter %c:$%08x pc=%c:$%08x", __func__, + (baddr.IsSuper() ? 'S' : 'U'), + laddr, IsSuper() ? 'S' : 'U', ppc); // まず TT をチェック - if (__predict_false(mmu_tt_quick[bus.laddr >> 24] != 0)) { + if (__predict_false(mmu_tt_quick[laddr >> 24] != 0)) { if (CheckTT()) { return true; } } // ATC からアドレスを取得 - if (mmu_tc.e) { - const m68030ATCLine& a = atc.fill_write(); - if (a.IsBusError()) { - MMULOG(3, 0, "%s: result BusErr (ATC:B)", __func__); + if (__predict_true(mmu_tc.e)) { + baddr &= mmu_tc.lmask; + const m68030ATCLine& a = atc.fill_write(baddr); + if (__predict_false(a.IsBusError())) { + putlog(3, "%s: result BusErr (ATC:B)", __func__); return false; } - if (a.IsWProtect()) { + if (__predict_false(a.IsWProtect())) { // Write アクセスで WP が立ってたらバスエラー - MMULOG(3, 0, "%s: result Buserr (ATC:WP)", __func__); + putlog(3, "%s: result Buserr (ATC:WP)", __func__); return false; } - bus.paddr = a.GetPAddr(); - bus.paddr |= bus.laddr & mmu_tc.pgmask; - //bus.ci = a->ci; + bus.paddr.SetAddr(a.GetPAddr() | (laddr & mmu_tc.pgmask)); + bus.ci = a.data & m68030ATCLine::CINHIBIT; } - MMULOG(3, 0, "%s: result $%08x", __func__, bus.paddr); + putlog(3, "%s: result $%08x", __func__, bus.paddr.Addr()); return true; } // ピーク用のアドレス変換を行う。 -// ATC にエントリが見付からない場合、do_search が true ならテーブル -// サーチまで行う。false ならテーブルサーチせずに帰る。 -// 変換できれば対応する物理アドレスを、バスエラーなら (uint64)-1 を返す。 -uint64 -MPU680x0Device::TranslatePeek(uint32 laddr, uint fc, bool do_search) +// 変換できれば対応する物理アドレスを、バスエラーなら BusErr を返す。 +// テーブルサーチを行ったら TableSearched ビットを立てる。 +busaddr +MPU680x0Device::TranslatePeek(busaddr baddr) { - uint64 paddr; + busaddr paddr; + uint32 laddr = baddr.Addr(); // 状態表示 - MMULOG(3, 0, "%s: enter %c:$%08x", __func__, - (fc & 0x04) ? 'S' : 'U', + putlog(3, "%s: enter %c:$%08x", __func__, + (baddr.IsSuper() ? 'S' : 'U'), laddr); // まず TT をチェック paddr = laddr; if (__predict_false(mmu_tt_quick[laddr >> 24] != 0)) { - uint64 ssw_laddr = ((uint64)(M68K::SSW_BUS_R | fc) << 32) | laddr; for (int i = 0; i < 2; i++) { m68030TT& tt = mmu_tt[i]; - if (tt.Match(ssw_laddr)) { + if (tt.Match(baddr)) { // 一致した。 // CI はここでは使わないため、一致したことだけわかればよい - MMULOG(3, 0, "%s: result $%08x (match tt)", + putlog(3, "%s: result $%08x (match tt)", __func__, (uint32)paddr); return paddr; } @@ -1750,46 +1779,43 @@ MPU680x0Device::TranslatePeek(uint32 lad if (mmu_tc.e) { // ATC からこっそりアドレスを取得 const m68030ATCLine *a; - a = atc.fill_peek(laddr & mmu_tc.lmask, fc); + a = atc.fill_peek(laddr & mmu_tc.lmask, baddr.GetFC()); if (a != NULL) { paddr = a->GetPAddr(); paddr |= laddr & mmu_tc.pgmask; - MMULOG(3, 0, "%s: result $%08x (match atc)", + putlog(3, "%s: result $%08x (match atc)", __func__, (uint32)paddr); return paddr; } // 見付からなかったのでこっそりテーブルサーチ。 - if (do_search) { - // mmu.search() はさすがに bus を使うので事前に退避。 - m68kbus backup = bus; - - bus.laddr = laddr; - bus.ssw = fc; - m68030MMU mmu(this); - mmu.m_debugger = true; - mmu.search(7); - paddr = mmu.make_atc_debugger(); - // リストア - bus = backup; - - if ((int64)paddr >= 0) { - paddr |= laddr & mmu_tc.pgmask; - MMULOG(3, 0, "%s: result $%08x (table search)", - __func__, (uint32)paddr); - return paddr; - } - } - // TC が有効だがヒットしなかったらバスエラー - MMULOG(3, 0, "%s: result BusErr", __func__); - return (uint64)-1; + // mmu.search() はさすがに bus を使うので事前に退避。 + m68kbus backup = bus; + + bus.laddr = baddr; + m68030MMU mmu(this, loglevel); + mmu.m_debugger = true; + mmu.search(7); + paddr = mmu.make_atc_debugger(); + // リストア + bus = backup; + + if (paddr.IsBusErr()) { + // TC が有効だがヒットしなかったらバスエラー + putlog(3, "%s: result BusErr", __func__); + } else { + paddr |= laddr & mmu_tc.pgmask; + putlog(3, "%s: result $%08x (table search)", + __func__, paddr.Addr()); + } + return paddr; } // TT が無効かまたは有効でもヒットせず、 // かつ TC も無効だったら (こっちは「有効でヒットせず」は含まない)、 // 論理アドレスをそのまま返す - MMULOG(3, 0, "%s: result $%08x (no translation)", __func__, laddr); + putlog(3, "%s: result $%08x (no translation)", __func__, laddr); return laddr; } @@ -1805,9 +1831,9 @@ MPU680x0Device::get_fc() uint fcfield = ir2 & 0x1f; if (fcfield == 0) { - return reg.sfc; + return reg.GetSFC(); } else if (fcfield == 1) { - return reg.dfc; + return reg.GetDFC(); } else if (fcfield < 0x08) { // break; } else if (fcfield < 0x10) { @@ -1869,13 +1895,12 @@ MPU680x0Device::mmu_op_pload() // 実効アドレスを論理アドレスとする ATC を作成。 // ってこれでいいのか? - bus.laddr = ea; if ((ir2 & 0x0200)) { - bus.ssw = M68K::SSW_BUS_R | fc; - atc.fill_read(); + busaddr addr(ea, busaddr::FC(fc) | busaddr::R); + atc.fill_read(addr); } else { - bus.ssw = M68K::SSW_BUS_W | fc; - atc.fill_write(); + busaddr addr(ea, busaddr::FC(fc) | busaddr::W); + atc.fill_write(addr); } } @@ -1884,7 +1909,7 @@ void MPU680x0Device::mmu_op_ptest() { uint level = (ir2 >> 10) & 7; - uint rw = (ir2 & 0x0200) ? M68K::SSW_BUS_R : M68K::SSW_BUS_W; + busaddr rw = (ir2 & 0x0200) ? busaddr::R : busaddr::W; uint rn = (ir2 >> 5) & 0xf; uint32 ea; uint32 fc; @@ -1903,7 +1928,7 @@ MPU680x0Device::mmu_op_ptest() // laddr は IS と PS のところを落としたもの。 // ssw_laddr のアドレスは IS を落とさないもの (PSは不問)。 - uint64 ssw_laddr = ((uint64)(rw | fc) << 32) | ea; + busaddr ssw_laddr(ea, busaddr::FC(fc) | rw); uint32 laddr = ea & mmu_tc.lmask; const m68030ATCLine *a = atc.fill_peek(laddr, fc); @@ -1931,16 +1956,15 @@ MPU680x0Device::mmu_op_ptest() } else { // レベル 1-7 ならテーブルサーチを実行。 - bus.laddr = ea; - bus.ssw = rw | fc; - m68030MMU table(this); + bus.laddr.Set(ea, busaddr::FC(fc) | rw); + m68030MMU table(this, loglevel); table.m_ptest = true; table.search(level); if (table.m_berr) { mmusr |= m68030MMUSR::B; } - if (table.m_l) { + if (table.m_lim) { // XXX not tested mmusr |= m68030MMUSR::L; }