--- nono/m680x0/m68030mmu.h 2026/04/29 17:04:40 1.1.1.3 +++ nono/m680x0/m68030mmu.h 2026/04/29 17:05:35 1.1.1.10 @@ -6,10 +6,11 @@ #pragma once -// ATC_SINGLE は過去との比較のために残してある、双方向リストによる -// FC 混合 22 エントリ実装。 -// 定義しない場合(デフォルト)は、FC 別の世代付き配列みたいなもの。 -//#define ATC_SINGLE 1 +#include +#include +#include "fixedqueue.h" + +class MPU68030Device; // SRP, CRP class m68030RP @@ -26,12 +27,13 @@ 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 レジスタの各フィールドを束ねた構造体のようなもの。 -// m68kcpu::SetTT(), GetTT() で読み書きする。 +// MPU68030Device::SetTT(), GetTT() で読み書きする。 class m68030TT { // 3 2 1 0 @@ -52,19 +54,27 @@ class m68030TT static const uint32 FCBASE_MASK = 0x00000070; static const uint32 FCMASK_MASK = 0x00000007; - uint32 e {}; // 00008000 イネーブル - uint32 ci {}; // 00000400 キャッシュ禁止 + bool e {}; // イネーブル + bool ci {}; // キャッシュ禁止 uint64 base {}; // ベース uint64 mask {}; // マスク // アクセスがこの TT と一致するか調べる。 - bool Match(uint64 ssw_laddr); + bool Match(busaddr addr) const; }; // 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; @@ -115,16 +125,18 @@ class m68030MMUSR // ATC の1エントリ struct m68030ATCLine { - // 1エントリはタグとデータの計64ビット。 + // tag + // LLLLLLLL'LLLLLLLL'LLLLLLLL'0000FFFI // - // タグ - // LLLLLLLL_LLLLLLLL_LLLLLLLL_0000000I : L は論理アドレス - // +-- invalid (%1で無効) + // I は Invalid (%1で無効) + // L は論理アドレス + // F は busaddr 形式の FC (3ビット) だが、FC 別のテーブルなので未使用 // - // FC はテーブル選択の時点で確定しているのでタグには不要。 + // paddr + // PPPPPPPP_PPPPPPPP_PPPPPPPP_00000000 : P は物理アドレス // - // データ - // PPPPPPPP_PPPPPPPP_PPPPPPPP_0000BCPM : P は物理アドレス + // data + // 00000000_00000000_00000000_0000BCPM // |||+-- Modified // ||+--- Write Protect // |+---- Cache Inhibit @@ -139,11 +151,9 @@ struct m68030ATCLine static const uint32 MODIFIED = 0x00000001; uint32 tag; -#if defined(ATC_SINGLE) - uint32 fc; -#endif uint32 paddr; uint32 data; + uint32 age; uint32 GetTag() const { return tag; } @@ -157,17 +167,14 @@ struct m68030ATCLine 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 - - // デバッグ表示 - void fill_print(uint fc); +// ATC の統計情報 +struct m68030ATCStat +{ + uint32 total {}; + uint32 tthit {}; + uint32 miss {}; }; // ATC のテーブル @@ -176,101 +183,91 @@ class m68030ATCTable final public: static const int LINES = 22; - m68030ATCTable(); - ~m68030ATCTable() { } + // ATC ハッシュ + enum : uint8 { + HASH_ATC_BASE = 0, // ATC #0- + HASH_NONE = 0xff, // 対応なし + HASH_TT = 0xfe, // TT + HASH_SUB = 0xfd, // PS<4KB + }; -#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 *); -#endif + m68030ATCTable(MPU68030Device *cpu_, uint fc_); + ~m68030ATCTable(); // フラッシュ - // 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); -#else - void flush_fc(uint32 fc); - void flush(uint32 fc, uint32 addr); -#endif + // Flush() はこのテーブルのすべてのエントリが対象。 + // Flush(addr) はこのテーブルのアドレスが一致するエントリが対象。 + void Flush(); + void Flush(uint32 addr); + + // PS<4KB の時に ATC を検索。 + m68030ATCLine *FindSub(const busaddr laddr); + + // テーブルサーチ。 + // テーブルという用語がぶつかってしまったので MMU サーチと呼ぶ。 + m68030ATCLine *MMUSearch(busaddr laddr); + + void Invalidate(m68030ATCLine *a); + void InvalidateSub(const m68030ATCLine *); + + void MakeHash(const m68030ATCLine *); + void MoveHead(m68030ATCLine *); + m68030ATCLine *RemoveTail(); + + // デバッグ表示 + std::string LineToStr(const m68030ATCLine *a) const; // ATC 実体 m68030ATCLine line[LINES] {}; - // 先頭から何エントリ目でヒットしたかの統計。最後の +1 はキャッシュミス。 - uint64 hit[LINES + 1] {}; + uint32 latest_age {}; + + // このテーブルの FC + uint fc {}; + + // PS(ページのビット長) - 12。負数なら PS<4KB + int ps4k {}; + + // 統計 + m68030ATCStat atcstat {}; + + // 移動平均用バッファ。(こっちは排他制御が必要) + FixedQueue atchist {}; + bool atchist_tt_once_hit {}; + std::mutex atchist_mtx {}; + + int loglevel {}; - // ATC_SINGLE ならリストの先頭。 - // !ATC_SINGLE なら注目エントリ。 - m68030ATCLine *head {}; - -#if !defined(ATC_SINGLE) - // LRU 用の更新カウンタ - uint32 counter = 0; - // head のヒット回数。 - uint64 hit_head = 0; -#endif + MPU68030Device *cpu {}; + + // ATC ハッシュ (他のメンバより後ろに置く?) + std::array hash {}; }; // ATC (Address Translation Cache) class m68030ATC final { - friend class MPUATC; public: - m68030ATC(m68kcpu *); - ~m68030ATC() { } + explicit m68030ATC(MPU68030Device *); + ~m68030ATC(); - // エントリをサーチ&更新 - const m68030ATCLine& fill_fetch(); - const m68030ATCLine& fill_read(); - const m68030ATCLine& fill_write(); - // デバッグ用にエントリを検索 - uint64 fill_peek(uint32 laddr, uint fc); + // ログレベルを設定する。Object のとは同じ使い方だけど別物。 + void SetLogLevel(int loglevel_); // フラッシュ (pflush* 命令から呼ばれる) void flush(); void flush(uint32 fc, uint32 mask); void flush(uint32 fc, uint32 mask, uint32 addr); - private: -#if !defined(ATC_SINGLE) + // テーブルの実体。 + std::unique_ptr tables[4] {}; + // FC ごとのテーブル。 - // 8個確保してあるが実際に使うのはこのうち4つだけ。 - m68030ATCTable tables[8] {}; -#else - // FC 混合のテーブル。 - m68030ATCTable tables[1] {}; -#endif + // 実際に使うのはこのうち4つだけ。 + std::array fctables {}; - m68kcpu *cpu {}; -}; + int loglevel {}; -extern bool m68030_mmu_translate_fetch(m68kcpu *cpu); -extern bool m68030_mmu_translate_read(m68kcpu *cpu); -extern bool m68030_mmu_translate_write(m68kcpu *cpu); -extern uint64 m68030_mmu_translate_peek(m68kcpu *cpu, uint32 laddr, uint fc, - bool do_search); -extern void mmu_op_pflush(m68kcpu *cpu); -extern void mmu_op_pflush_ea(m68kcpu *cpu); -extern void mmu_op_pload(m68kcpu *cpu); -extern void mmu_op_ptest(m68kcpu *cpu); + private: + MPU68030Device *cpu {}; +};