--- nono/m88xx0/m88200.h 2026/04/29 17:04:41 1.1.1.3 +++ nono/m88xx0/m88200.h 2026/04/29 17:05:22 1.1.1.9 @@ -8,10 +8,14 @@ #pragma once +#include "device.h" #include "bus.h" +#include "mainbus.h" +#include "monitor.h" #include -class m88kcpu; +class MPU88xx0Device; +class MainbusDevice; // SAPR, UAPR レジスタ struct m88200APR @@ -31,29 +35,49 @@ struct m88200BATC // +-------------------------+-------------------------+-+-------+--+ // | LBA | 0 |S| 0 |~V| // +-------------------------+-------------------------+-+-------+--+ - uint32 lba; // LBA,S,V + static const uint32 LBAMASK = 0xfff80000; + static const uint32 S = 0x00000020; + static const uint32 INVALID = 0x00000001; + uint32 lba; // LBA,S,~V uint32 pba; // PBA // stat は ACC_STAT_MASK と同じ WT,G,CI,WP のみ使用。 - // BATC (BWP レジスタ) のビット位置とは違うので注意。 + // BWP (BATC Write Port) のビット位置とは違うので注意。 uint32 stat; bool wp; // WP (比較で使うのでこれだけ抜き出しておく) + + // このエントリが有効なら true を返す + bool IsValid() const { return (lba & INVALID) == 0; } + // S ビットが立っていれば true を返す + bool IsS() const { return (lba & S); } + // 論理アドレス(32ビット)を返す + uint32 Laddr() const { return (lba & LBAMASK); } }; // PATC struct m88200PATC { - // LPA には S ビットと有効/無効情報を混ぜておく。比較を1回で済ませるため。 + // LPA には S, V ビットを混ぜておく。比較を1回で済ませるため。 // V ビットは invalid なら %1 にして一致しなくしておく。実際の // PATC エントリの有効/無効は 46ビットの PATC 構造の外で管理されている? // 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 // +---------------------------------------+-----------+-+-------+--+ - // | LPA | |S| 0 |~V| + // | LPA | 0 |S| 0 |~V| // +---------------------------------------+-----------+-+-------+--+ - uint32 lpa; // LPA,S,(V) + static const uint32 LPAMASK = 0xfffff000; + static const uint32 S = 0x00000020; + static const uint32 INVALID = 0x00000001; + uint32 lpa; // LPA,S,~V uint32 pfa; // PFA uint32 stat; // ACC_STAT_MASK と同じ WT,G,CI,WP のみ使用。 bool m; // Modified bool wp; // Write Protect (比較で使うのでこれだけ抜き出しておく) + + // このエントリが有効なら true を返す + bool IsValid() const { return (lpa & INVALID) == 0; } + // S ビットが立っていれば true を返す + bool IsS() const { return (lpa & S); } + // 論理アドレス(32ビット)を返す + uint32 Laddr() const { return (lpa & LPAMASK); } }; // キャッシュの1セット @@ -126,22 +150,29 @@ class m88200CacheSet int Lookup(uint32 tagaddr) const; }; -class m88200 : public Object +class m88200 : public Device { + using inherited = Device; public: - m88200(); + m88200(MPU88xx0Device *parent_, uint id_); ~m88200() override; - // 本当はコンストラクタ渡ししたかったもの - void Ctor(m88kcpu *parent_); + bool Init() override; - // リセット + // リセット (ResetHard() ではない) void Reset(); - void MonitorUpdate(TextScreen&) override; - private: - m88kcpu *parent {}; + DECLARE_MONITOR_CALLBACK(MonitorUpdateReg); + DECLARE_MONITOR_CALLBACK(MonitorUpdateATC); + DECLARE_MONITOR_CALLBACK(MonitorUpdateCache); + + MPU88xx0Device *parent {}; + + // モニター + Monitor reg_monitor { this }; + Monitor atc_monitor { this }; + Monitor cache_monitor { this }; public: // @@ -164,10 +195,8 @@ class m88200 : public Object // IDR レジスタの内容を返す uint32 GetIDR() const { - return (id << 24) | (0x5 << 21); + return (id << 24) | (0x5 << 21) | (version << 16); } - // ID を設定する (IDR ではない) - void SetID(uint id_); // Version フィールドを設定する void SetVersion(uint version_); @@ -254,11 +283,12 @@ class m88200 : public Object private: uint32 GetAPR(const m88200APR&) const; void SetAPR(m88200APR&, uint32 data); + // 現在の xAPR + const m88200APR *acc_apr {}; public: uint32 GetAPR(uint issuper) const; uint32 GetUAPR() const { return GetAPR(uapr); } uint32 GetSAPR() const { return GetAPR(sapr); } - void SetAPR(uint issuper, uint32 data); void SetUAPR(uint32 data) { SetAPR(uapr, data); } void SetSAPR(uint32 data) { SetAPR(sapr, data); } @@ -293,6 +323,11 @@ class m88200 : public Object uint32 GetPFAR() const { return fault_addr; } void SetPFAR(uint32 val) { fault_addr = val; } + void SetFault(uint32 code_, uint32 addr_) { + fault_code = code_; + fault_addr = addr_; + } + // BWP0-7 (BATC Write Ports 0..7) +$400..+$41c // 3 2 1 // 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 @@ -300,17 +335,17 @@ class m88200 : public Object // | | |S|W|G|C|W|V| // | Logical Block Address | Physical Block Address | |T| |I|P| | // +---------------------------------------------------------------+ - static const uint32 BATC_LBA_MASK = 0xfff80000; - static const uint32 BATC_PBA_MASK = 0x0007ffc0; - static const uint32 BATC_S = 0x00000020; // Address Space - static const uint32 BATC_WT = 0x00000010; // WriteThrough - static const uint32 BATC_G = 0x00000008; // Global - static const uint32 BATC_CI = 0x00000004; // Cache Inhibit - static const uint32 BATC_WP = 0x00000002; // Write Protect - static const uint32 BATC_V = 0x00000001; // Valid - std::array batc {}; - uint32 GetBATC(uint n) const; - void SetBATC(uint n, uint32 val); + static const uint32 BWP_LBA_MASK = 0xfff80000; + static const uint32 BWP_PBA_MASK = 0x0007ffc0; + static const uint32 BWP_FLAG_MASK = 0x0000003f; + static const uint32 BWP_S = 0x00000020; // Address Space + static const uint32 BWP_WT = 0x00000010; // WriteThrough + static const uint32 BWP_G = 0x00000008; // Global + static const uint32 BWP_CI = 0x00000004; // Cache Inhibit + static const uint32 BWP_WP = 0x00000002; // Write Protect + static const uint32 BWP_V = 0x00000001; // Valid + void SetBWP(uint n, uint32 val); + void SetBATC(uint n, uint32 laddr, uint32 paddr, uint32 flags); // CDP0-3 (Cache Data Ports 0..3) +$800..+$80c // 3 2 1 @@ -358,9 +393,9 @@ class m88200 : public Object // 物理バスアクセス // // XXX size をどうするか - uint64 MBusRead(uint32 paddr, int size); - uint64 MBusWrite(uint32 paddr, uint32 data, int size); - uint64 MBusXmem(uint32 paddr, uint32 data, int size); + busdata MBusRead(uint32 paddr, int size); + busdata MBusWrite(uint32 paddr, uint32 data, int size); + busdata MBusXmem(uint32 paddr, uint32 data, int size); // // アクセス関数 @@ -424,12 +459,16 @@ class m88200 : public Object static const uint32 DESC_WP = 0x00000004; // Write Protect static const uint32 DESC_V = 0x00000001; // Valid + uint32 GetLaddr() const { return acc_laddr; } + uint32 GetPaddr() const { return acc_paddrH | acc_paddrL; } + private: uint32 acc_laddr {}; // Logical Address uint32 acc_paddrH {}; // Physical Address 上位30ビット。 // 下位2ビットは 0 固定。 uint32 acc_paddrL {}; // paddr の下位2ビット // 上位30ビットは 0 固定。 + public: // acc_stat は 4 ビットのみ使用。 // それ以外のビットは代入時にマスクすること。 static const uint32 ACC_STAT_MASK = DESC_WT | DESC_G | DESC_CI | DESC_WP; @@ -449,11 +488,11 @@ class m88200 : public Object // S/U 信号線 // 実際には P Bus の Address フェーズで毎回送られてくるが // そうそう変わらないので状態変化を通知してもらう方式。 - // true なら super, false なら user。 - bool acc_super {}; - void SetSuper(bool super) { - acc_super = super; - } + // acc_super は S か U のみ。 + busaddr acc_super {}; + void SetSuper(bool super); + bool IsSuper() const { return acc_super.IsSuper(); } + bool IsUser() const { return !IsSuper(); } m88200PATC *acc_patc {}; // ヒットした PATC エントリ uint32 tmp_desc {}; // TEMP_DESCR @@ -462,7 +501,7 @@ class m88200 : public Object // アドレス変換 // bool Translate(); - uint64 TranslatePeek(uint32 laddr, bool issuper, bool do_search) const; + busaddr TranslatePeek(busaddr laddr) const; private: static std::string stat2str(uint32 stat); bool SelectAreaDesc(); @@ -470,13 +509,53 @@ class m88200 : public Object bool FetchSegmentDesc(); bool FetchPageDesc(); bool UpdatePageDesc(); - void CreatePATCEntry(); - public: + // BATC + static const uint32 BATC_LBA_MASK = BWP_LBA_MASK; + static const uint32 BATC_S = m88200BATC::S; + static const uint32 BATC_INVALID = m88200BATC::INVALID; + std::array batc {}; + // PATC - static const uint32 PATC_S = 0x00000020; // Supervisor + static const uint32 PATC_S = m88200PATC::S; + static const uint32 PATC_INVALID = m88200PATC::INVALID; + void CreatePATCEntry(); + void InvalidatePATCEntry(m88200PATC&); std::array patc {}; + // 次回追加する位置 + int patc_next {}; + // BATC/PATC 混合のハッシュ。 + // 1エントリが 4KB の1ページを示し、4GB のメモリ空間全体あるので + // 1M 個 (x User/Supervisor で2倍)。 + // 各エントリは1バイトで、内容は以下の通り。 + // 0: BATC/PATC なし + // 0xff-0xf6: BATC #(~n) + // 1-56: PATC #(n-1) + // BATC は重複して設定することも可能だが、してはいけないとマニュアルに + // 書いてあるので、ここでも動作不定でよいことにする。 + // 前半 (0x00'0000..0x0f'ffff) が User モード用、 + // 後半 (0x10'0000..0x1f'ffff) が Supervisor モード用。 + inline uint32 addr2hash(bool issuper, uint32 addr) const; + void DumpATC(); + std::array atc_hash_all {}; + // 現在の特権状態によって atc_hash_all の [0] か [0x10'0000] を指す。 + uint8 *atc_hash {}; + + // 統計 + uint64 translate_total {}; + std::array batc_hit {}; + uint64 patc_hit {}; + uint64 atc_miss {}; +#define M88200_STAT +#if defined(M88200_STAT) + // 開発用の統計 + uint64 stat_patc_create {}; // エントリ作成回数 + uint64 stat_patc_invcmd_all {}; // Invalidate ALL 発行回数 + uint64 stat_patc_invcmd_seg {}; // Invalidate Segment 発行回数 + uint64 stat_patc_invcmd_page {}; // Invalidate Page 発行回数 + uint64 stat_patc_invalidate {}; // 無効にした PATC の総数 +#endif // // キャッシュ @@ -508,18 +587,24 @@ class m88200 : public Object // MBus // public: - // MBus を所有している CMMU ID を返す。誰も持っていなければ -1。 + // MBus を所有している CMMU を返す。誰も持っていなければ NULL。 // これは static 関数 static m88200 *GetBusMaster() { return mbus_master; } - // この CMMU からのアクセスにウェイトを加算する (VM から使う) - void AddCycle(uint64 cycle); - private: void MBusAcquire(); void MBusRelease() { } + // 他 CMMU にスヌープさせる (バスマスタ側) + void MBusMakeSnoop(uint32, int); + // バススヌープを行う (スレーブ側) + void Snoop(uint32, int); + + MainbusDevice *mainbus {}; // MBus を所有してる CMMU を指す。NULL なら解放。 // これは static 変数で全 m88200 で共有している static m88200 *mbus_master; + + // スヌープ相手の CMMU リスト + std::vector other_cmmu {}; };