--- nono/m680x0/m68030mmu.h 2026/04/29 17:05:15 1.1.1.6 +++ nono/m680x0/m68030mmu.h 2026/04/29 17:05:57 1.1.1.11 @@ -6,12 +6,30 @@ #pragma once -class MPU680x0Device; +#include +#include +#include "fixedqueue.h" + +// ATC 実装種別。 +//#define M68030_CUSTOM_ATC +#define ATC_ORDER64 -// ATC_SINGLE は過去との比較のために残してある、双方向リストによる -// FC 混合 22 エントリ実装。 -// 定義しない場合(デフォルト)は、FC 別の世代付き配列みたいなもの。 -//#define ATC_SINGLE 1 +// 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 @@ -19,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 @@ -28,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 @@ -55,19 +71,30 @@ class m68030TT static const uint32 FCBASE_MASK = 0x00000070; static const uint32 FCMASK_MASK = 0x00000007; - uint32 e {}; // 00008000 イネーブル - uint32 ci {}; // 00000400 キャッシュ禁止 - uint64 base {}; // ベース - uint64 mask {}; // マスク + void Set(uint32 data); // アクセスがこの TT と一致するか調べる。 - bool Match(uint64 ssw_laddr) const; + bool Match(busaddr addr) const; + + bool e {}; // イネーブル + bool ci {}; // キャッシュ禁止 + private: + uint64 base {}; // ベース + uint64 mask {}; // マスク }; // TC レジスタの各フィールドを束ねた構造体のようなもの。 // m68kcpu::SetTC(), GetTC() で読み書きする。 class m68030TC { + // 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 + // +-+---------+-+-+-------+-------+-------+-------+-------+-------+ + // |E| 0 |S|F| PS | IS | TIA | TIB | TIC | TID | + // +-+---------+-+-+-------+-------+-------+-------+-------+-------+ + // | | +-- FCL (Function Code Lookup Enable) + // | +---- SRE (Supervisor Root Pointer Enable) + // +-- Enable public: static const uint32 MASK = 0x83ffffff; static const uint32 TC_E = 0x80000000; @@ -80,6 +107,9 @@ class m68030TC uint32 fcl {}; // TC_FCL の位置 uint ps {}; uint is {}; + + // 68030 のテーブルは最大4階層 (TIA 〜 TID) で、 + // TIA から termlv 段までが有効。 union { uint tix[4] {}; struct { @@ -90,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 @@ -118,20 +158,31 @@ class m68030MMUSR // ATC の1エントリ struct m68030ATCLine { - // 1エントリはタグとデータの計64ビット。 - // - // タグ - // LLLLLLLL_LLLLLLLL_LLLLLLLL_0000000I : L は論理アドレス - // +-- invalid (%1で無効) + // 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 別のテーブルなのでここは使わない。 // - // 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 | + // +---------------+---------------+---------------+---------------+ // - // データ - // PPPPPPPP_PPPPPPPP_PPPPPPPP_0000BCPM : P は物理アドレス - // |||+-- 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; @@ -142,128 +193,300 @@ struct m68030ATCLine static const uint32 MODIFIED = 0x00000001; uint32 tag; -#if defined(ATC_SINGLE) - uint32 fc; -#endif 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; } bool IsWProtect() const { return data & WPROTECT; } bool IsModified() const { return data & MODIFIED; } +}; -#if !defined(ATC_SINGLE) - // LRU 用カウンタ - uint32 age; -#else - m68030ATCLine *prev; - m68030ATCLine *next; -#endif +// ATCTable_* の共通部分だが、ポリモーフィズム (virtual) は使わずに書く。 +class m68030ATCTable +{ + public: + static constexpr int LINES = M68030_ATC_LINES; - // デバッグ表示 - std::string fill_print(uint fc); + // 論理アドレスマスクを設定する。 + 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 {}; // アドレス変換した回数 (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- + HASH_NONE = 0xff, // 対応なし + HASH_TT = 0xfe, // TT + HASH_SUB = 0xfd, // PS<4KB + }; + + m68030ATCTable_Custom(MPU68030Device *cpu_, uint fc_); + + // 統計情報、移動平均等をリセットする。 + void ResetStat(); + + // ハッシュを完全に作り直す。 + void Rehash(); - m68030ATCTable(); - ~m68030ATCTable(); + // 論理アドレスからタグを作成する。 + uint32 MakeTag(const busaddr laddr) const { + return (laddr.Addr() & lmask); + } + + // フラッシュ + // Flush() はこのテーブルのすべてのエントリが対象。 + // Flush(addr) はこのテーブルのアドレスが一致するエントリが対象。 + void Flush(); + void Flush(uint32 addr); + + m68030ATCLine *Pop(); + + // PS<4KB の時に ATC を検索。 + m68030ATCLine *FindSub(const busaddr laddr); + + void Invalidate(m68030ATCLine *a); + void InvalidateSub(const m68030ATCLine *); + + void ClearHash(); + void MakeHash(const m68030ATCLine *); + void MoveHead(m68030ATCLine *); + + // デバッグ表示 + std::string LineToStr(const m68030ATCLine *a) const; + + // エントリの実体。 + std::array line {}; + + // 統計情報。 + m68030ATCStat stat {}; + + // 移動平均用バッファ。(こっちは排他制御が必要) + FixedQueue hist {}; + bool hist_tt_once_hit {}; + std::mutex hist_mtx {}; + + private: + uint32 latest_age {}; + + // このテーブルの FC + uint fc {}; + + // PS(ページのビット長) - 12。負数なら PS<4KB + int ps4k {}; + + public: + // ATC ハッシュ (他のメンバより後ろに置く?) + std::array hash {}; +}; -#if !defined(ATC_SINGLE) - // 空きエントリを取得。 - m68030ATCLine *Lookup(); - // a をエントリの先頭に - m68030ATCLine *MoveHead(m68030ATCLine *a); #else - // 空きエントリを取得。 - m68030ATCLine *lookup(); - // LRU の先頭、2番目に追加 - void insert_head(m68030ATCLine *); - void insert_second(m68030ATCLine *); - // LRU の先頭、2番目に移動 - void move_head(m68030ATCLine *); - void move_second(m68030ATCLine *); - // LRU の末尾に追加 - void insert_tail(m68030ATCLine *); - // LRU から削除 - void remove(m68030ATCLine *); +// +// Motorola ATC +// + +struct m68030ATCStat +{ + // 先頭からn番目のヒット回数 + std::array hit {}; + // ATC 検索ミス回数 + uint64 miss {}; + + void Clear() { + hit = {}; + miss = 0; + } +}; + +class m68030ATCTable_Motorola : public m68030ATCTable +{ + friend class MPU68030Device; + +#if defined(ATC_ORDER64) + static constexpr int ORDER0_COUNT = 12; + static constexpr int ORDER1_COUNT = M68030_ATC_LINES - ORDER0_COUNT; #endif - // フラッシュ - // flush() はこのテーブルのすべてのエントリが対象。 - // flush(addr) はこのテーブルのアドレスが一致するエントリが対象。 - // flush_fc(fc) はこのテーブルの FC が fc であるエントリが対象。 - // flush(fc, addr) はこのテーブルの fc と addr が一致するエントリが対象。 - // いずれも ATC クラスから呼ばれるが、ATC_SINGLE によって、一致する FC が - // 呼び出し前に決定されているかこちらで比較しないといけないかが変わる。 - void flush(); -#if !defined(ATC_SINGLE) - void flush(uint32 addr); + 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 - void flush_fc(uint32 fc); - void flush(uint32 fc, uint32 addr); + return order[pri]; #endif + } + + // pri 番目のエントリを返す。 + m68030ATCLine *GetLine(uint pri) { + return &line[GetIdx(pri)]; + } + + // デバッグ表示 + static std::string LineToStr(const m68030ATCLine *); - // ATC 実体 - m68030ATCLine line[LINES] {}; + private: + // pri 番目の値を idx にする。 + void Set(uint pri, uint idx); - // 先頭から何エントリ目でヒットしたかの統計。最後の +1 はキャッシュミス。 - uint64 hit[LINES + 1] {}; + int Lookup(const busaddr); - // ATC_SINGLE ならリストの先頭。 - // !ATC_SINGLE なら注目エントリ。 - m68030ATCLine *head {}; - -#if !defined(ATC_SINGLE) - // LRU 用の更新カウンタ - uint32 counter = 0; - // head のヒット回数。 - uint64 hit_head = 0; + // 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 { - friend class MPU680x0Device; public: - m68030ATC(MPU680x0Device *); - ~m68030ATC(); + explicit m68030ATC(MPU68030Device *cpu_); - // エントリをサーチ&更新 - const m68030ATCLine& fill_fetch(); - const m68030ATCLine& fill_read(); - const m68030ATCLine& fill_write(); - // デバッグ用にエントリを検索 - const m68030ATCLine *fill_peek(uint32 laddr, uint fc); - - // フラッシュ (pflush* 命令から呼ばれる) - void flush(); - void flush(uint32 fc, uint32 mask); - void flush(uint32 fc, uint32 mask, uint32 addr); + // ログレベルを設定する。Object のとは同じ使い方だけど別物。 + void SetLogLevel(int loglevel_); + + // TC の設定変更に追従する。 + void SetTC(const m68030TC&); + +#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: -#if !defined(ATC_SINGLE) - // FC ごとのテーブル。 - // 8個確保してあるが実際に使うのはこのうち4つだけ。 - m68030ATCTable tables[8] {}; +#if defined(M68030_CUSTOM_ATC) + // FC 別テーブルは 4つ。こっちはループで回せる。 + std::array, 4> alltables {}; + // fc で検索する場合。実際にはこのうち 4つだけが有効。 + std::array fctables {}; #else - // FC 混合のテーブル。 - m68030ATCTable tables[1] {}; + // テーブルは1つ。 + std::unique_ptr table {}; #endif - MPU680x0Device *cpu {}; + int loglevel {}; + + MPU68030Device *cpu {}; };