|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2017 [email protected] ! 4: // ! 5: ! 6: #include "header.h" ! 7: #include "mystring.h" ! 8: #include "m68030core.h" ! 9: #include "m68030bus.h" ! 10: #include "m68030ea.h" ! 11: #include "m68030mmu.h" ! 12: #include "bus.h" ! 13: #include "mpu.h" ! 14: ! 15: #define TIA (0) ! 16: #define TIB (1) ! 17: #define TIC (2) ! 18: #define TID (3) ! 19: #define FCL (4) // 便宜上ね ! 20: #define MAX_LV (5) ! 21: ! 22: // ディスクリプタタイプ ! 23: #define GET_DT(x) (x & 0x03) ! 24: #define DT_INVALID (0) ! 25: #define DT_PAGE (1) ! 26: #define DT_VALID4 (2) ! 27: #define DT_VALID8 (3) ! 28: ! 29: // ディスクリプタ ! 30: #define MMU_DESC_S (0x00000100) ! 31: #define MMU_DESC_CI (0x00000040) ! 32: #define MMU_DESC_M (0x00000010) ! 33: #define MMU_DESC_U (0x00000008) ! 34: #define MMU_DESC_WP (0x00000004) ! 35: #define MMU_DESC_DT (0x00000003) ! 36: ! 37: // エントリの状態 ! 38: enum ATCtype { ! 39: INVALID, ! 40: NORMAL, ! 41: EARLY, ! 42: INDIRECT, ! 43: }; ! 44: ! 45: // ! 46: // デバッグ表示 ! 47: // ! 48: ! 49: #define IF_DEBUG if (gMPU->loglevel > 0) ! 50: ! 51: // デバッグ表示のため値の表示に必要な桁数を返す ! 52: #define NIBBLE(x) ( (x) == 0 ? 1 : ((x) + 3) / 4 ) ! 53: ! 54: // インデント付き fmt, ap を出力 ! 55: static void viprintf(int indent, const char *fmt, va_list) __printflike(2, 0); ! 56: static void ! 57: viprintf(int indent, const char *fmt, va_list ap) ! 58: { ! 59: static const char *indentstr = " "; // 長さは適当 ! 60: char buf[1024]; ! 61: ! 62: vsnprintf(buf, sizeof(buf), fmt, ap); ! 63: cpulog(3, "%s%s", &indentstr[strlen(indentstr) - indent], buf); ! 64: } ! 65: ! 66: // IF_DEBUG 中だと分かってるところではこっちを使う ! 67: static void IPRINTF(int indent, const char *fmt, ...)__printflike(2, 3); ! 68: static void ! 69: IPRINTF(int indent, const char *fmt, ...) ! 70: { ! 71: va_list ap; ! 72: ! 73: va_start(ap, fmt); ! 74: viprintf(indent, fmt, ap); ! 75: va_end(ap); ! 76: } ! 77: ! 78: // MMU デバッグモードならインデント付き fmt... を出力 ! 79: #define DPRINTF(indent, ...) do { \ ! 80: IF_DEBUG \ ! 81: IPRINTF(indent, __VA_ARGS__); \ ! 82: } while(0) ! 83: ! 84: // MMU デバッグモードなら ATC エントリ a を表示 ! 85: #define FILL_PRINT(fc, a) do { \ ! 86: IF_DEBUG \ ! 87: (a)->fill_print(fc); \ ! 88: } while (0) ! 89: ! 90: ! 91: // テーブルサーチ操作クラス ! 92: class m68030MMU ! 93: { ! 94: public: ! 95: m68030MMU(m68kcpu *); ! 96: virtual ~m68030MMU() { } ! 97: ! 98: // サーチを実行 ! 99: void search(); ! 100: ! 101: // ATC にエントリを作成 ! 102: void make_atc(m68030ATCLine *); ! 103: ! 104: // ATC にエントリを作成 (デバッガアクセス用) ! 105: uint64 make_atc_debugger(); ! 106: ! 107: private: ! 108: // リミットチェック ! 109: bool limitcheck() const; ! 110: ! 111: // ディスクリプタを取得 ! 112: bool fetch_desc(uint32, int); ! 113: ! 114: // MMU による物理メモリ読み込み ! 115: uint64 phys_read_32(uint32 addr); ! 116: ! 117: // MMU による物理メモリ書き込み ! 118: uint64 phys_write_32(uint32 addr, uint32 data); ! 119: ! 120: // デバッガ読み込み ! 121: uint64 phys_peek_32(uint32 addr); ! 122: ! 123: // ディスクリプタを表示用に (デバッグ用) ! 124: std::string sprintf_desc(); ! 125: ! 126: // ディスクリプタタイプ文字列 (デバッグ用) ! 127: const char *dtname(uint32 dt); ! 128: ! 129: public: ! 130: ATCtype m_type; // 状態 ! 131: int m_s; // S ビット ! 132: int m_wp; // WP ビット ! 133: int m_m; // ページディスクリプタの M が立っているか ! 134: int m_l; // サーチ中にリミットを越えた ! 135: bool m_berr; // テーブルサーチ中にバスエラー ! 136: bool m_ptest; // PTEST[RW] 命令中なら真 ! 137: bool m_debugger; // デバッガからのアクセスなら true にする ! 138: private: ! 139: int x; // 段数 TIA〜TID, FCL ! 140: int m_lv[MAX_LV]; ! 141: uint32 m_laddr; ! 142: int m_fc; ! 143: uint32 m_desc1; // ディスクリプタ ! 144: uint32 m_desc2; // ロングディスクリプタの後半部 ! 145: int m_descsize; // ディスクリプタサイズ (4 or 8) ! 146: int m_lastsize; // 前段のディスクリプタサイズ ! 147: ! 148: // デバッグ用文字列 ! 149: static const char * const m_lvname[MAX_LV]; ! 150: ! 151: m68kcpu *cpu; ! 152: }; ! 153: ! 154: // 現在の TC:E、TT:E の状態に応じてアドレス変換の有無を切り替える。 ! 155: // mmu_enable ならアドレス変換ありのバスアクセスを使う。see m68030bus.cpp ! 156: void ! 157: m68kcpu::mmu_enable_changed() ! 158: { ! 159: bool enable; ! 160: ! 161: // TC、TT0、TT1 のいずれかが有効ならアドレス変換あり ! 162: enable = (mmu_tc.e || mmu_tt[0].e || mmu_tt[1].e); ! 163: ! 164: // 変化した時だけ ! 165: if (mmu_enable && !enable) { ! 166: // 無効にする ! 167: mmu_enable = false; ! 168: cpulog(1, "MMU アドレス変換停止"); ! 169: } else if (!mmu_enable && enable) { ! 170: // 有効にする ! 171: mmu_enable = true; ! 172: cpulog(1, "MMU アドレス変換開始"); ! 173: } ! 174: } ! 175: ! 176: ! 177: // ! 178: // レジスタクラス ! 179: // ! 180: ! 181: void ! 182: m68kcpu::SetSRP(uint32 h, uint32 l) ! 183: { ! 184: reg.srp.h = h & m68030RP::H_MASK; ! 185: reg.srp.l = l & m68030RP::L_MASK; ! 186: } ! 187: ! 188: void ! 189: m68kcpu::SetCRP(uint32 h, uint32 l) ! 190: { ! 191: reg.crp.h = h & m68030RP::H_MASK; ! 192: reg.crp.l = l & m68030RP::L_MASK; ! 193: } ! 194: ! 195: void ! 196: m68kcpu::SetTT(int n, uint32 data) ! 197: { ! 198: uint32 lbase; ! 199: uint32 lmask; ! 200: uint32 sbase; ! 201: uint32 smask; ! 202: ! 203: // マスクしてレジスタイメージにセット ! 204: reg.tt[n] = data & m68030TT::MASK; ! 205: ! 206: // data を分解してメンバにセット。 ! 207: // ! 208: // 3 2 1 0 ! 209: // 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 ! 210: // +---------------+---------------+-+-+-+-+-+-+-+-+-+-----+-+-----+ ! 211: // |LogicalAddrBase|LogicalAddrMask|E| |C|R|M| | FCB | | FCM | ! 212: // +---------------+---------------+-+-+-+-+-+-+-+-+-+-----+-+-----+ ! 213: ! 214: mmu_tt[n].e = (data & m68030TT::E); ! 215: mmu_tt[n].ci = (data & m68030TT::CI); ! 216: ! 217: // 下位ロングワード ! 218: // ・lbase は比較先アドレスで、ff000000の位置。 ! 219: // ・lmask はアドレスマスク。%1 が無視を表しているので NOT しておく。 ! 220: // ! 221: // target AAAAAAAA xxxxxxxx xxxxxxxx xxxxxxxx : Aは論理アドレス ! 222: // ^ : xは不問 ! 223: // lbase BBBBBBBB 00000000 00000000 00000000 : Bは論理アドレスベース ! 224: // & ! 225: // lmask MMMMMMMM 00000000 00000000 00000000 : Mは論理アドレスマスク ! 226: // ! 227: lbase = (data & m68030TT::LBASE_MASK); ! 228: lmask = (~data & m68030TT::LMASK_MASK) << 8; ! 229: ! 230: // 上位ロングワード ! 231: // ・E ビットは位置はどこでもいいので TT:E ビットの ! 232: // 位置をそのまま使用する。target 側のこの位置は必ずビットが落ちている ! 233: // ため base 側にビットを立てておくと必ず不一致になることを利用して、 ! 234: // E ビットの評価も一度に行う。 ! 235: // ・RW ビットは SSW の RW と比較するので、SSW_RW のビット位置を使う ! 236: // (0x00000040 の位置)。 ! 237: // また TT::RW は Write が %1 だが SSW_RW は Read が %1 なので反転。 ! 238: // ・RWM が %1 なら R/W は無視、RWM が %0 なら R/W の一致も検査するので ! 239: // RWM が %0 の時は RW のマスクビットを立てておく。 ! 240: // ・FCMask は %1 が無視を表しているので NOT しておく。 ! 241: // ! 242: // target 00000000 00000000 00000000 0R000FFF : R はアクセス R/~W ! 243: // ^ : F はアクセス FC ! 244: // base 00000000 00000000 E0000000 0R000FFF : R は期待する R/~W ! 245: // & : F は期待する FC ! 246: // : E は ~TT:E ! 247: // mask 00000000 00000000 10000000 0M000CCC : M は R/~W マスク ! 248: // : C は FC マスク ! 249: sbase = ~data & m68030TT::E; ! 250: sbase |= (~data & m68030TT::RW) >> 3; ! 251: sbase |= ( data & m68030TT::FCBASE_MASK) >> 4; ! 252: smask = m68030TT::E; ! 253: if ((data & m68030TT::RWM) == 0) { ! 254: smask |= SSW_RW; ! 255: } ! 256: smask |= ~data & m68030TT::FCMASK_MASK; ! 257: ! 258: mmu_tt[n].base = lbase | (((uint64)sbase) << 32); ! 259: mmu_tt[n].mask = lmask | (((uint64)smask) << 32); ! 260: ! 261: // 論理アドレスとEnableビットだけの早見表を作成。 ! 262: // TT0 が一致するなら bit0 をセット、TT1 が一致するなら bit1 をセット ! 263: // しておく。 ! 264: for (int i = 0; i < countof(mmu_tt_quick); i++) { ! 265: uint32 laddr = ((uint32)i) << 24; ! 266: if (mmu_tt[n].e && ((laddr ^ lbase) & lmask) == 0) { ! 267: mmu_tt_quick[i] |= (1 << n); ! 268: } else { ! 269: mmu_tt_quick[i] &= ~(1 << n); ! 270: } ! 271: } ! 272: ! 273: mmu_enable_changed(); ! 274: } ! 275: ! 276: // アクセスがこの TT と一致するか調べる。 ! 277: // ssw_laddr は上位32ビットが cpu->bus.ssw、下位32ビットが論理アドレス ! 278: // (下24ビットは呼び出し側でマスクしなくてよい)。 ! 279: // 一致すれば true を返す。 ! 280: bool ! 281: m68030TT::Match(uint64 ssw_laddr) ! 282: { ! 283: bool rv = (((ssw_laddr ^ base) & mask) == 0); ! 284: return rv; ! 285: } ! 286: ! 287: // 成功すれば true、MMU 構成例外が起きる場合は false を返す。 ! 288: // 呼び出し側で例外を起こすこと。 ! 289: bool ! 290: m68kcpu::SetTC(uint32 data) ! 291: { ! 292: // マスクしてレジスタイメージにセット ! 293: reg.tc = data & m68030TC::MASK; ! 294: ! 295: // data を分解してメンバにセット ! 296: mmu_tc.Set(data); ! 297: ! 298: // 有効にする場合は一貫性を確認 ! 299: if (mmu_tc.e) { ! 300: if (mmu_tc.Check() == false) { ! 301: // エラーなら E をクリアして MMU 構成例外。 ! 302: // (例外処理自体は呼び出し側で行う) ! 303: mmu_tc.e = 0; ! 304: mmu_enable_changed(); ! 305: return false; ! 306: } ! 307: } ! 308: ! 309: // マスクをあらかじめ用意しておく ! 310: mmu_tc.MakeMask(); ! 311: ! 312: // TC:E が変更されていればスイッチ更新 ! 313: mmu_enable_changed(); ! 314: return true; ! 315: ! 316: } ! 317: ! 318: // TC レジスタへの書き込み値を m68030TC クラスにセットする。 ! 319: void ! 320: m68030TC::Set(uint32 data) ! 321: { ! 322: e = data & TC_E; ! 323: sre = data & TC_SRE; ! 324: fcl = data & TC_FCL; ! 325: tid = (data) & 0x0f; ! 326: tic = (data >>= 4) & 0x0f; ! 327: tib = (data >>= 4) & 0x0f; ! 328: tia = (data >>= 4) & 0x0f; ! 329: is = (data >>= 4) & 0x0f; ! 330: ps = (data >>= 4) & 0x0f; ! 331: } ! 332: ! 333: // 現在の値が MMU 構成例外になるなら false を返す。 ! 334: bool ! 335: m68030TC::Check() const ! 336: { ! 337: if (ps < 8) ! 338: return false; ! 339: if (tia == 0) ! 340: return false; ! 341: if (tib == 0 && (tic > 0 || tid > 0)) ! 342: return false; ! 343: if (tic == 0 && tid > 0) ! 344: return false; ! 345: if (ps + is + tia + tib + tic + tid != 32) ! 346: return false; ! 347: ! 348: return true; ! 349: } ! 350: ! 351: // 論理マスク、ページマスクを作成。(テーブルサーチで参照される) ! 352: void ! 353: m68030TC::MakeMask() ! 354: { ! 355: // lmask (論理マスク) は TIA〜TID 部分のマスク。 ! 356: // pgmask (ページマスク) は PS 部分のマスク。 ! 357: // ! 358: // 例えば IS=$8, TIA=$3, TIB=$4, TIC=$4, TID=$0, PS=$d ! 359: // (X68030 IPL 内の MMU 判定のケース) なら ! 360: // ! 361: // 3 2 1 0 ! 362: // 10987654 32109876 54321098 76543210 ! 363: // +--------+--------+--------+--------+ ! 364: // |IIIIIIII AAABBBBC CCCPPPPP PPPPPPPP| ! 365: // +--------+--------+--------+--------+ ! 366: // lmask = 00000000 11111111 11100000 00000000 ! 367: // pgmask = 00000000 00000000 00011111 11111111 ! 368: lmask = (1 << (tia + tib + tic + tid)) - 1; ! 369: lmask <<= ps; ! 370: pgmask = (1 << ps) - 1; ! 371: ! 372: // アドレスを (IS,) TIA 〜 TID に分解。 ! 373: // ! 374: // TIA=$C, TIB=$A, (TIC = TID = 0), PS=$A の場合以下のようにする。 ! 375: // 使ってない TIC, TID については tix[TIC] == 0 で判断する。 ! 376: // ! 377: // A B PS ! 378: // +----------------+--------------+--------------+ ! 379: // $00A01A00 | 0000 0000 1010 | 0000 0001 10 | xx xxxx xxxx | ! 380: // +----------------+--------------+--------------+ ! 381: // shift[TIA]=20 shift[TIB]=10 ! 382: // mask[TIA]=0xfff mask[TIB]=0x3ff ! 383: int sh = ps; ! 384: for (int i = TID; i >= TIA; i--) { ! 385: if (tix[i] > 0) { ! 386: shift[i] = sh; ! 387: mask[i] = (1 << tix[i]) - 1; ! 388: sh += tix[i]; ! 389: } ! 390: } ! 391: } ! 392: ! 393: void ! 394: m68kcpu::SetMMUSR(uint16 data) ! 395: { ! 396: reg.mmusr = data & m68030MMUSR::MASK; ! 397: } ! 398: ! 399: ! 400: // ! 401: // ATC テーブル ! 402: // ! 403: ! 404: // コンストラクタ ! 405: m68030ATCTable::m68030ATCTable() ! 406: { ! 407: #if !defined(ATC_SINGLE) ! 408: for (int i = 0; i < countof(line); i++) { ! 409: line[i].Invalidate(); ! 410: } ! 411: head = &line[0]; ! 412: #else ! 413: for (int i = 0; i < countof(line); i++) { ! 414: line[i].Invalidate(); ! 415: insert_tail(&line[i]); ! 416: } ! 417: #endif ! 418: } ! 419: ! 420: #if !defined(ATC_SINGLE) ! 421: // a のエントリを先頭にする。 ! 422: m68030ATCLine * ! 423: m68030ATCTable::MoveHead(m68030ATCLine *a) ! 424: { ! 425: // head を向け直す ! 426: head = a; ! 427: ! 428: // 更新 ! 429: head->age = counter++; ! 430: ! 431: // そのエントリを返す ! 432: return head; ! 433: } ! 434: #endif ! 435: ! 436: ! 437: // ! 438: // ATC ! 439: // ! 440: ! 441: // コンストラクタ ! 442: m68030ATC::m68030ATC(m68kcpu *parent) ! 443: { ! 444: cpu = parent; ! 445: } ! 446: ! 447: #if defined(ATC_SINGLE) ! 448: // item をリストの先頭に挿入。 ! 449: void ! 450: m68030ATCTable::insert_head(m68030ATCLine *item) ! 451: { ! 452: item->prev = NULL; ! 453: item->next = head; ! 454: if (head) { ! 455: head->prev = item; ! 456: } ! 457: head = item; ! 458: } ! 459: ! 460: // item をリストの先頭から2番目に挿入。 ! 461: void ! 462: m68030ATCTable::insert_second(m68030ATCLine *item) ! 463: { ! 464: item->prev = head; ! 465: if (head) { ! 466: item->next = head->next; ! 467: if (head->next) { ! 468: head->next->prev = item; ! 469: } ! 470: head->next = item; ! 471: } else { ! 472: item->next = NULL; ! 473: } ! 474: } ! 475: ! 476: // item をリストの末尾に追加。 ! 477: void ! 478: m68030ATCTable::insert_tail(m68030ATCLine *item) ! 479: { ! 480: item->next = NULL; ! 481: if (head == NULL) { ! 482: item->prev = NULL; ! 483: head = item; ! 484: } else { ! 485: m68030ATCLine *a = head; ! 486: while (a->next) ! 487: a = a->next; ! 488: a->next = item; ! 489: item->prev = a; ! 490: } ! 491: } ! 492: ! 493: // item をリストから外す ! 494: void ! 495: m68030ATCTable::remove(m68030ATCLine *item) ! 496: { ! 497: if (item->prev) ! 498: item->prev->next = item->next; ! 499: if (item->next) ! 500: item->next->prev = item->prev; ! 501: if (item == head) ! 502: head = item->next; ! 503: } ! 504: ! 505: // item をリストの先頭に移す。 ! 506: // fill_fetch() から呼ばれるもので、リストは空でなく、item は先頭から ! 507: // 3番目以内ではない、という前提で高速化。 ! 508: void ! 509: m68030ATCTable::move_head(m68030ATCLine *item) ! 510: { ! 511: // 先頭でない前提の remove ! 512: item->prev->next = item->next; ! 513: if (item->next) ! 514: item->next->prev = item->prev; ! 515: ! 516: // 先頭がある前提の insert_head ! 517: item->prev = NULL; ! 518: item->next = head; ! 519: head->prev = item; ! 520: head = item; ! 521: } ! 522: ! 523: // item を先頭から2番目に移す。 ! 524: // fill_{read,write} から呼ばれるもので、リストは空でなく、item は先頭から ! 525: // 3番目以内ではない、という前提で高速化。 ! 526: void ! 527: m68030ATCTable::move_second(m68030ATCLine *item) ! 528: { ! 529: // 先頭でない前提の remove ! 530: item->prev->next = item->next; ! 531: if (item->next) ! 532: item->next->prev = item->prev; ! 533: ! 534: // 先頭2つがある前提の insert_second ! 535: item->prev = head; ! 536: item->next = head->next; ! 537: head->next->prev = item; ! 538: head->next = item; ! 539: } ! 540: #endif // ATC_SINGLE ! 541: ! 542: // fill_{fetch,read,write}() が各アクセス用の ATC サーチ。 ! 543: // 論理アドレス fc:addr が ATC にあればそのエントリを返す。 ! 544: // なければ ATC を更新してそのエントリを返す。 ! 545: // fill_peek() はデバッグ用なので一切状態を更新せず結果だけ返す。 ! 546: ! 547: const m68030ATCLine& ! 548: m68030ATC::fill_fetch() ! 549: { ! 550: uint32 laddr = cpu->bus.laddr & cpu->mmu_tc.lmask; ! 551: uint fc = cpu->bus.GetFC(); ! 552: m68030ATCTable *table; ! 553: m68030ATCLine *a; ! 554: int i; ! 555: ! 556: #if !defined(ATC_SINGLE) ! 557: table = &tables[fc]; ! 558: // キャッシュとマッチすればそれを返す ! 559: a = table->head; ! 560: if (a->GetTag() == laddr) { ! 561: FILL_PRINT(fc, a); ! 562: table->hit_head++; ! 563: return *a; ! 564: } ! 565: for (i = 0; i < countof(table->line); i++) { ! 566: a = &table->line[i]; ! 567: if (a->GetTag() == laddr) { ! 568: // ヒットしたので先頭に移動。fetch は常に入れ替え ! 569: a = table->MoveHead(a); ! 570: ! 571: FILL_PRINT(fc, a); ! 572: table->hit[i]++; ! 573: return *a; ! 574: } ! 575: } ! 576: ! 577: // 見付からなかったので、古いエントリを1つ更新。 ! 578: a = table->MoveHead(table->Lookup()); ! 579: table->hit[m68030ATCTable::LINES]++; ! 580: // タグはこっちで初期化 ! 581: a->tag = laddr; ! 582: #else ! 583: table = &tables[0]; ! 584: // キャッシュとマッチすればそれを返す ! 585: a = table->head; ! 586: for (i = 0; a; a = a->next, i++) { ! 587: if (a->GetTag() == laddr && a->fc == fc) { ! 588: // ヒットしたので先頭に移動。 ! 589: if (i > 2) { ! 590: table->move_head(a); ! 591: } ! 592: ! 593: FILL_PRINT(fc, a); ! 594: table->hit[i]++; ! 595: return *a; ! 596: } ! 597: } ! 598: ! 599: // 見付からなかったので、古いエントリを1つ更新。 ! 600: a = table->lookup(); ! 601: table->remove(a); ! 602: table->insert_head(a); ! 603: table->hit[m68030ATCTable::LINES]++; ! 604: // タグはこっちで初期化 ! 605: a->tag = laddr; ! 606: a->fc = fc; ! 607: #endif ! 608: ! 609: // テーブルサーチして結果を ATC に入れる ! 610: m68030MMU mmu(cpu); ! 611: mmu.search(); ! 612: mmu.make_atc(a); ! 613: ! 614: FILL_PRINT(fc, a); ! 615: return *a; ! 616: } ! 617: ! 618: const m68030ATCLine& ! 619: m68030ATC::fill_read() ! 620: { ! 621: uint32 laddr = cpu->bus.laddr & cpu->mmu_tc.lmask; ! 622: uint fc = cpu->bus.GetFC(); ! 623: m68030ATCTable *table; ! 624: m68030ATCLine *a; ! 625: int i; ! 626: ! 627: #if !defined(ATC_SINGLE) ! 628: table = &tables[fc]; ! 629: // キャッシュとマッチすればそれを返す ! 630: a = table->head; ! 631: if (a->GetTag() == laddr) { ! 632: FILL_PRINT(fc, a); ! 633: table->hit_head++; ! 634: return *a; ! 635: } ! 636: for (i = 0; i < countof(table->line); i++) { ! 637: a = &table->line[i]; ! 638: if (a->GetTag() == laddr) { ! 639: // ヒットしたので先頭に移動。 ! 640: a = table->MoveHead(a); ! 641: ! 642: FILL_PRINT(fc, a); ! 643: table->hit[i]++; ! 644: return *a; ! 645: } ! 646: } ! 647: ! 648: // 見付からなかったので、古いエントリを1つ更新 ! 649: a = table->MoveHead(table->Lookup()); ! 650: table->hit[m68030ATCTable::LINES]++; ! 651: // タグはこっちで初期化 ! 652: a->tag = laddr; ! 653: #else ! 654: table = &tables[0]; ! 655: // キャッシュとマッチすればそれを返す ! 656: a = table->head; ! 657: for (i = 0; a; a = a->next, i++) { ! 658: if ((a->GetTag() == laddr) && (a->fc == fc)) { ! 659: // ヒットしたので先頭から2番目に移動 ! 660: if (i > 2) { ! 661: table->move_second(a); ! 662: } ! 663: ! 664: FILL_PRINT(fc, a); ! 665: table->hit[i]++; ! 666: return *a; ! 667: } ! 668: } ! 669: ! 670: // 見付からなかったので、古いエントリを1つ更新 ! 671: a = table->lookup(); ! 672: table->remove(a); ! 673: table->insert_head(a); ! 674: table->hit[m68030ATCTable::LINES]++; ! 675: // タグはこっちで初期化 ! 676: a->tag = laddr; ! 677: a->fc = fc; ! 678: #endif ! 679: ! 680: // テーブルサーチして結果を ATC に入れる ! 681: m68030MMU mmu(cpu); ! 682: mmu.search(); ! 683: mmu.make_atc(a); ! 684: ! 685: FILL_PRINT(fc, a); ! 686: return *a; ! 687: } ! 688: ! 689: const m68030ATCLine& ! 690: m68030ATC::fill_write() ! 691: { ! 692: uint32 laddr = cpu->bus.laddr & cpu->mmu_tc.lmask; ! 693: uint fc = cpu->bus.GetFC(); ! 694: m68030ATCTable *table; ! 695: m68030ATCLine *a; ! 696: int i; ! 697: ! 698: #if !defined(ATC_SINGLE) ! 699: table = &tables[fc]; ! 700: // キャッシュとマッチすればそれを返す ! 701: a = table->head; ! 702: if (a->GetTag() == laddr) { ! 703: // ライトアクセスなので、WP でなく Modified == 0 なら ! 704: // Modified を立てるため、このエントリを破棄して改めて ! 705: // テーブルサーチを実行する。 ! 706: if (!a->IsWProtect() && !a->IsModified()) { ! 707: FILL_PRINT(fc, a); ! 708: DPRINTF(1, "ATC_fill: write access but M is not set, " ! 709: "so invalidate it"); ! 710: a->Invalidate(); ! 711: goto search; ! 712: } ! 713: FILL_PRINT(fc, a); ! 714: table->hit_head++; ! 715: return *a; ! 716: } ! 717: for (i = 0; i < countof(table->line); i++) { ! 718: a = &table->line[i]; ! 719: if (a->GetTag() == laddr) { ! 720: // ライトアクセスなので、WP でなく Modified == 0 なら ! 721: // Modified を立てるため、このエントリを破棄して改めて ! 722: // テーブルサーチを実行する。 ! 723: if (!a->IsWProtect() && !a->IsModified()) { ! 724: FILL_PRINT(fc, a); ! 725: DPRINTF(1, "ATC_fill: write access but M is not set, " ! 726: "so invalidate it"); ! 727: a->Invalidate(); ! 728: break; ! 729: } ! 730: // ヒットしたので先頭に移動。 ! 731: a = table->MoveHead(a); ! 732: ! 733: FILL_PRINT(fc, a); ! 734: table->hit[i]++; ! 735: return *a; ! 736: } ! 737: } ! 738: search:; ! 739: ! 740: // 見付からなかったので、古いエントリを1つ更新 ! 741: a = table->MoveHead(table->Lookup()); ! 742: table->hit[m68030ATCTable::LINES]++; ! 743: // タグはこっちで初期化 ! 744: a->tag = laddr; ! 745: #else ! 746: table = &tables[0]; ! 747: // キャッシュとマッチすればそれを返す ! 748: a = table->head; ! 749: for (i = 0; a; a = a->next, i++) { ! 750: if ((a->GetTag() == laddr) && (a->fc == fc)) { ! 751: // ライトアクセスなので、WP でなく Modified == 0 なら ! 752: // Modified を立てるため、このエントリを破棄して改めて ! 753: // テーブルサーチを実行する。 ! 754: if (!a->IsWProtect() && !a->IsModified()) { ! 755: FILL_PRINT(fc, a); ! 756: DPRINTF(1, "ATC_fill: write access but M is not set, " ! 757: "so invalidate it"); ! 758: a->Invalidate(); ! 759: break; ! 760: } ! 761: ! 762: // ヒットしたので、先頭から2番目に移動 ! 763: if (i > 2) { ! 764: table->move_second(a); ! 765: } ! 766: ! 767: FILL_PRINT(fc, a); ! 768: table->hit[i]++; ! 769: return *a; ! 770: } ! 771: } ! 772: ! 773: // 見付からなかったので、古いエントリを1つ更新 ! 774: a = table->lookup(); ! 775: table->remove(a); ! 776: table->insert_head(a); ! 777: // 論理部分(タグ部分)を初期化 ! 778: a->tag = laddr; ! 779: a->fc = fc; ! 780: table->hit[m68030ATCTable::LINES]++; ! 781: #endif ! 782: ! 783: // テーブルサーチして結果を ATC に入れる ! 784: m68030MMU mmu(cpu); ! 785: mmu.search(); ! 786: mmu.make_atc(a); ! 787: ! 788: FILL_PRINT(fc, a); ! 789: return *a; ! 790: } ! 791: ! 792: // ピークアクセス用に ATC を検索する。 ! 793: // ATC になければ (uint64)-1 を返す。ここでは疑似テーブルサーチは行わない。 ! 794: // laddr は論理ページアドレスにマスクしておくこと。 ! 795: // 戻り値はいずれの場合も物理ページアドレスか、バスエラーなら (uint64)-1。 ! 796: uint64 ! 797: m68030ATC::fill_peek(uint32 laddr, uint fc) ! 798: { ! 799: m68030ATCTable *table; ! 800: m68030ATCLine *a; ! 801: ! 802: #if !defined(ATC_SINGLE) ! 803: // キャッシュとマッチすればそれを返す ! 804: table = &tables[fc]; ! 805: for (int i = 0; i < countof(table->line); i++) { ! 806: a = &table->line[i]; ! 807: if (a->GetTag() == laddr) { ! 808: // ヒットした ! 809: uint32 paddr = a->GetPAddr(); ! 810: DPRINTF(1, "fill_peek: match %d:$%08x -> $%08x", ! 811: fc, laddr, paddr); ! 812: return paddr; ! 813: } ! 814: } ! 815: #else ! 816: // キャッシュとマッチすればそれを返す ! 817: table = &tables[0]; ! 818: for (a = table->head; a; a = a->next) { ! 819: if ((a->GetTag() == laddr) && ((a->fc & 4) == fc)) { ! 820: // ヒットした ! 821: uint32 paddr = a->GetPAddr(); ! 822: DPRINTF(1, "fill_peek: match %d:$%08x -> $%08x", ! 823: a->fc, laddr, paddr); ! 824: return paddr; ! 825: } ! 826: } ! 827: #endif ! 828: ! 829: return (uint64)-1; ! 830: } ! 831: ! 832: // デバッグ表示。 ! 833: // ATC_SINGLE なら fc は ATCLine に含まれているため、引数はダミーで ! 834: // 変数名が衝突するため仮引数名も変えてある。なんだかなあ。 ! 835: #if defined(ATC_SINGLE) ! 836: void ! 837: m68030ATCLine::fill_print(uint dummyfc) ! 838: #else ! 839: void ! 840: m68030ATCLine::fill_print(uint fc) ! 841: #endif ! 842: { ! 843: uint32 laddr = GetLAddr(); ! 844: ! 845: if (!IsBusError()) { ! 846: uint32 wp = IsWProtect(); ! 847: uint32 mod = IsModified(); ! 848: IPRINTF(1, "ATC_fill: match %d:$%08x -> $%08x WP=%d M=%d", ! 849: fc, laddr, GetPAddr(), wp, mod); ! 850: } else { ! 851: IPRINTF(1, "ATC_fill: match %d:$%08x -> BusErr", ! 852: fc, laddr); ! 853: } ! 854: } ! 855: ! 856: #if !defined(ATC_SINGLE) ! 857: // 更新用にエントリを1つ差し出す。 ! 858: m68030ATCLine * ! 859: m68030ATCTable::Lookup() ! 860: { ! 861: uint32 minage; ! 862: int minidx; ! 863: ! 864: // 空きエントリを探しながら、最古エントリを探しておく。 ! 865: // 最古エントリは age が最も小さいもの。 ! 866: minage = (uint32)-1; ! 867: minidx = 0; ! 868: for (int i = 0; i < countof(line); i++) { ! 869: m68030ATCLine& a = line[i]; ! 870: if (a.IsInvalid()) { ! 871: DPRINTF(1, "ATC_lookup got free entry [%d]", i); ! 872: return &a; ! 873: } ! 874: if (a.age < minage) { ! 875: minage = a.age; ! 876: minidx = i; ! 877: } ! 878: } ! 879: // 空きがなければ、最古のエントリを差し出す ! 880: DPRINTF(1, "ATC_lookup got oldest entry [%d]", minidx); ! 881: return &line[minidx]; ! 882: } ! 883: #else ! 884: // 更新用にエントリを1つ差し出す。 ! 885: m68030ATCLine * ! 886: m68030ATCTable::lookup() ! 887: { ! 888: m68030ATCLine *a; ! 889: ! 890: // 空きエントリを探す ! 891: for (int i = 0; i < LINES; i++) { ! 892: a = &line[i]; ! 893: if (a->IsInvalid()) { ! 894: DPRINTF(1, "ATC_lookup got free entry [%d]", i); ! 895: goto found; ! 896: } ! 897: } ! 898: ! 899: // 空きがなければ、リストの末尾が最古なのでこれを差し出す ! 900: a = head; ! 901: while (a->next) { ! 902: a = a->next; ! 903: } ! 904: DPRINTF(1, "ATC_lookup got oldest entry"); ! 905: ! 906: found: ! 907: return a; ! 908: } ! 909: #endif ! 910: ! 911: // ATC をすべてフラッシュする。命令からコールされる ! 912: void ! 913: m68030ATC::flush() ! 914: { ! 915: for (int i = 0; i < countof(tables); i++) { ! 916: tables[i].flush(); ! 917: } ! 918: } ! 919: ! 920: // ATC の fc, mask が一致するエントリをフラッシュする。 ! 921: // 命令からコールされる。 ! 922: void ! 923: m68030ATC::flush(uint32 fc, uint32 mask) ! 924: { ! 925: #if !defined(ATC_SINGLE) ! 926: for (int i = 0; i < countof(tables); i++) { ! 927: if (((i ^ fc) & mask) == 0) { ! 928: // FC が一致したテーブルを全フラッシュ ! 929: tables[i].flush(); ! 930: } ! 931: } ! 932: #else ! 933: for (int i = 0; i < 8; i++) { ! 934: if (((i ^ fc) & mask) == 0) { ! 935: // この FC をテーブルからフラッシュ ! 936: tables[0].flush_fc(i); ! 937: } ! 938: } ! 939: #endif ! 940: } ! 941: ! 942: // ATC の fc, mask, addr が一致するエントリをフラッシュする。 ! 943: // 命令からコールされる。 ! 944: void ! 945: m68030ATC::flush(uint32 fc, uint32 mask, uint32 addr) ! 946: { ! 947: #if !defined(ATC_SINGLE) ! 948: for (int i = 0; i < countof(tables); i++) { ! 949: if (((i ^ fc) & mask) == 0) { ! 950: // FC が一致したテーブルから addr が一致したエントリをフラッシュ ! 951: tables[i].flush(addr); ! 952: } ! 953: } ! 954: #else ! 955: for (int i = 0; i < 8; i++) { ! 956: if (((i ^ fc) & mask) == 0) { ! 957: // FC と addr が一致したエントリをフラッシュ ! 958: tables[0].flush(i, addr); ! 959: } ! 960: } ! 961: #endif ! 962: } ! 963: ! 964: // この ATC テーブルのエントリをすべてフラッシュする。 ! 965: void ! 966: m68030ATCTable::flush() ! 967: { ! 968: for (int i = 0; i < countof(line); i++) { ! 969: m68030ATCLine& a = line[i]; ! 970: a.Invalidate(); ! 971: } ! 972: } ! 973: ! 974: #if !defined(ATC_SINGLE) ! 975: // addr が一致するエントリをすべてフラッシュ ! 976: void ! 977: m68030ATCTable::flush(uint32 addr) ! 978: { ! 979: for (int i = 0; i < countof(line); i++) { ! 980: m68030ATCLine& a = line[i]; ! 981: if (a.GetLAddr() == addr) { ! 982: a.Invalidate(); ! 983: } ! 984: } ! 985: } ! 986: #else ! 987: // FC が一致するエントリをすべてフラッシュする ! 988: void ! 989: m68030ATCTable::flush_fc(uint32 fc) ! 990: { ! 991: for (int i = 0; i < countof(line); i++) { ! 992: m68030ATCLine& a = line[i]; ! 993: if (a.fc == fc) { ! 994: a.Invalidate(); ! 995: } ! 996: } ! 997: } ! 998: ! 999: // FC と addr が一致するエントリをすべてフラッシュ ! 1000: void ! 1001: m68030ATCTable::flush(uint32 fc, uint32 addr) ! 1002: { ! 1003: for (int i = 0; i < countof(line); i++) { ! 1004: m68030ATCLine& a = line[i]; ! 1005: if (a.fc == fc && a.GetLAddr() == addr) { ! 1006: a.Invalidate(); ! 1007: } ! 1008: } ! 1009: } ! 1010: #endif ! 1011: ! 1012: ! 1013: // ! 1014: // テーブルサーチ ! 1015: // ! 1016: ! 1017: // コンストラクタ ! 1018: m68030MMU::m68030MMU(m68kcpu *parent) ! 1019: { ! 1020: cpu = parent; ! 1021: ! 1022: m_type = INVALID; ! 1023: m_s = 0; ! 1024: m_wp = 0; ! 1025: m_m = 0; ! 1026: m_l = 0; ! 1027: m_berr = false; ! 1028: m_debugger = false; ! 1029: m_ptest = false; ! 1030: ! 1031: x = -1; ! 1032: memset(m_lv, 0, sizeof(m_lv)); ! 1033: m_laddr = 0; ! 1034: m_fc = -1; ! 1035: m_desc1 = 0; ! 1036: m_desc2 = 0; ! 1037: m_descsize = 0; ! 1038: m_lastsize = 0; ! 1039: } ! 1040: ! 1041: // テーブルサーチのメイン部分。 ! 1042: // m_type および ATC 作成に必要な情報を埋めてから帰る。 ! 1043: // ATC は帰った先で作成する。 ! 1044: void ! 1045: m68030MMU::search() ! 1046: { ! 1047: const char *rpname; ! 1048: int dt; ! 1049: bool is_super; ! 1050: ! 1051: m_laddr = cpu->bus.laddr; ! 1052: m_fc = cpu->bus.GetFC(); ! 1053: ! 1054: is_super = (m_fc & 0x04); ! 1055: ! 1056: // アドレスを (IS,) TIA .. TID に分解。 ! 1057: // ! 1058: // TIA=$C, TIB=$A, (TIC = TID = 0), PS=$A の場合以下のようにする。 ! 1059: // 使ってない TIC, TID については cpu->mmu_tc->{tic,tid} == 0 で判断する。 ! 1060: // ! 1061: // A B PS ! 1062: // +----------------+--------------+--------------+ ! 1063: // $00A01A00 | 0000 0000 1010 | 0000 0001 10 | xx xxxx xxxx | ! 1064: // +----------------+--------------+--------------+ ! 1065: // shift[TIA] =20 shift[TIB] =10 ! 1066: // lv[TIA].idx=0xA lv[TIB].idx=0x6 ! 1067: // ! 1068: for (int i = TID; i >= TIA; i--) { ! 1069: if (cpu->mmu_tc.tix[i] > 0) { ! 1070: uint32 mask = cpu->mmu_tc.mask[i]; ! 1071: m_lv[i] = (m_laddr >> cpu->mmu_tc.shift[i]) & mask; ! 1072: } ! 1073: } ! 1074: m_lv[FCL] = m_fc; ! 1075: ! 1076: IF_DEBUG { ! 1077: std::string buf; ! 1078: ! 1079: buf += string_format("search: laddr=$%08x ->", m_laddr); ! 1080: if (cpu->mmu_tc.is > 0) ! 1081: buf += string_format(" IS=%d", cpu->mmu_tc.is); ! 1082: if (cpu->mmu_tc.fcl) ! 1083: buf += string_format(" FC=%d", m_lv[FCL]); ! 1084: for (int i = TIA; i <= TID; i++) { ! 1085: if (cpu->mmu_tc.tix[i] > 0) { ! 1086: buf += string_format(" %s=%d($%0*x)", ! 1087: m_lvname[i], cpu->mmu_tc.tix[i], ! 1088: NIBBLE(cpu->mmu_tc.tix[i]), m_lv[i]); ! 1089: } ! 1090: } ! 1091: IPRINTF(2, "%s", buf.c_str()); ! 1092: } ! 1093: ! 1094: // サーチ時の初期化処理。図9-26 ! 1095: m_wp = 0; ! 1096: m_s = 0; ! 1097: ! 1098: // ここから図9-25。 ! 1099: ! 1100: // 使用するルートポインタを決定 ! 1101: if (cpu->mmu_tc.sre && is_super) { ! 1102: rpname = "SRP"; ! 1103: m_desc1 = cpu->GetSRPh(); ! 1104: m_desc2 = cpu->GetSRPl(); ! 1105: } else { ! 1106: rpname = "CRP"; ! 1107: m_desc1 = cpu->GetCRPh(); ! 1108: m_desc2 = cpu->GetCRPl(); ! 1109: } ! 1110: ! 1111: // ルートポインタの DT をチェック ! 1112: dt = GET_DT(m_desc1); ! 1113: DPRINTF(2, "search: %s dt=%s", rpname, dtname(dt)); ! 1114: switch (dt) { ! 1115: case DT_PAGE: // ページディスクリプタ ! 1116: m_type = EARLY; ! 1117: return; ! 1118: ! 1119: case DT_VALID4: // 有効(4バイト) ! 1120: case DT_VALID8: // 有効(8バイト) ! 1121: // descsize は DT=$2 なら 4、DT=$3 なら 8 になる ! 1122: m_descsize = 1 << dt; ! 1123: m_lastsize = 8; ! 1124: break; ! 1125: } ! 1126: ! 1127: // 必要ならファンクションコード・ルックアップ ! 1128: if (cpu->mmu_tc.fcl) { ! 1129: x = FCL; ! 1130: DPRINTF(2, "search: %s tableaddr=$%08x idx=$%x", ! 1131: m_lvname[x], m_desc2, m_lv[x]); ! 1132: ! 1133: // ディスクリプタをフェッチ ! 1134: if (fetch_desc(m_desc2, m_lv[x]) == false) { ! 1135: return; ! 1136: } ! 1137: ! 1138: // ディスクリプタタイプをチェック ! 1139: dt = GET_DT(m_desc1); ! 1140: switch (dt) { ! 1141: case DT_INVALID: // 無効 ! 1142: m_type = INVALID; ! 1143: return; ! 1144: ! 1145: case DT_PAGE: // ページディスクリプタ ! 1146: m_type = EARLY; ! 1147: return; ! 1148: ! 1149: case DT_VALID4: // 有効4バイト ! 1150: case DT_VALID8: // 有効8バイト ! 1151: m_lastsize = m_descsize; ! 1152: m_descsize = 1 << dt; ! 1153: break; ! 1154: } ! 1155: } ! 1156: ! 1157: // TIx のテーブルサーチに入る。図9-25 の下半分。 ! 1158: ! 1159: x = TIA; ! 1160: for (;;) { ! 1161: // リミットチェック ! 1162: if (m_lastsize == 8 && limitcheck() == false) { ! 1163: m_type = INVALID; ! 1164: m_l = 1; ! 1165: return; ! 1166: } ! 1167: ! 1168: // テーブルアドレス ! 1169: uint32 tableaddr; ! 1170: tableaddr = (m_lastsize == 4) ? m_desc1 : m_desc2; ! 1171: tableaddr &= 0xfffffff0; ! 1172: DPRINTF(2, "search: %s tableaddr=$%08x idx=$%x", ! 1173: m_lvname[x], tableaddr, m_lv[x]); ! 1174: ! 1175: // ディスクリプタをフェッチ ! 1176: if (fetch_desc(tableaddr, m_lv[x]) == false) { ! 1177: return; ! 1178: } ! 1179: ! 1180: // ディスクリプタタイプをチェック ! 1181: dt = GET_DT(m_desc1); ! 1182: switch (dt) { ! 1183: case DT_INVALID: // 無効 ! 1184: m_type = INVALID; ! 1185: return; ! 1186: ! 1187: case DT_PAGE: // ページディスクリプタ ! 1188: if (x == TID) { ! 1189: m_type = NORMAL; ! 1190: } else { ! 1191: if (cpu->mmu_tc.tix[x + 1] == 0) { ! 1192: m_type = NORMAL; ! 1193: } else { ! 1194: m_type = EARLY; ! 1195: } ! 1196: } ! 1197: return; ! 1198: ! 1199: case DT_VALID4: // 有効4バイト ! 1200: case DT_VALID8: // 有効8バイト ! 1201: m_lastsize = m_descsize; ! 1202: m_descsize = 1 << dt; ! 1203: ! 1204: if (x == TID || cpu->mmu_tc.tix[x + 1] == 0) { ! 1205: // 間接 ! 1206: m_type = INDIRECT; ! 1207: ! 1208: // ディスクリプタをフェッチ ! 1209: tableaddr = (m_lastsize == 4) ? m_desc1 : m_desc2; ! 1210: tableaddr &= 0xfffffff0; ! 1211: if (fetch_desc(tableaddr, 0) == false) { ! 1212: return; ! 1213: } ! 1214: if (GET_DT(m_desc1) != DT_PAGE) { ! 1215: m_type = INVALID; ! 1216: } ! 1217: return; ! 1218: } ! 1219: // 次段のサーチを繰り返す ! 1220: x++; ! 1221: continue; ! 1222: } ! 1223: } ! 1224: __unreachable(); ! 1225: } ! 1226: ! 1227: // リミットチェックを実行。図9-28。 ! 1228: // 無効のケースに落ちたら false を返す。 ! 1229: bool ! 1230: m68030MMU::limitcheck() const ! 1231: { ! 1232: int lu = (m_desc1 & 0x80000000); ! 1233: uint16 limit = (m_desc1 >> 16) & 0x7fff; ! 1234: ! 1235: if (lu != 0 && m_lv[x] < limit) { ! 1236: return false; ! 1237: } ! 1238: if (lu == 0 && m_lv[x] > limit) { ! 1239: return false; ! 1240: } ! 1241: return true; ! 1242: } ! 1243: ! 1244: // ディスクリプタ中のフラグの更新 (を予約する) ! 1245: #define UPDATE_DESC(flag) do { \ ! 1246: if ((m_desc1 & (flag)) == 0) { \ ! 1247: m_desc1 |= (flag); \ ! 1248: do_write = true; \ ! 1249: } \ ! 1250: } while (0) ! 1251: ! 1252: // ディスクリプタのフェッチと、ヒストリおよびステータスの更新。 ! 1253: // 図9-29。 ! 1254: // ディスクリプタを取得できれば true、 ! 1255: // ATC エントリの作成に向かう場合は false。 ! 1256: bool ! 1257: m68030MMU::fetch_desc(uint32 tableaddr, int idx) ! 1258: { ! 1259: uint32 descaddr; ! 1260: bool do_write; ! 1261: uint dt; ! 1262: ! 1263: // ディスクリプタのアドレスを計算。ここだけマニュアルの説明が雑すぎ。 ! 1264: // インダイレクトなら idx = 0 でコールしてあるので、 ! 1265: // tableaddr がそのまま PA になるという寸法。 ! 1266: descaddr = tableaddr + idx * m_descsize; ! 1267: DPRINTF(2, "fetch_desc: descsize=%d descaddr=$%08x", ! 1268: m_descsize, descaddr); ! 1269: ! 1270: // バスエラー発生フラグをクリアしておく ! 1271: m_berr = false; ! 1272: ! 1273: // ディスクリプタを取得 ! 1274: if (m_debugger) { ! 1275: // デバッガアクセス ! 1276: uint64 data; ! 1277: data = phys_peek_32(descaddr); ! 1278: if ((int64)data < 0) { ! 1279: goto buserr; ! 1280: } ! 1281: m_desc1 = data; ! 1282: ! 1283: if (m_descsize == 8) { ! 1284: data = phys_peek_32(descaddr + 4); ! 1285: if ((int64)data < 0) { ! 1286: goto buserr; ! 1287: } ! 1288: m_desc2 = data; ! 1289: } ! 1290: } else { ! 1291: uint64 data; ! 1292: ! 1293: data = phys_read_32(descaddr); ! 1294: if ((int64)data < 0) { ! 1295: goto buserr; ! 1296: } ! 1297: m_desc1 = data; ! 1298: ! 1299: if (m_descsize == 8) { ! 1300: data = phys_read_32(descaddr + 4); ! 1301: if ((int64)data < 0) { ! 1302: goto buserr; ! 1303: } ! 1304: m_desc2 = data; ! 1305: } ! 1306: } ! 1307: ! 1308: // ディスクリプタタイプをチェック ! 1309: // DT は必ず最初のロングワードの下位2ビット。 ! 1310: do_write = false; ! 1311: dt = GET_DT(m_desc1); ! 1312: DPRINTF(2, "fetch_desc: desc=%s dt=%s", ! 1313: sprintf_desc().c_str(), dtname(dt)); ! 1314: switch (dt) { ! 1315: case DT_INVALID: // 無効 ! 1316: return true; ! 1317: ! 1318: case DT_PAGE: // ページディスクリプタ ! 1319: // U ビットを更新 ! 1320: UPDATE_DESC(MMU_DESC_U); ! 1321: ! 1322: // 書き込み操作なら M を更新 ! 1323: if (cpu->bus.IsWrite() && !m_ptest) { ! 1324: UPDATE_DESC(MMU_DESC_M); ! 1325: } ! 1326: // 図にはないけど、ATC 更新のためと PTEST のために ! 1327: // ページディスクリプタの M ビットを記録。 ! 1328: if ((m_desc1 & MMU_DESC_M)) ! 1329: m_m = 1; ! 1330: break; ! 1331: ! 1332: case DT_VALID4: // 有効4バイト ! 1333: case DT_VALID8: // 有効8バイト ! 1334: // U ビットを更新 ! 1335: UPDATE_DESC(MMU_DESC_U); ! 1336: break; ! 1337: } ! 1338: ! 1339: // デバッガ自身がアドレス変換を実施している時は書き込みは行わない ! 1340: if (m_debugger) { ! 1341: do_write = false; ! 1342: } ! 1343: ! 1344: // ライトライクルの実行 ! 1345: if (do_write) { ! 1346: int64 berr = phys_write_32(descaddr, m_desc1); ! 1347: if (berr < 0) { ! 1348: goto buserr; ! 1349: } ! 1350: // バス動作正常終了 ! 1351: DPRINTF(2, "fetch_desc: desc=%s updated", sprintf_desc().c_str()); ! 1352: } ! 1353: ! 1354: // ステータス更新 ! 1355: // XXX Cache Inhibit ビットは未実装なので、ページディスクリプタと ! 1356: // 有効4/8バイトのケースは同じでよくなる。 ! 1357: // XXX 実際には CI はページディスクリプタにしかないけど ! 1358: m_wp |= (m_desc1 & MMU_DESC_WP) ? 1 : 0; ! 1359: if (m_descsize == 8) { ! 1360: m_s |= (m_desc1 & MMU_DESC_S) ? 1 : 0; ! 1361: } ! 1362: ! 1363: return true; ! 1364: ! 1365: // バスエラー ! 1366: buserr: ! 1367: m_type = INVALID; ! 1368: m_berr = true; ! 1369: return false; ! 1370: } ! 1371: ! 1372: // ATC エントリを作成。実行系用。 ! 1373: // 図9-27 だが雑すぎ。 ! 1374: void ! 1375: m68030MMU::make_atc(m68030ATCLine *a) ! 1376: { ! 1377: std::string buf; ! 1378: uint32 paddr; ! 1379: ! 1380: a->data = 0; ! 1381: switch (m_type) { ! 1382: case INVALID: // 無効 ! 1383: a->data |= m68030ATCLine::BUSERROR; ! 1384: DPRINTF(2, "make_atc: type=INVALID -> BusErr"); ! 1385: return; ! 1386: ! 1387: case NORMAL: // ノーマル ! 1388: case INDIRECT: // 間接 ! 1389: paddr = (m_descsize == 4) ? m_desc1 : m_desc2; ! 1390: DPRINTF(2, "make_atc: type=NORMAL paddr=$%08x", paddr & 0xffffff00); ! 1391: break; ! 1392: ! 1393: case EARLY: // アーリーターミネーション ! 1394: paddr = (m_descsize == 4) ? m_desc1 : m_desc2; ! 1395: buf = string_format("make_atc: type=EARLY paddr=$%08x", ! 1396: paddr & 0xffffff00); ! 1397: ! 1398: // 残ってるビットも足して返す ! 1399: for (int i = x + 1; i <= TID; i++) { ! 1400: if (cpu->mmu_tc.tix[i] > 0) { ! 1401: paddr |= m_lv[i] << cpu->mmu_tc.shift[i]; ! 1402: buf += string_format(" +%s=%08x", m_lvname[i], paddr); ! 1403: } ! 1404: } ! 1405: DPRINTF(2, "%s", buf.c_str()); ! 1406: break; ! 1407: default: ! 1408: __unreachable(); ! 1409: } ! 1410: ! 1411: // PS の部分は反映しない ! 1412: a->paddr = paddr & cpu->mmu_tc.lmask; ! 1413: ! 1414: //if (m_ci) a->data |= m68030ATCLine::CINHIBIT; ! 1415: if (m_wp) ! 1416: a->data |= m68030ATCLine::WPROTECT; ! 1417: if (m_m) ! 1418: a->data |= m68030ATCLine::MODIFIED; ! 1419: } ! 1420: ! 1421: // make_atc() と同様にテーブルサーチの結果から物理ページアドレスを返す。 ! 1422: // バスエラーになるケースなら (uint64)-1 を返す。 ! 1423: // デバッガアクセスなので、VM に一切干渉しない。 ! 1424: uint64 ! 1425: m68030MMU::make_atc_debugger() ! 1426: { ! 1427: uint64 paddr; ! 1428: ! 1429: switch (m_type) { ! 1430: case INVALID: // 無効 ! 1431: return (uint64)-1; ! 1432: break; ! 1433: ! 1434: case NORMAL: // ノーマル ! 1435: case INDIRECT: // 間接 ! 1436: paddr = (m_descsize == 4) ? m_desc1 : m_desc2; ! 1437: paddr &= 0xffffff00; ! 1438: break; ! 1439: ! 1440: case EARLY: // アーリーターミネーション ! 1441: paddr = (m_descsize == 4) ? m_desc1 : m_desc2; ! 1442: paddr &= 0xffffff00; ! 1443: // 残ってるビットも足して返す ! 1444: for (int i = x + 1; i <= TID; i++) { ! 1445: if (cpu->mmu_tc.tix[i] > 0) { ! 1446: paddr |= m_lv[i] << cpu->mmu_tc.shift[i]; ! 1447: } ! 1448: } ! 1449: break; ! 1450: default: ! 1451: __unreachable(); ! 1452: } ! 1453: return paddr; ! 1454: } ! 1455: ! 1456: // 物理メモリからの読み込み。 ! 1457: // 正常に読み込めれば 32bit の値。バスエラーなら (uint64)-1 を返す。 ! 1458: uint64 ! 1459: m68030MMU::phys_read_32(uint32 addr) ! 1460: { ! 1461: m68kbus backup; ! 1462: uint64 data; ! 1463: ! 1464: // バス情報を一旦退避 ! 1465: backup = cpu->bus; ! 1466: ! 1467: // 物理バスアクセス ! 1468: cpu->bus.ssw = SSW_BUS_R | FC_SD; ! 1469: data = m68030_phys_read_32(addr); ! 1470: if ((int64)data < 0) ! 1471: return data; ! 1472: ! 1473: // バス情報を復元 ! 1474: cpu->bus = backup; ! 1475: return data; ! 1476: } ! 1477: ! 1478: // 物理メモリへの書き込み。 ! 1479: // 正常に書き込めれば 0、バスエラーなら (uint64)-1 を返す。 ! 1480: uint64 ! 1481: m68030MMU::phys_write_32(uint32 addr, uint32 data) ! 1482: { ! 1483: m68kbus backup; ! 1484: uint64 berr; ! 1485: ! 1486: // バス情報を一旦退避 ! 1487: backup = cpu->bus; ! 1488: ! 1489: // 物理バスアクセス ! 1490: cpu->bus.ssw = SSW_BUS_W | FC_SD; ! 1491: berr = m68030_phys_write_32(addr, data); ! 1492: if ((int64)berr < 0) ! 1493: return berr; ! 1494: ! 1495: // バス情報を復元 ! 1496: cpu->bus = backup; ! 1497: return 0; ! 1498: } ! 1499: ! 1500: // デバッガによるメモリ読み込み ! 1501: uint64 ! 1502: m68030MMU::phys_peek_32(uint32 addr) ! 1503: { ! 1504: uint64 peekdata; ! 1505: uint32 data; ! 1506: ! 1507: // 1バイト目はバスエラーを検査。 ! 1508: peekdata = m68030_phys_peek_8(addr); ! 1509: if ((int64)peekdata < 0) { ! 1510: // バスエラー ! 1511: return -1; ! 1512: } ! 1513: data = peekdata << 24; ! 1514: ! 1515: // ここはロングワード境界でアクセスしてるはずなので、 ! 1516: // 先頭バイト以外のバスエラーチェックは不要。 ! 1517: data |= m68030_phys_peek_8(addr + 1) << 16; ! 1518: data |= m68030_phys_peek_8(addr + 2) << 8; ! 1519: data |= m68030_phys_peek_8(addr + 3); ! 1520: ! 1521: return data; ! 1522: } ! 1523: ! 1524: // ディスクリプタ表示用の文字列を返す。 ! 1525: // m_descsize によって m_desc1, m_desc2 を適切に文字列にする。 ! 1526: std::string ! 1527: m68030MMU::sprintf_desc() ! 1528: { ! 1529: std::string buf; ! 1530: ! 1531: if (m_descsize == 4) { ! 1532: buf = string_format("%08x", m_desc1); ! 1533: } else { ! 1534: buf = string_format("%08x_%08x", m_desc1, m_desc2); ! 1535: } ! 1536: ! 1537: // フラグの出現条件がややこしいので注意 ! 1538: int dt = GET_DT(m_desc1); ! 1539: buf += string_format(" (%s%s%s%c%c)", ! 1540: ((m_descsize == 4) ? "x" : ((m_desc1 & MMU_DESC_S) ? "S" : "-")), ! 1541: ((dt != DT_PAGE) ? "x" : ((m_desc1 & MMU_DESC_CI) ? "C" : "-")), ! 1542: ((dt != DT_PAGE) ? "x" : ((m_desc1 & MMU_DESC_M) ? "M" : "-")), ! 1543: (m_desc1 & MMU_DESC_U) ? 'U' : '-', ! 1544: (m_desc1 & MMU_DESC_WP) ? 'W' : '-' ! 1545: ); ! 1546: ! 1547: return buf; ! 1548: } ! 1549: ! 1550: // ディスクリプタタイプ文字列 (デバッグ用) ! 1551: const char * ! 1552: m68030MMU::dtname(uint32 dt) ! 1553: { ! 1554: static char buf[32]; ! 1555: switch (dt) { ! 1556: case DT_INVALID: return "invalid"; ! 1557: case DT_PAGE: return "page"; ! 1558: case DT_VALID4: return "valid4"; ! 1559: case DT_VALID8: return "valid8"; ! 1560: } ! 1561: sprintf(buf, "(invalid DT %d)", dt); ! 1562: return buf; ! 1563: } ! 1564: ! 1565: // デバッグ用文字列 ! 1566: const char * const m68030MMU::m_lvname[MAX_LV] = { ! 1567: "TIA", ! 1568: "TIB", ! 1569: "TIC", ! 1570: "TID", ! 1571: "FCL", // この順ではないが、便宜上ここにおいてある ! 1572: }; ! 1573: ! 1574: // ! 1575: // アドレス変換 ! 1576: // ! 1577: ! 1578: // 論理アドレスが TT0/TT1 どちらかと一致すれば true を返す。 ! 1579: // 一致しなければ false を返す。 ! 1580: // 高速化のため mmu_tt_quick による評価は呼び出し側で行なっている。 ! 1581: static bool ! 1582: m68030_check_tt(m68kcpu *cpu) ! 1583: { ! 1584: bool ci; ! 1585: int match; ! 1586: ! 1587: match = 0; ! 1588: ci = false; ! 1589: for (int i = 0; i < 2; i++) { ! 1590: m68030TT& tt = cpu->mmu_tt[i]; ! 1591: if (tt.Match(cpu->bus.ssw_laddr)) { ! 1592: // 一致した ! 1593: match += i + 1; ! 1594: ci |= tt.ci != 0; ! 1595: DPRINTF(1, "check_tt: TT%d match", i); ! 1596: } ! 1597: } ! 1598: ! 1599: // CI は計算はするけど現状未実装なので放置 ! 1600: (void)ci; ! 1601: ! 1602: // 一致したら PA <- LA ! 1603: if (match != 0) { ! 1604: DPRINTF(0, "check_tt: result %08x (match TT%s)", ! 1605: cpu->bus.laddr, ! 1606: (match == 3) ? "0 and TT1" : ((match == 1) ? "0" : "1")); ! 1607: return true; ! 1608: } ! 1609: return false; ! 1610: } ! 1611: ! 1612: // フェッチ用のアドレス変換を行う。 ! 1613: // 変換できれば true、バスエラーなら false を返す。 ! 1614: bool ! 1615: m68030_mmu_translate_fetch(m68kcpu *cpu) ! 1616: { ! 1617: // 状態表示 ! 1618: DPRINTF(0, "translate_fetch: enter %c:$%08x pc=$%08x", ! 1619: (cpu->bus.GetFC() & 0x04) ? 'S' : 'U', ! 1620: cpu->bus.laddr, ! 1621: RegPPC); ! 1622: ! 1623: // まず TT をチェック ! 1624: if (__predict_false(cpu->mmu_tt_quick[cpu->bus.laddr >> 24] != 0)) { ! 1625: if (m68030_check_tt(cpu)) { ! 1626: return true; ! 1627: } ! 1628: } ! 1629: ! 1630: // ATC からアドレスを取得 ! 1631: if (cpu->mmu_tc.e) { ! 1632: const m68030ATCLine& a = cpu->atc.fill_fetch(); ! 1633: if (a.IsBusError()) { ! 1634: DPRINTF(0, "translate_fetch: result BusErr (ATC:B)"); ! 1635: return false; ! 1636: } ! 1637: ! 1638: cpu->bus.paddr = a.GetPAddr(); ! 1639: cpu->bus.paddr |= cpu->bus.laddr & cpu->mmu_tc.pgmask; ! 1640: //cpu->bus.ci = a->ci; ! 1641: } ! 1642: ! 1643: DPRINTF(0, "translate_fetch: result $%08x", cpu->bus.paddr); ! 1644: return true; ! 1645: } ! 1646: ! 1647: // リード用のアドレス変換を行う。 ! 1648: // 変換できれば true、バスエラーなら false を返す。 ! 1649: bool ! 1650: m68030_mmu_translate_read(m68kcpu *cpu) ! 1651: { ! 1652: // 状態表示 ! 1653: DPRINTF(0, "translate_read: enter %c:$%08x pc=%c:$%08x", ! 1654: (cpu->bus.GetFC() & 0x04) ? 'S' : 'U', ! 1655: cpu->bus.laddr, ! 1656: (cpu->reg.s) ? 'S' : 'U', ! 1657: RegPPC); ! 1658: ! 1659: // まず TT をチェック ! 1660: if (__predict_false(cpu->mmu_tt_quick[cpu->bus.laddr >> 24] != 0)) { ! 1661: if (m68030_check_tt(cpu)) { ! 1662: return true; ! 1663: } ! 1664: } ! 1665: ! 1666: // ATC からアドレスを取得 ! 1667: if (cpu->mmu_tc.e) { ! 1668: const m68030ATCLine& a = cpu->atc.fill_read(); ! 1669: if (a.IsBusError()) { ! 1670: DPRINTF(0, "translate_read: result BusErr (ATC:B)"); ! 1671: return false; ! 1672: } ! 1673: ! 1674: cpu->bus.paddr = a.GetPAddr(); ! 1675: cpu->bus.paddr |= cpu->bus.laddr & cpu->mmu_tc.pgmask; ! 1676: //cpu->bus.ci = a->ci; ! 1677: } ! 1678: ! 1679: DPRINTF(0, "translate_read: result $%08x", cpu->bus.paddr); ! 1680: return true; ! 1681: } ! 1682: ! 1683: // ライト用のアドレス変換を行う。 ! 1684: // 変換できれば true、バスエラーなら false を返す。 ! 1685: bool ! 1686: m68030_mmu_translate_write(m68kcpu *cpu) ! 1687: { ! 1688: // 状態表示 ! 1689: DPRINTF(0, "translate_write: enter %c:$%08x pc=%c:$%08x", ! 1690: (cpu->bus.GetFC() & 0x04) ? 'S' : 'U', ! 1691: cpu->bus.laddr, ! 1692: (cpu->reg.s) ? 'S' : 'U', ! 1693: RegPPC); ! 1694: ! 1695: // まず TT をチェック ! 1696: if (__predict_false(cpu->mmu_tt_quick[cpu->bus.laddr >> 24] != 0)) { ! 1697: if (m68030_check_tt(cpu)) { ! 1698: return true; ! 1699: } ! 1700: } ! 1701: ! 1702: // ATC からアドレスを取得 ! 1703: if (cpu->mmu_tc.e) { ! 1704: const m68030ATCLine& a = cpu->atc.fill_write(); ! 1705: if (a.IsBusError()) { ! 1706: DPRINTF(0, "translate_write: result BusErr (ATC:B)"); ! 1707: return false; ! 1708: } ! 1709: if (a.IsWProtect()) { ! 1710: // Write アクセスで WP が立ってたらバスエラー ! 1711: DPRINTF(0, "translate_write: result Buserr (ATC:WP)"); ! 1712: return false; ! 1713: } ! 1714: ! 1715: cpu->bus.paddr = a.GetPAddr(); ! 1716: cpu->bus.paddr |= cpu->bus.laddr & cpu->mmu_tc.pgmask; ! 1717: //cpu->bus.ci = a->ci; ! 1718: } ! 1719: ! 1720: DPRINTF(0, "translate_write: result $%08x", cpu->bus.paddr); ! 1721: return true; ! 1722: } ! 1723: ! 1724: // ピーク用のアドレス変換を行う。 ! 1725: // ATC にエントリが見付からない場合、do_search が true ならテーブル ! 1726: // サーチまで行う。false ならテーブルサーチせずに帰る。 ! 1727: // 変換できれば対応する物理アドレスを、バスエラーなら (uint64)-1 を返す。 ! 1728: uint64 ! 1729: m68030_mmu_translate_peek(m68kcpu *cpu, uint32 laddr, uint fc, bool do_search) ! 1730: { ! 1731: uint64 paddr; ! 1732: ! 1733: // 状態表示 ! 1734: DPRINTF(0, "translate_peek: enter %c:$%08x", ! 1735: (fc & 0x04) ? 'S' : 'U', ! 1736: laddr); ! 1737: ! 1738: // まず TT をチェック ! 1739: paddr = laddr; ! 1740: for (int i = 0; i < 2; i++) { ! 1741: m68030TT& tt = cpu->mmu_tt[i]; ! 1742: uint64 ssw = (uint64)(SSW_BUS_R | fc) << 32; ! 1743: if (tt.Match(ssw | laddr)) { ! 1744: // 一致した。 ! 1745: // CI はここでは使わないため、一致したことだけわかればよい ! 1746: DPRINTF(0, "translate_peek: result $%08x (match tt)", ! 1747: (uint32)paddr); ! 1748: return paddr; ! 1749: } ! 1750: } ! 1751: ! 1752: // 次に TC (ATC と MMU テーブルサーチ)。 ! 1753: if (cpu->mmu_tc.e) { ! 1754: // ATC からこっそりアドレスを取得 ! 1755: paddr = cpu->atc.fill_peek(laddr & cpu->mmu_tc.lmask, fc); ! 1756: if ((int64)paddr >= 0) { ! 1757: paddr |= laddr & cpu->mmu_tc.pgmask; ! 1758: DPRINTF(0, "translate_peek: result $%08x (match atc)", ! 1759: (uint32)paddr); ! 1760: return paddr; ! 1761: } ! 1762: ! 1763: // 見付からなかったのでこっそりテーブルサーチ。 ! 1764: if (do_search) { ! 1765: // mmu.search() はさすがに cpu->bus を使うので事前に退避。 ! 1766: m68kbus backup = cpu->bus; ! 1767: ! 1768: cpu->bus.laddr = laddr; ! 1769: cpu->bus.ssw = fc; ! 1770: m68030MMU mmu(cpu); ! 1771: mmu.m_debugger = true; ! 1772: mmu.search(); ! 1773: paddr = mmu.make_atc_debugger(); ! 1774: // リストア ! 1775: cpu->bus = backup; ! 1776: ! 1777: if ((int64)paddr >= 0) { ! 1778: paddr |= laddr & cpu->mmu_tc.pgmask; ! 1779: DPRINTF(0, "translate_peek: result $%08x (table search)", ! 1780: (uint32)paddr); ! 1781: return paddr; ! 1782: } ! 1783: } ! 1784: } ! 1785: ! 1786: DPRINTF(0, "translate_peek: result BusErr"); ! 1787: return (uint64)-1; ! 1788: } ! 1789: ! 1790: // ! 1791: // 命令 ! 1792: // ! 1793: ! 1794: // MMU 命令からの呼び出し用。 ! 1795: // XXX 命令によってこの中のいずれかの EA に対応していないものがあれば調査。 ! 1796: // XXX クロック未調査。 ! 1797: static inline uint32 ! 1798: cea_mmu(m68kcpu *cpu) ! 1799: { ! 1800: uint mm = eamode(RegIR); ! 1801: uint rr = eanum(RegIR); ! 1802: ! 1803: switch (mm) { ! 1804: case 0: // Dn ! 1805: case 1: // An ! 1806: break; ! 1807: ! 1808: case 2: // (An) ! 1809: return cea_anin(cpu, rr); ! 1810: ! 1811: case 3: // (An)+ ! 1812: case 4: // -(An) ! 1813: break; ! 1814: ! 1815: case 5: // d16(An) ! 1816: return cea_andi(cpu, rr); ! 1817: case 6: // (An,IX) ! 1818: return cea_anix(cpu, rr); ! 1819: case 7: ! 1820: switch (rr) { ! 1821: case 0: // Abs.W ! 1822: return cea_absw(cpu); ! 1823: case 1: // Abs.L ! 1824: return cea_absl(cpu); ! 1825: default: ! 1826: break; ! 1827: } ! 1828: break; ! 1829: } ! 1830: // 不当命令 ! 1831: throw M68K_EXCEP_ILLEGAL; ! 1832: } ! 1833: ! 1834: // RegIR2 の下位5ビットから FC を返す。 ! 1835: // 不当パターンなら C++ の例外をスローする。 ! 1836: static uint32 ! 1837: get_fc(m68kcpu *cpu) ! 1838: { ! 1839: uint fcfield = RegIR2 & 0x1f; ! 1840: ! 1841: if (fcfield == 0) { ! 1842: return RegSFC; ! 1843: } else if (fcfield == 1) { ! 1844: return RegDFC; ! 1845: } else if (fcfield < 0x08) { ! 1846: // break; ! 1847: } else if (fcfield < 0x10) { ! 1848: return RegD(fcfield & 7) & 7; ! 1849: } else if (fcfield < 0x18) { ! 1850: return fcfield & 7; ! 1851: } ! 1852: // 不当命令 ! 1853: throw M68K_EXCEP_ILLEGAL; ! 1854: } ! 1855: ! 1856: // MMU 不当命令 (2ワード目で確定) ! 1857: void ! 1858: mmu_op_illg2(m68kcpu *cpu) ! 1859: { ! 1860: cpulog(1, "MMU 不当命令 %04x %04x", RegIR, RegIR2); ! 1861: m68030_exception(cpu, M68K_EXCEP_FLINE); ! 1862: } ! 1863: ! 1864: // PFLUSH fc,#mask 命令 (EA を持たない方) ! 1865: void ! 1866: mmu_op_pflush(m68kcpu *cpu) ! 1867: { ! 1868: uint32 mask; ! 1869: uint32 fc; ! 1870: ! 1871: mask = (RegIR2 >> 5) & 7; ! 1872: fc = get_fc(cpu); ! 1873: cpu->atc.flush(fc, mask); ! 1874: } ! 1875: ! 1876: // PFLUSH fc,#mask,ea 命令 ! 1877: void ! 1878: mmu_op_pflush_ea(m68kcpu *cpu) ! 1879: { ! 1880: uint32 ea; ! 1881: uint32 mask; ! 1882: uint32 fc; ! 1883: ! 1884: ea = cea_mmu(cpu); ! 1885: mask = (RegIR2 >> 5) & 7; ! 1886: fc = get_fc(cpu); ! 1887: cpu->atc.flush(fc, mask, ea); ! 1888: } ! 1889: ! 1890: // PLOADR/PLOADW 命令 ! 1891: void ! 1892: mmu_op_pload(m68kcpu *cpu) ! 1893: { ! 1894: uint32 ea; ! 1895: uint32 fc; ! 1896: ! 1897: if ((RegIR2 & 0x01e0) != 0) { ! 1898: mmu_op_illg2(cpu); ! 1899: return; ! 1900: } ! 1901: ea = cea_mmu(cpu); ! 1902: fc = get_fc(cpu); ! 1903: ! 1904: // 実効アドレスを論理アドレスとする ATC を作成。 ! 1905: // ってこれでいいのか? ! 1906: cpu->bus.laddr = ea; ! 1907: if ((RegIR2 & 0x0200)) { ! 1908: cpu->bus.ssw = SSW_BUS_R | fc; ! 1909: cpu->atc.fill_read(); ! 1910: } else { ! 1911: cpu->bus.ssw = SSW_BUS_W | fc; ! 1912: cpu->atc.fill_write(); ! 1913: } ! 1914: } ! 1915: ! 1916: // PTESTR/PTESTW 命令 ! 1917: // XXX てきとー ! 1918: void ! 1919: mmu_op_ptest(m68kcpu *cpu) ! 1920: { ! 1921: uint level = (RegIR2 >> 10) & 7; ! 1922: uint rw = (RegIR2 & 0x0200) ? SSW_BUS_R : SSW_BUS_W; ! 1923: uint32 ea; ! 1924: uint32 fc; ! 1925: uint16 mmusr; ! 1926: ! 1927: ea = cea_mmu(cpu); ! 1928: fc = get_fc(cpu); ! 1929: ! 1930: if (level == 0) { ! 1931: cpulog(0, "未実装 PTEST %04x %04x", RegIR, RegIR2); ! 1932: return; ! 1933: } ! 1934: if ((RegIR2 & 0x0100)) { ! 1935: cpulog(0, "未実装 PTEST %04x %04x", RegIR, RegIR2); ! 1936: return; ! 1937: } ! 1938: ! 1939: // テーブルサーチを実行 ! 1940: cpu->bus.laddr = ea; ! 1941: cpu->bus.ssw = rw | fc; ! 1942: m68030MMU table(cpu); ! 1943: table.m_ptest = true; ! 1944: table.search(); ! 1945: // 結果を MMUSR に格納 ! 1946: mmusr = 0; ! 1947: if (level == 0) { ! 1948: if (table.m_type == INVALID) { ! 1949: mmusr |= m68030MMUSR::B; ! 1950: } ! 1951: } else { ! 1952: if (table.m_berr) { ! 1953: mmusr |= m68030MMUSR::B; ! 1954: } ! 1955: } ! 1956: if (table.m_l) { ! 1957: mmusr |= m68030MMUSR::L; ! 1958: } ! 1959: if (table.m_s && (fc & 4)) { ! 1960: mmusr |= m68030MMUSR::S; ! 1961: } ! 1962: if (table.m_wp) { ! 1963: mmusr |= m68030MMUSR::W; ! 1964: } ! 1965: if (table.m_type == INVALID) { ! 1966: mmusr |= m68030MMUSR::I; ! 1967: } ! 1968: if (table.m_m) { ! 1969: mmusr |= m68030MMUSR::M; ! 1970: } ! 1971: // XXX N 未実装 ! 1972: mmusr |= 1; ! 1973: ! 1974: cpu->SetMMUSR(mmusr); ! 1975: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.