--- nono/m680x0/m68030mmu.h 2026/04/29 17:05:26 1.1.1.8 +++ nono/m680x0/m68030mmu.h 2026/04/29 17:05:57 1.1.1.11 @@ -10,7 +10,26 @@ #include #include "fixedqueue.h" -class MPU680x0Device; +// ATC 実装種別。 +//#define M68030_CUSTOM_ATC +#define ATC_ORDER64 + +// ATC エントリ数。 +#define M68030_ATC_LINES (22) + +#if defined(M68030_CUSTOM_ATC) +#else +# if defined(ATC_ORDER64) +# if M68030_ATC_LINES > 24 +# error M68030_ATC_LINES must be <= 24 on ATC_ORDER64. +# endif +# if M68030_ATC_LINES < 13 +# error M68030_ATC_LINES must be >= 13 on ATC_ORDER64. +# endif +# endif +#endif + +class MPU68030Device; // SRP, CRP class m68030RP @@ -18,7 +37,7 @@ class m68030RP // 6 5 4 3 // 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 // +-+-----------------------------+---------------------------+---+ - // |U| LIMIT | unused |DT | + // |U| LIMIT | 0 |DT | // +-+-----------------------------+---------------------------+---+ // // 3 2 1 0 @@ -27,13 +46,11 @@ class m68030RP // | TABLE ADDRESS (PA31-PA4) |unused | // +-------------------------------------------------------+-------+ public: - static const uint32 DT_MASK = 0x00000003; static const uint32 H_MASK = 0xffff0003; - static const uint32 L_MASK = 0xfffffff0; }; // TT レジスタの各フィールドを束ねた構造体のようなもの。 -// MPU680x0Device::SetTT(), GetTT() で読み書きする。 +// MPU68030Device::SetTT(), GetTT() で読み書きする。 class m68030TT { // 3 2 1 0 @@ -54,13 +71,16 @@ class m68030TT static const uint32 FCBASE_MASK = 0x00000070; static const uint32 FCMASK_MASK = 0x00000007; + void Set(uint32 data); + + // アクセスがこの TT と一致するか調べる。 + bool Match(busaddr addr) const; + bool e {}; // イネーブル bool ci {}; // キャッシュ禁止 + private: uint64 base {}; // ベース uint64 mask {}; // マスク - - // アクセスがこの TT と一致するか調べる。 - bool Match(busaddr addr) const; }; // TC レジスタの各フィールドを束ねた構造体のようなもの。 @@ -87,6 +107,9 @@ class m68030TC uint32 fcl {}; // TC_FCL の位置 uint ps {}; uint is {}; + + // 68030 のテーブルは最大4階層 (TIA 〜 TID) で、 + // TIA から termlv 段までが有効。 union { uint tix[4] {}; struct { @@ -97,15 +120,25 @@ class m68030TC } __packed; }; + int termlv {}; // 有効な段数 (例えば TIB までなら 2) int shift[4] {}; // TIA-TID の各部分のシフト量 uint32 mask[4] {}; // TIA-TID の各部分のマスク uint32 lmask {}; // TIA-TID 全体のマスク uint32 pgmask {}; // PS 部分のマスク public: - void Set(uint32); + // 値を代入し、二次変数も用意する。 + // 構成例外を起こすなら false を返す。 + bool Set(uint32); + + // (E に関わらず) 構成が有効なら true を返す。 + bool ConfigOK() const { return config_ok; } + + private: bool Check() const; void MakeMask(); + + bool config_ok {}; // (E に関わらず) 構成が有効なら true }; class m68030MMUSR @@ -125,22 +158,31 @@ class m68030MMUSR // ATC の1エントリ struct m68030ATCLine { - // tag - // LLLLLLLL'LLLLLLLL'LLLLLLLL'0000FFFI + // tag: + // 3 2 1 0 + // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + // +---------------+---------------+---------------+-------+-----+-+ + // | Logical Address [31:8] | 0 | FC |I| + // +---------------+---------------+---------------+-------+-----+-+ + // I: Invalid (%1で無効)。 + // FC: busaddr 形式の FC (210 の順) で、_Motorola のみで使用。 + // _Custom のほうは FC 別のテーブルなのでここは使わない。 // - // I は Invalid (%1で無効) - // L は論理アドレス - // F は busaddr 形式の FC (3ビット) だが、FC 別のテーブルなので未使用 + // paddr: + // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + // +---------------+---------------+---------------+---------------+ + // | Physical Address [31:8] | 0 | + // +---------------+---------------+---------------+---------------+ // - // paddr - // PPPPPPPP_PPPPPPPP_PPPPPPPP_00000000 : P は物理アドレス - // - // data - // 00000000_00000000_00000000_0000BCPM - // |||+-- Modified - // ||+--- Write Protect - // |+---- Cache Inhibit - // +----- Bus Error + // data: + // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + // +---------------+---------------+---------------+-------+-+-+-+-+ + // | 0 |B|C|P|M| + // +---------------+---------------+---------------+-------+-+-+-+-+ + // B: Bus Error + // C: Cache Inhibit + // P: Write Protect + // M: Modified static const uint32 LADDR_MASK = 0xffffff00; static const uint32 INVALID = 0x00000001; @@ -153,15 +195,20 @@ struct m68030ATCLine uint32 tag; uint32 paddr; uint32 data; +#if defined(M68030_CUSTOM_ATC) uint32 age; +#endif uint32 GetTag() const { return tag; } - void Invalidate() { tag |= INVALID; } + void Invalidate() { tag |= INVALID; } bool IsInvalid() const { return tag & INVALID; } bool IsValid() const { return !IsInvalid(); } uint32 GetLAddr() const { return tag & LADDR_MASK; } +#if !defined(M68030_CUSTOM_ATC) + uint32 GetFC() const { return (tag >> 1) & 7; } +#endif uint32 GetPAddr() const { return paddr; } bool IsBusError() const { return data & BUSERROR; } bool IsCInhibit() const { return data & CINHIBIT; } @@ -169,20 +216,52 @@ struct m68030ATCLine bool IsModified() const { return data & MODIFIED; } }; -// ATC の統計情報 +// ATCTable_* の共通部分だが、ポリモーフィズム (virtual) は使わずに書く。 +class m68030ATCTable +{ + public: + static constexpr int LINES = M68030_ATC_LINES; + + // 論理アドレスマスクを設定する。 + void SetMask(uint32 lmask_) { + lmask = lmask_; + } + + protected: + // デバッグ表示用 + static std::string LineToStrCommon(const m68030ATCLine *, uint fc); + + public: + int loglevel {}; + + protected: + // cpu->mmu_tc.lmask のコピー。 + uint32 lmask {}; + + MPU68030Device *cpu {}; +}; + +#if defined(M68030_CUSTOM_ATC) +// +// カスタム ATC。FC を分離し、TT と ATC を同時に検索する魔改造版。 +// + struct m68030ATCStat { - uint32 total {}; - uint32 tthit {}; - uint32 miss {}; + uint32 total {}; // アドレス変換した回数 (TC と TT 両方) + uint32 tthit {}; // TT にヒットした回数 + uint32 miss {}; // ATC ミスした回数 + + void Clear() { + total = 0; + tthit = 0; + miss = 0; + } }; -// ATC のテーブル -class m68030ATCTable final +class m68030ATCTable_Custom : public m68030ATCTable { public: - static const int LINES = 22; - // ATC ハッシュ enum : uint8 { HASH_ATC_BASE = 0, // ATC #0- @@ -191,8 +270,18 @@ class m68030ATCTable final HASH_SUB = 0xfd, // PS<4KB }; - m68030ATCTable(MPU680x0Device *cpu_, uint fc_); - ~m68030ATCTable(); + m68030ATCTable_Custom(MPU68030Device *cpu_, uint fc_); + + // 統計情報、移動平均等をリセットする。 + void ResetStat(); + + // ハッシュを完全に作り直す。 + void Rehash(); + + // 論理アドレスからタグを作成する。 + uint32 MakeTag(const busaddr laddr) const { + return (laddr.Addr() & lmask); + } // フラッシュ // Flush() はこのテーブルのすべてのエントリが対象。 @@ -200,26 +289,33 @@ class m68030ATCTable final void Flush(); void Flush(uint32 addr); + m68030ATCLine *Pop(); + // PS<4KB の時に ATC を検索。 m68030ATCLine *FindSub(const busaddr laddr); - // テーブルサーチ。 - // テーブルという用語がぶつかってしまったので MMU サーチと呼ぶ。 - m68030ATCLine *MMUSearch(busaddr laddr); - void Invalidate(m68030ATCLine *a); void InvalidateSub(const m68030ATCLine *); - void MakeHash(m68030ATCLine *); + void ClearHash(); + void MakeHash(const m68030ATCLine *); void MoveHead(m68030ATCLine *); - m68030ATCLine *RemoveTail(); // デバッグ表示 std::string LineToStr(const m68030ATCLine *a) const; - // ATC 実体 - m68030ATCLine line[LINES] {}; + // エントリの実体。 + std::array line {}; + // 統計情報。 + m68030ATCStat stat {}; + + // 移動平均用バッファ。(こっちは排他制御が必要) + FixedQueue hist {}; + bool hist_tt_once_hit {}; + std::mutex hist_mtx {}; + + private: uint32 latest_age {}; // このテーブルの FC @@ -228,46 +324,169 @@ class m68030ATCTable final // PS(ページのビット長) - 12。負数なら PS<4KB int ps4k {}; - // 統計 - m68030ATCStat atcstat {}; + public: + // ATC ハッシュ (他のメンバより後ろに置く?) + std::array hash {}; +}; - // 移動平均用バッファ。(こっちは排他制御が必要) - FixedQueue atchist {}; - bool atchist_tt_once_hit {}; - std::mutex atchist_mtx {}; +#else +// +// Motorola ATC +// - int loglevel {}; +struct m68030ATCStat +{ + // 先頭からn番目のヒット回数 + std::array hit {}; + // ATC 検索ミス回数 + uint64 miss {}; + + void Clear() { + hit = {}; + miss = 0; + } +}; - MPU680x0Device *cpu {}; +class m68030ATCTable_Motorola : public m68030ATCTable +{ + friend class MPU68030Device; - // ATC ハッシュ (他のメンバより後ろに置く?) - std::array hash {}; +#if defined(ATC_ORDER64) + static constexpr int ORDER0_COUNT = 12; + static constexpr int ORDER1_COUNT = M68030_ATC_LINES - ORDER0_COUNT; +#endif + + public: + explicit m68030ATCTable_Motorola(MPU68030Device *cpu_); + + // 統計情報、移動平均等をリセットする。 + void ResetStat(); + + // 論理アドレスからタグを作成する。 + uint32 MakeTag(const busaddr laddr) const { + return (laddr.Addr() & lmask) | (laddr.GetFC() << 1); + } + + // エントリのフラッシュ。(pflush* 命令から呼ばれる) + void Flush(); + void Flush(uint32 fc, uint32 mask); + void Flush(uint32 fc, uint32 mask, uint32 addr); + + // laddr を検索して見付かれば先頭に移動。 + m68030ATCLine *LookupAndMove(const busaddr laddr); + + // laddr を検索して見付かったのを返す。(PTEST 用) + const m68030ATCLine *LookupOnly(const busaddr laddr); + + // laddr を検索して返す。なければ NULL を返す。(デバッガ用) + const m68030ATCLine *LookupByDebugger(const busaddr laddr) { + // 今は Only と同じ。 + return LookupOnly(laddr); + } + + // 空きもしくは最も古いエントリを先頭に移動。 + m68030ATCLine *Pop(); + + // pri 番目の idx を返す。 + uint GetIdx(uint pri) const + { +#if defined(ATC_ORDER64) + if (__predict_true(pri < ORDER0_COUNT)) { + return (order[0] >> (pri * 5)) & 0x1f; + } else { + return (order[1] >> ((pri - ORDER0_COUNT) * 5)) & 0x1f; + } +#else + return order[pri]; +#endif + } + + // pri 番目のエントリを返す。 + m68030ATCLine *GetLine(uint pri) { + return &line[GetIdx(pri)]; + } + + // デバッグ表示 + static std::string LineToStr(const m68030ATCLine *); + + private: + // pri 番目の値を idx にする。 + void Set(uint pri, uint idx); + + int Lookup(const busaddr); + + // pri 番目の要素を先頭に移動。 + void MoveHead(uint pri); + // pri 番目の要素を末尾に移動。 + void MoveTail(uint pri); + + // エントリの実体。 + std::array line {}; + + // 順序管理。 +#if defined(ATC_ORDER64) + std::array order {}; +#else + std::array order {}; +#endif + + // 統計情報。 + m68030ATCStat stat {}; }; -// ATC (Address Translation Cache) -class m68030ATC final +#endif // M68030_CUSTOM_ATC + +class m68030ATC { public: - explicit m68030ATC(MPU680x0Device *); - ~m68030ATC(); + explicit m68030ATC(MPU68030Device *cpu_); // ログレベルを設定する。Object のとは同じ使い方だけど別物。 void SetLogLevel(int loglevel_); - // フラッシュ (pflush* 命令から呼ばれる) - void flush(); - void flush(uint32 fc, uint32 mask); - void flush(uint32 fc, uint32 mask, uint32 addr); - - // テーブルの実体。 - std::unique_ptr tables[4] {}; - - // FC ごとのテーブル。 - // 実際に使うのはこのうち4つだけ。 - std::array fctables {}; + // TC の設定変更に追従する。 + void SetTC(const m68030TC&); - int loglevel {}; +#if defined(M68030_CUSTOM_ATC) + // ハッシュを完全に作り直す。 + void Rehash(); +#endif + + // テーブルを取得する。 +#if defined(M68030_CUSTOM_ATC) + m68030ATCTable_Custom *GetTable(uint fc) { + assert((bool)fctables[fc]); + return fctables[fc]; + } +#else + m68030ATCTable_Motorola *GetTable() { + return table.get(); + } +#endif + + // エントリのフラッシュ。(pflush* 命令から呼ばれる) + void FlushAll(); + void Flush(uint32 fc, uint32 mask); + void Flush(uint32 fc, uint32 mask, uint32 addr); + + // 統計情報、移動平均等をリセットする。 + void ResetStat(); + + // 統計情報、移動平均等を更新する。 + void CalcStat(); private: - MPU680x0Device *cpu {}; +#if defined(M68030_CUSTOM_ATC) + // FC 別テーブルは 4つ。こっちはループで回せる。 + std::array, 4> alltables {}; + // fc で検索する場合。実際にはこのうち 4つだけが有効。 + std::array fctables {}; +#else + // テーブルは1つ。 + std::unique_ptr table {}; +#endif + + int loglevel {}; + + MPU68030Device *cpu {}; };