|
|
1.1 root 1: //
2: // nono
1.1.1.2 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #pragma once
8:
1.1.1.8 root 9: #include <array>
10: #include <mutex>
11: #include "fixedqueue.h"
1.1.1.6 root 12:
1.1.1.11! root 13: // ATC 実装種別。
! 14: //#define M68030_CUSTOM_ATC
! 15: #define ATC_ORDER64
! 16:
! 17: // ATC エントリ数。
! 18: #define M68030_ATC_LINES (22)
! 19:
! 20: #if defined(M68030_CUSTOM_ATC)
! 21: #else
! 22: # if defined(ATC_ORDER64)
! 23: # if M68030_ATC_LINES > 24
! 24: # error M68030_ATC_LINES must be <= 24 on ATC_ORDER64.
! 25: # endif
! 26: # if M68030_ATC_LINES < 13
! 27: # error M68030_ATC_LINES must be >= 13 on ATC_ORDER64.
! 28: # endif
! 29: # endif
! 30: #endif
! 31:
1.1.1.9 root 32: class MPU68030Device;
1.1 root 33:
34: // SRP, CRP
35: class m68030RP
36: {
37: // 6 5 4 3
38: // 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
39: // +-+-----------------------------+---------------------------+---+
1.1.1.11! root 40: // |U| LIMIT | 0 |DT |
1.1 root 41: // +-+-----------------------------+---------------------------+---+
42: //
43: // 3 2 1 0
44: // 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
45: // +-------------------------------------------------------+-------+
46: // | TABLE ADDRESS (PA31-PA4) |unused |
47: // +-------------------------------------------------------+-------+
48: public:
49: static const uint32 H_MASK = 0xffff0003;
50: };
51:
52: // TT レジスタの各フィールドを束ねた構造体のようなもの。
1.1.1.9 root 53: // MPU68030Device::SetTT(), GetTT() で読み書きする。
1.1 root 54: class m68030TT
55: {
56: // 3 2 1 0
57: // 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
58: // +---------------+---------------+-+-+-+-+-+-+-+-+-+-----+-+-----+
59: // |LogicalAddrBase|LogicalAddrMask|E| |C|R|M| | FCB | | FCM |
60: // +---------------+---------------+-+-+-+-+-+-+-+-+-+-----+-+-----+
61:
62: public:
63: static const uint32 MASK = 0xffff8777;
64:
65: static const uint32 LBASE_MASK = 0xff000000;
66: static const uint32 LMASK_MASK = 0x00ff0000;
67: static const uint32 E = 0x00008000;
68: static const uint32 CI = 0x00000400;
69: static const uint32 RW = 0x00000200;
70: static const uint32 RWM = 0x00000100;
71: static const uint32 FCBASE_MASK = 0x00000070;
72: static const uint32 FCMASK_MASK = 0x00000007;
73:
1.1.1.11! root 74: void Set(uint32 data);
! 75:
! 76: // アクセスがこの TT と一致するか調べる。
! 77: bool Match(busaddr addr) const;
! 78:
1.1.1.7 root 79: bool e {}; // イネーブル
80: bool ci {}; // キャッシュ禁止
1.1.1.11! root 81: private:
1.1.1.3 root 82: uint64 base {}; // ベース
83: uint64 mask {}; // マスク
1.1 root 84: };
85:
86: // TC レジスタの各フィールドを束ねた構造体のようなもの。
87: // m68kcpu::SetTC(), GetTC() で読み書きする。
88: class m68030TC
89: {
1.1.1.7 root 90: // 3 2 1 0
91: // 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
92: // +-+---------+-+-+-------+-------+-------+-------+-------+-------+
93: // |E| 0 |S|F| PS | IS | TIA | TIB | TIC | TID |
94: // +-+---------+-+-+-------+-------+-------+-------+-------+-------+
95: // | | +-- FCL (Function Code Lookup Enable)
96: // | +---- SRE (Supervisor Root Pointer Enable)
97: // +-- Enable
1.1 root 98: public:
99: static const uint32 MASK = 0x83ffffff;
100: static const uint32 TC_E = 0x80000000;
101: static const uint32 TC_SRE = 0x02000000;
102: static const uint32 TC_FCL = 0x01000000;
103:
104: // レジスタの各フィールド
1.1.1.3 root 105: uint32 e {}; // TC_E の位置
106: uint32 sre {}; // TC_SRE の位置
107: uint32 fcl {}; // TC_FCL の位置
108: uint ps {};
109: uint is {};
1.1.1.11! root 110:
! 111: // 68030 のテーブルは最大4階層 (TIA 〜 TID) で、
! 112: // TIA から termlv 段までが有効。
1.1 root 113: union {
114: uint tix[4] {};
115: struct {
116: uint tia;
117: uint tib;
118: uint tic;
119: uint tid;
120: } __packed;
121: };
122:
1.1.1.11! root 123: int termlv {}; // 有効な段数 (例えば TIB までなら 2)
1.1 root 124: int shift[4] {}; // TIA-TID の各部分のシフト量
125: uint32 mask[4] {}; // TIA-TID の各部分のマスク
1.1.1.3 root 126: uint32 lmask {}; // TIA-TID 全体のマスク
127: uint32 pgmask {}; // PS 部分のマスク
1.1 root 128:
129: public:
1.1.1.11! root 130: // 値を代入し、二次変数も用意する。
! 131: // 構成例外を起こすなら false を返す。
! 132: bool Set(uint32);
! 133:
! 134: // (E に関わらず) 構成が有効なら true を返す。
! 135: bool ConfigOK() const { return config_ok; }
! 136:
! 137: private:
1.1 root 138: bool Check() const;
139: void MakeMask();
1.1.1.11! root 140:
! 141: bool config_ok {}; // (E に関わらず) 構成が有効なら true
1.1 root 142: };
143:
144: class m68030MMUSR
145: {
146: public:
147: static const uint16 MASK = 0xee43;
148: static const uint16 B = 0x8000; // バスエラー
149: static const uint16 L = 0x4000; // リミット違反
150: static const uint16 S = 0x2000; // スーパバイザ専用
151: static const uint16 W = 0x0800; // 書き込み保護
152: static const uint16 I = 0x0400; // 無効
153: static const uint16 M = 0x0200; // 修正
154: static const uint16 T = 0x0040; // 透過アクセス
155: static const uint16 N = 0x0007; // レベル数
156: };
157:
158: // ATC の1エントリ
159: struct m68030ATCLine
160: {
1.1.1.11! root 161: // tag:
! 162: // 3 2 1 0
! 163: // 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
! 164: // +---------------+---------------+---------------+-------+-----+-+
! 165: // | Logical Address [31:8] | 0 | FC |I|
! 166: // +---------------+---------------+---------------+-------+-----+-+
! 167: // I: Invalid (%1で無効)。
! 168: // FC: busaddr 形式の FC (210 の順) で、_Motorola のみで使用。
! 169: // _Custom のほうは FC 別のテーブルなのでここは使わない。
1.1 root 170: //
1.1.1.11! root 171: // paddr:
! 172: // 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
! 173: // +---------------+---------------+---------------+---------------+
! 174: // | Physical Address [31:8] | 0 |
! 175: // +---------------+---------------+---------------+---------------+
1.1.1.7 root 176: //
1.1.1.11! root 177: // data:
! 178: // 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
! 179: // +---------------+---------------+---------------+-------+-+-+-+-+
! 180: // | 0 |B|C|P|M|
! 181: // +---------------+---------------+---------------+-------+-+-+-+-+
! 182: // B: Bus Error
! 183: // C: Cache Inhibit
! 184: // P: Write Protect
! 185: // M: Modified
1.1 root 186:
187: static const uint32 LADDR_MASK = 0xffffff00;
188: static const uint32 INVALID = 0x00000001;
189: static const uint32 PADDR_MASK = 0xffffff00;
190: static const uint32 BUSERROR = 0x00000008;
191: static const uint32 CINHIBIT = 0x00000004;
192: static const uint32 WPROTECT = 0x00000002;
193: static const uint32 MODIFIED = 0x00000001;
194:
195: uint32 tag;
196: uint32 paddr;
197: uint32 data;
1.1.1.11! root 198: #if defined(M68030_CUSTOM_ATC)
1.1.1.8 root 199: uint32 age;
1.1.1.11! root 200: #endif
1.1 root 201:
202: uint32 GetTag() const { return tag; }
203:
1.1.1.11! root 204: void Invalidate() { tag |= INVALID; }
1.1 root 205: bool IsInvalid() const { return tag & INVALID; }
206: bool IsValid() const { return !IsInvalid(); }
207:
208: uint32 GetLAddr() const { return tag & LADDR_MASK; }
1.1.1.11! root 209: #if !defined(M68030_CUSTOM_ATC)
! 210: uint32 GetFC() const { return (tag >> 1) & 7; }
! 211: #endif
1.1 root 212: uint32 GetPAddr() const { return paddr; }
213: bool IsBusError() const { return data & BUSERROR; }
214: bool IsCInhibit() const { return data & CINHIBIT; }
215: bool IsWProtect() const { return data & WPROTECT; }
216: bool IsModified() const { return data & MODIFIED; }
1.1.1.8 root 217: };
1.1 root 218:
1.1.1.11! root 219: // ATCTable_* の共通部分だが、ポリモーフィズム (virtual) は使わずに書く。
! 220: class m68030ATCTable
! 221: {
! 222: public:
! 223: static constexpr int LINES = M68030_ATC_LINES;
! 224:
! 225: // 論理アドレスマスクを設定する。
! 226: void SetMask(uint32 lmask_) {
! 227: lmask = lmask_;
! 228: }
! 229:
! 230: protected:
! 231: // デバッグ表示用
! 232: static std::string LineToStrCommon(const m68030ATCLine *, uint fc);
! 233:
! 234: public:
! 235: int loglevel {};
! 236:
! 237: protected:
! 238: // cpu->mmu_tc.lmask のコピー。
! 239: uint32 lmask {};
! 240:
! 241: MPU68030Device *cpu {};
! 242: };
! 243:
! 244: #if defined(M68030_CUSTOM_ATC)
! 245: //
! 246: // カスタム ATC。FC を分離し、TT と ATC を同時に検索する魔改造版。
! 247: //
! 248:
1.1.1.8 root 249: struct m68030ATCStat
250: {
1.1.1.11! root 251: uint32 total {}; // アドレス変換した回数 (TC と TT 両方)
! 252: uint32 tthit {}; // TT にヒットした回数
! 253: uint32 miss {}; // ATC ミスした回数
! 254:
! 255: void Clear() {
! 256: total = 0;
! 257: tthit = 0;
! 258: miss = 0;
! 259: }
1.1 root 260: };
261:
1.1.1.11! root 262: class m68030ATCTable_Custom : public m68030ATCTable
1.1 root 263: {
264: public:
1.1.1.8 root 265: // ATC ハッシュ
266: enum : uint8 {
267: HASH_ATC_BASE = 0, // ATC #0-
268: HASH_NONE = 0xff, // 対応なし
269: HASH_TT = 0xfe, // TT
270: HASH_SUB = 0xfd, // PS<4KB
271: };
1.1 root 272:
1.1.1.11! root 273: m68030ATCTable_Custom(MPU68030Device *cpu_, uint fc_);
! 274:
! 275: // 統計情報、移動平均等をリセットする。
! 276: void ResetStat();
! 277:
! 278: // ハッシュを完全に作り直す。
! 279: void Rehash();
! 280:
! 281: // 論理アドレスからタグを作成する。
! 282: uint32 MakeTag(const busaddr laddr) const {
! 283: return (laddr.Addr() & lmask);
! 284: }
1.1 root 285:
286: // フラッシュ
1.1.1.8 root 287: // Flush() はこのテーブルのすべてのエントリが対象。
288: // Flush(addr) はこのテーブルのアドレスが一致するエントリが対象。
289: void Flush();
290: void Flush(uint32 addr);
291:
1.1.1.11! root 292: m68030ATCLine *Pop();
! 293:
1.1.1.8 root 294: // PS<4KB の時に ATC を検索。
295: m68030ATCLine *FindSub(const busaddr laddr);
296:
297: void Invalidate(m68030ATCLine *a);
298: void InvalidateSub(const m68030ATCLine *);
299:
1.1.1.11! root 300: void ClearHash();
1.1.1.10 root 301: void MakeHash(const m68030ATCLine *);
1.1.1.8 root 302: void MoveHead(m68030ATCLine *);
303:
304: // デバッグ表示
305: std::string LineToStr(const m68030ATCLine *a) const;
1.1 root 306:
1.1.1.11! root 307: // エントリの実体。
! 308: std::array<m68030ATCLine, LINES> line {};
1.1 root 309:
1.1.1.11! root 310: // 統計情報。
! 311: m68030ATCStat stat {};
! 312:
! 313: // 移動平均用バッファ。(こっちは排他制御が必要)
! 314: FixedQueue<m68030ATCStat, 3> hist {};
! 315: bool hist_tt_once_hit {};
! 316: std::mutex hist_mtx {};
! 317:
! 318: private:
1.1.1.8 root 319: uint32 latest_age {};
320:
321: // このテーブルの FC
322: uint fc {};
323:
324: // PS(ページのビット長) - 12。負数なら PS<4KB
325: int ps4k {};
326:
1.1.1.11! root 327: public:
! 328: // ATC ハッシュ (他のメンバより後ろに置く?)
! 329: std::array<uint8, 1024 * 1024> hash {};
! 330: };
1.1 root 331:
1.1.1.11! root 332: #else
! 333: //
! 334: // Motorola ATC
! 335: //
1.1.1.7 root 336:
1.1.1.11! root 337: struct m68030ATCStat
! 338: {
! 339: // 先頭からn番目のヒット回数
! 340: std::array<uint64, M68030_ATC_LINES> hit {};
! 341: // ATC 検索ミス回数
! 342: uint64 miss {};
! 343:
! 344: void Clear() {
! 345: hit = {};
! 346: miss = 0;
! 347: }
! 348: };
1.1.1.7 root 349:
1.1.1.11! root 350: class m68030ATCTable_Motorola : public m68030ATCTable
! 351: {
! 352: friend class MPU68030Device;
1.1.1.8 root 353:
1.1.1.11! root 354: #if defined(ATC_ORDER64)
! 355: static constexpr int ORDER0_COUNT = 12;
! 356: static constexpr int ORDER1_COUNT = M68030_ATC_LINES - ORDER0_COUNT;
! 357: #endif
! 358:
! 359: public:
! 360: explicit m68030ATCTable_Motorola(MPU68030Device *cpu_);
! 361:
! 362: // 統計情報、移動平均等をリセットする。
! 363: void ResetStat();
! 364:
! 365: // 論理アドレスからタグを作成する。
! 366: uint32 MakeTag(const busaddr laddr) const {
! 367: return (laddr.Addr() & lmask) | (laddr.GetFC() << 1);
! 368: }
! 369:
! 370: // エントリのフラッシュ。(pflush* 命令から呼ばれる)
! 371: void Flush();
! 372: void Flush(uint32 fc, uint32 mask);
! 373: void Flush(uint32 fc, uint32 mask, uint32 addr);
! 374:
! 375: // laddr を検索して見付かれば先頭に移動。
! 376: m68030ATCLine *LookupAndMove(const busaddr laddr);
! 377:
! 378: // laddr を検索して見付かったのを返す。(PTEST 用)
! 379: const m68030ATCLine *LookupOnly(const busaddr laddr);
! 380:
! 381: // laddr を検索して返す。なければ NULL を返す。(デバッガ用)
! 382: const m68030ATCLine *LookupByDebugger(const busaddr laddr) {
! 383: // 今は Only と同じ。
! 384: return LookupOnly(laddr);
! 385: }
! 386:
! 387: // 空きもしくは最も古いエントリを先頭に移動。
! 388: m68030ATCLine *Pop();
! 389:
! 390: // pri 番目の idx を返す。
! 391: uint GetIdx(uint pri) const
! 392: {
! 393: #if defined(ATC_ORDER64)
! 394: if (__predict_true(pri < ORDER0_COUNT)) {
! 395: return (order[0] >> (pri * 5)) & 0x1f;
! 396: } else {
! 397: return (order[1] >> ((pri - ORDER0_COUNT) * 5)) & 0x1f;
! 398: }
! 399: #else
! 400: return order[pri];
! 401: #endif
! 402: }
! 403:
! 404: // pri 番目のエントリを返す。
! 405: m68030ATCLine *GetLine(uint pri) {
! 406: return &line[GetIdx(pri)];
! 407: }
! 408:
! 409: // デバッグ表示
! 410: static std::string LineToStr(const m68030ATCLine *);
! 411:
! 412: private:
! 413: // pri 番目の値を idx にする。
! 414: void Set(uint pri, uint idx);
! 415:
! 416: int Lookup(const busaddr);
! 417:
! 418: // pri 番目の要素を先頭に移動。
! 419: void MoveHead(uint pri);
! 420: // pri 番目の要素を末尾に移動。
! 421: void MoveTail(uint pri);
! 422:
! 423: // エントリの実体。
! 424: std::array<m68030ATCLine, LINES> line {};
! 425:
! 426: // 順序管理。
! 427: #if defined(ATC_ORDER64)
! 428: std::array<uint64, 2> order {};
! 429: #else
! 430: std::array<uint8, LINES> order {};
! 431: #endif
! 432:
! 433: // 統計情報。
! 434: m68030ATCStat stat {};
1.1 root 435: };
436:
1.1.1.11! root 437: #endif // M68030_CUSTOM_ATC
! 438:
! 439: class m68030ATC
1.1 root 440: {
441: public:
1.1.1.11! root 442: explicit m68030ATC(MPU68030Device *cpu_);
1.1 root 443:
1.1.1.7 root 444: // ログレベルを設定する。Object のとは同じ使い方だけど別物。
445: void SetLogLevel(int loglevel_);
446:
1.1.1.11! root 447: // TC の設定変更に追従する。
! 448: void SetTC(const m68030TC&);
1.1 root 449:
1.1.1.11! root 450: #if defined(M68030_CUSTOM_ATC)
! 451: // ハッシュを完全に作り直す。
! 452: void Rehash();
! 453: #endif
! 454:
! 455: // テーブルを取得する。
! 456: #if defined(M68030_CUSTOM_ATC)
! 457: m68030ATCTable_Custom *GetTable(uint fc) {
! 458: assert((bool)fctables[fc]);
! 459: return fctables[fc];
! 460: }
! 461: #else
! 462: m68030ATCTable_Motorola *GetTable() {
! 463: return table.get();
! 464: }
! 465: #endif
! 466:
! 467: // エントリのフラッシュ。(pflush* 命令から呼ばれる)
! 468: void FlushAll();
! 469: void Flush(uint32 fc, uint32 mask);
! 470: void Flush(uint32 fc, uint32 mask, uint32 addr);
! 471:
! 472: // 統計情報、移動平均等をリセットする。
! 473: void ResetStat();
! 474:
! 475: // 統計情報、移動平均等を更新する。
! 476: void CalcStat();
1.1.1.7 root 477:
1.1.1.8 root 478: private:
1.1.1.11! root 479: #if defined(M68030_CUSTOM_ATC)
! 480: // FC 別テーブルは 4つ。こっちはループで回せる。
! 481: std::array<std::unique_ptr<m68030ATCTable_Custom>, 4> alltables {};
! 482: // fc で検索する場合。実際にはこのうち 4つだけが有効。
! 483: std::array<m68030ATCTable_Custom *, 8> fctables {};
! 484: #else
! 485: // テーブルは1つ。
! 486: std::unique_ptr<m68030ATCTable_Motorola> table {};
! 487: #endif
! 488:
! 489: int loglevel {};
! 490:
1.1.1.9 root 491: MPU68030Device *cpu {};
1.1 root 492: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.