--- nono/m88xx0/m88200.h 2026/04/29 17:04:34 1.1 +++ nono/m88xx0/m88200.h 2026/04/29 17:05:56 1.1.1.13 @@ -8,16 +8,22 @@ #pragma once +#include "device.h" #include "bus.h" +#include "mainbus.h" #include -class m88kcpu; +#define M88200_STAT + +class MPU88xx0Device; +class MainbusDevice; // SAPR, UAPR レジスタ struct m88200APR { bool enable; uint32 addr; + // stat は ACC_STAT_MASK と同じ位置の WT,G,CI のみ使用。APR に WP はない。 uint32 stat; const char *name; // 自分の名前(ログ表示用) }; @@ -31,29 +37,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セット @@ -67,26 +93,25 @@ class m88200CacheSet IV = 3, // Invalid }; - // // 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 - // +---------------------------------------+---------------+----+---+ - // | tag | set |Word| | - // +---------------------------------------+---------------+----+---+ + // 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 + // +---------------------------------------+---------------+----+-+--+ + // | tag | set |word|0|~V| + // +---------------------------------------+---------------+----+-+--+ // タグはアドレスの上位 20ビット。 // ただし無効なラインかどうかのチェックも一度で済ませるために // 無効(vv[]==IV)ならビット 0 を 1 にしておく。比較対象の paddr は // 下位12ビットを落としているため、これで絶対に一致しなくなる。 static const uint32 TAG_INVALID = 0x00000001; - uint32 tag[4]; + uint32 tag[4] {}; // LRU // CSSP の L ビットのロジックに従う。 - int L {}; + uint L {}; // ステータス - Status vv[4]; + Status vv[4] {}; // データ。word[] は以下の順 // Word @@ -94,22 +119,22 @@ class m88200CacheSet // line0 [ 0] [ 1] [ 2] [ 3] // line1 [ 4] [ 5] [ 6] [ 7] // : - uint32 word[16]; + uint32 word[16] {}; // 自身のセットインデックス - uint32 setidx; + uint32 setidx {}; // 引数 L の状態から line を最新にしたらどうなるか、を返す。 // 表示処理で一時変数に対して処理が必要なため static 分離してある。 - static int TryUseLine(int L, int line); + static uint TryUseLine(uint tmpL, int line); // 引数 L の状態から line を最古にしたらどうなるか、を返す。 // 対称性のため static 分離してある。 - static int TryUnuseLine(int L, int line); + static uint TryUnuseLine(uint tmpL, int line); // 引数 L の状態で、最新の line を返す。 // 表示処理で一時変数に対して処理が必要なため static 分離してある。 - static int TryGetOldestLine(int L); + static int TryGetOldestLine(uint tmpL); void Use(int line) { L = TryUseLine(L, line); @@ -118,34 +143,37 @@ class m88200CacheSet // 更新用に最も古いラインを選んで差し出す int SelectOldestLine() const; - void Update(int line, Status status); + void Update(uint line, Status status); - uint64 ReadLine(int line, uint32 tagaddr); - - void Write(int line, uint32 paddr, uint32 data, int size); - - uint64 CopyBackLine(int line); + void Write(uint line, uint32 paddr, uint32 data, uint size); // キャッシュを検索して、ヒットした line を返す。 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(); - bool MonitorUpdate() override; - private: - m88kcpu *parent; + DECLARE_MONITOR_SCREEN(MonitorScreenReg); + DECLARE_MONITOR_SCREEN(MonitorScreenATC); + DECLARE_MONITOR_SCREEN(MonitorScreenCache); + + MPU88xx0Device *parent {}; + + // モニター + Monitor *reg_monitor {}; + Monitor *atc_monitor {}; + Monitor *cache_monitor {}; public: // @@ -162,16 +190,13 @@ class m88200 : public Object // ID はリセット時、下位7ビットはハードウェアで初期化、最上位ビットは // 0 で初期化。その後は全ビット変更可能。 // Type は $5 = 88200、$6 = 88204。ここでは 88200 固定。 - // Version は不明。 - uint32 id; - uint32 version; + uint32 id {}; + uint32 version {}; // 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_); @@ -181,7 +206,7 @@ class m88200 : public Object // +---------------------------------------------------+-----------+ // | reserved |CommandCode| // +---------------------------------------------------+-----------+ - uint32 command; + uint32 command {}; uint32 GetSCR() const; void SetSCR(uint32 val); private: @@ -190,8 +215,8 @@ class m88200 : public Object static const uint32 GG_PAGE = 1; static const uint32 GG_SEG = 2; static const uint32 GG_ALL = 3; - void FlushCache(); - void InvalidatePATC(); + void FlushCacheCmd(); + void InvalidatePATCCmd(); public: // SSR (System Status Register) +$008 @@ -212,7 +237,7 @@ class m88200 : public Object static const uint32 SSR_WP = 0x00000004; // Write Protection static const uint32 SSR_BH = 0x00000002; // BATC Hit static const uint32 SSR_V = 0x00000001; // Valid - uint32 ssr; + uint32 ssr {}; uint32 GetSSR() const { return ssr; } void SetSSR(uint32 val) { ssr = val; } @@ -222,7 +247,7 @@ class m88200 : public Object // +---------------------------------------------------------------+ // | Address | // +---------------------------------------------------------------+ - uint32 sar; + uint32 sar {}; uint32 GetSAR() const { return sar; } void SetSAR(uint32 val) { sar = val; } @@ -236,7 +261,7 @@ class m88200 : public Object static const uint32 SCTR_PE = 0x00008000; // Parity Enable static const uint32 SCTR_SE = 0x00004000; // Snoop Enable static const uint32 SCTR_PR = 0x00002000; // Priority Arbitration - uint32 sctr; + uint32 sctr {}; uint32 GetSCTR() const { return sctr; } void SetSCTR(uint32 val); @@ -258,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); } @@ -279,7 +305,7 @@ class m88200 : public Object static const uint32 FAULT_CODE_PAGE = 5; // Page Fault static const uint32 FAULT_CODE_SUPERVISOR = 6; // Supervisor Violation static const uint32 FAULT_CODE_WRITE = 7; // Write Violation - uint32 fault_code; + uint32 fault_code {}; uint32 GetPFSR() const { return fault_code << 16; } @@ -293,10 +319,15 @@ class m88200 : public Object // +---------------------------------------------------------------+ // | Address | // +---------------------------------------------------------------+ - uint32 fault_addr; + uint32 fault_addr {}; 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 @@ -304,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 @@ -361,28 +392,26 @@ 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(busaddr paddr); + busdata MBusWrite(busaddr paddr, uint32 data); + busdata MBusXmem(busaddr paddr, uint32 data); // // アクセス関数 // private: - template uint64 load(uint32 addr); - template uint64 store(uint32 addr, uint32 data); - template uint64 xmem(uint32 addr, uint32 data); + template busdata load(uint32 addr); + template busdata store(uint32 addr, uint32 data); + template busdata xmem(uint32 addr, uint32 data); public: - uint64 load_8(uint32 addr); - uint64 load_16(uint32 addr); - uint64 load_32(uint32 addr); - uint64 store_8(uint32 addr, uint32 data); - uint64 store_16(uint32 addr, uint32 data); - uint64 store_32(uint32 addr, uint32 data); - uint64 xmem_8(uint32 addr, uint32 data); - uint64 xmem_16(uint32 addr, uint32 data); - uint64 xmem_32(uint32 addr, uint32 data); + busdata load_1(uint32 addr); + busdata load_2(uint32 addr); + busdata load_4(uint32 addr); + busdata store_1(uint32 addr, uint32 data); + busdata store_2(uint32 addr, uint32 data); + busdata store_4(uint32 addr, uint32 data); + busdata xmem_1(uint32 addr, uint32 data); + busdata xmem_4(uint32 addr, uint32 data); // // 現在のアクセス中の状態。 @@ -428,12 +457,11 @@ class m88200 : public Object static const uint32 DESC_WP = 0x00000004; // Write Protect static const uint32 DESC_V = 0x00000001; // Valid + private: uint32 acc_laddr {}; // Logical Address - uint32 acc_paddrH {}; // Physical Address 上位30ビット。 - // 下位2ビットは 0 固定。 - uint32 acc_paddrL {}; // paddr の下位2ビット - // 上位30ビットは 0 固定。 + uint32 acc_paddr {}; // Physical Address + public: // acc_stat は 4 ビットのみ使用。 // それ以外のビットは代入時にマスクすること。 static const uint32 ACC_STAT_MASK = DESC_WT | DESC_G | DESC_CI | DESC_WP; @@ -446,27 +474,27 @@ class m88200 : public Object // pdaddr ... Page Descriptor Address // の2つに明確に分けて管理することにする。 uint32 acc_sdaddr {}; - uint32 acc_pdaddr {}; - bool acc_read; // True if read access + busaddr acc_pdaddr {}; + bool acc_read {}; // True if read access bool acc_IsWrite() const { return !acc_read; } // True if write access // 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 + uint32 tmp_desc {}; // TEMP_DESCR // // アドレス変換 // 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(); @@ -474,37 +502,119 @@ 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; + void MakeBATCHash(); + std::array batc {}; + // 検索用のハッシュ。値のビットN (0..9) が立っていれば batc[N] がこの + // ハッシュに当たることを示している (この後完全一致で比較する必要はある)。 + // [0x00] => 0b00'0000'0000; + std::array batc_hash_s {}; + std::array batc_hash_u {}; + // 現在の特権状態によって batc_hash_{s,u} のいずれかを指す。 + uint16 *batc_hash {}; + static int batc_hash_func(uint32 a) { + return (a >> 19) & 0x0f; + } + // 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 InvalidatePATCHash(int); std::array patc {}; + // 検索用のハッシュ。値のビット N (0..55) が立っていれば patc[N] がこの + // ハッシュに当たることを示している (この後完全一致で比較する必要はある)。 + std::array patc_hash_s {}; + std::array patc_hash_u {}; + // 現在の特権状態によって patc_hash_{s,u} のいずれかを指す。 + uint64 *patc_hash {}; + static int patc_hash_func(uint32 a) { + return (a >> 12) & 0xff; + } + // 空きエントリ。patc[N] が空いていればビット N を立てる。 + uint64 patc_free {}; + // 次回追加する位置。 + int patc_next {}; + + // 統計 + uint64 translate_total {}; + std::array batc_hit {}; + uint64 patc_hit {}; + uint64 atc_miss {}; +#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 の総数 + uint64 stat_patc_search {}; // ハッシュを引いた回数 + uint64 stat_patc_miss1 {}; // ハッシュだけでミスした回数 + uint64 stat_patc_miss2 {}; // ビットを調べてミスした回数 + std::array stat_batc_hash_s {}; // BATC.S の衝突状況 + std::array stat_batc_hash_u {}; // BATC.U の衝突状況 +#endif + // + // 物理アドレスアクセス + // + busdata PhysRead(busaddr paddr, uint32 stat); + busdata PhysWrite(busaddr paddr, uint32 data, uint32 stat); // // キャッシュ // - + private: std::array setarray {}; + // キャッシュラインにメモリから読み込む + bool ReadLine(m88200CacheSet& set, uint line, uint32 tagaddr); + // キャッシュラインをメモリに書き出す + bool CopyBackLine(m88200CacheSet& set, uint line); // キャッシュに対して paddr の読み込みを行う - uint64 CacheRead(uint32 paddr); + busdata CacheRead(uint32 paddr); // キャッシュに対して paddr への書き込みを行う - uint64 CacheWrite(uint32 paddr, uint32 data, int size); - uint64 CacheWriteHit(m88200CacheSet& set, int line, - uint32 paddr, uint32 data, int size); - uint64 CacheXmem(uint32 paddr, uint32 data, int size); + busdata CacheWrite(uint32 paddr, uint32 data, uint size); + busdata CacheWriteHit(m88200CacheSet& set, uint line, + uint32 paddr, uint32 data, uint size); + busdata CacheXmem(uint32 paddr, uint32 data, uint size); + public: // モニタスクリーン作成用 - void MonitorCacheSet(TextScreen&, int y, int setidx); - void MonitorCacheOverview(TextScreen&, int y, int cursor, bool is_gui); + void MonitorCacheSet(TextScreen&, int y, uint setidx); + void MonitorCacheOverview(TextScreen&, int y, uint cursor, bool is_gui); void MonitorCacheOverview(TextScreen& s, int y, bool is_gui) { MonitorCacheOverview(s, y, -1, is_gui); } + // + // MBus + // + public: + // MBus を所有している CMMU を返す。誰も持っていなければ NULL。 + // これは static 関数 + static m88200 *GetBusMaster() { return mbus_master; } + private: - // まだない - void MBusAcquire() { } + static constexpr bool IM_0 = false; + static constexpr bool IM_1 = true; + void MBusAcquire(); void MBusRelease() { } + // 他 CMMU にスヌープさせる (バスマスタ側) + void MBusMakeSnoop(uint32 addr, bool im); + // バススヌープを行う (スレーブ側) + void Snoop(uint32 addr, bool im); + + MainbusDevice *mainbus {}; + + // MBus を所有してる CMMU を指す。NULL なら解放。 + // これは static 変数で全 m88200 で共有している + static m88200 *mbus_master; + + // スヌープ相手の CMMU リスト + std::vector other_cmmu {}; };