|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2025 nono project ! 4: // Licensed under nono-license.txt ! 5: // ! 6: ! 7: // ! 8: // ページテーブルモニター ! 9: // ! 10: ! 11: #include "wxpagetablemonitor.h" ! 12: #include "wxmainframe.h" ! 13: #include "wxscrollbar.h" ! 14: #include "wxtextscreen.h" ! 15: #include "mainbus.h" ! 16: #include "mpu680x0.h" ! 17: #include "m68040mmu.h" ! 18: ! 19: enum { ! 20: ID_SRP, ! 21: ID_URP, ! 22: ID_LADDR, ! 23: ID_SCROLL_0 = IDGROUP_PAGETABLE, ! 24: ID_SCROLL_4 = ID_SCROLL_0 + 4, ! 25: ! 26: ID_local_end, // 最後に置く (チェック用) ! 27: }; ! 28: static_assert(ID_local_end - 1 <= (int)IDGROUP_PAGETABLE_END, "ID exceeded"); ! 29: ! 30: static constexpr int HEAD_ROW = 2; // テーブルのヘッダ行数 ! 31: ! 32: // ! 33: // ページテーブルの1段階 ! 34: // ! 35: ! 36: // コンストラクタ ! 37: PageTable::PageTable(wxWindow *parent, int lv_, int width) ! 38: { ! 39: const int height = 32 + HEAD_ROW; ! 40: ! 41: lv = lv_; ! 42: screen = new WXTextScreen(parent, nnSize(width, height)); ! 43: vscroll = new WXScrollBar(parent, ID_SCROLL_0 + lv, wxSB_VERTICAL); ! 44: vscroll->SetScrollParam(0, height, height, height); ! 45: } ! 46: ! 47: // パラメータをクリアする。(インデックスとコントロールはそのまま) ! 48: void ! 49: PageTable::Clear() ! 50: { ! 51: title = ""; ! 52: head = ""; ! 53: base = 0xffffffff; ! 54: mask = 0; ! 55: bitpos = 0; ! 56: bitlen = 0; ! 57: count = 0; ! 58: cursor = 0; ! 59: } ! 60: ! 61: // 指定位置のアドレスを返す。 ! 62: uint32 ! 63: PageTable::GetAddr(int idx) const ! 64: { ! 65: if (__predict_false(base == 0xffffffff)) { ! 66: return base; ! 67: } else { ! 68: return base + idx * 4; ! 69: } ! 70: } ! 71: ! 72: // 表示開始位置を返す。 ! 73: int ! 74: PageTable::ViewTop() const ! 75: { ! 76: if (__predict_false(vscroll == NULL)) { ! 77: return 0; ! 78: } ! 79: return vscroll->GetThumbPosition(); ! 80: } ! 81: ! 82: // このテーブルのコントロールの表示状態を制御する。 ! 83: void ! 84: PageTable::Show(bool enable) ! 85: { ! 86: screen->Show(enable); ! 87: vscroll->Show(enable); ! 88: } ! 89: ! 90: ! 91: // ! 92: // ページテーブルウィンドウ (共通部分) ! 93: // ! 94: ! 95: // +-------------------------------------------------+ ! 96: // | wxPanel *ctrlpanel | ! 97: // | (wx 製のコントロールパネル、横目一杯まで伸びる) | ! 98: // +-------------------------------------------------+ ! 99: // | WXTextScreen *stat | ! 100: // | (横目一杯のテキスト情報) | ! 101: // +-----------------+-----------------+--- ---+ ! 102: // | PageTable[0] | PageTable[1] | ... | ! 103: // | (TIA 情報) | (TIB 情報) | | ! 104: // +-----------------+-----------------+-------------+ ! 105: // ! 106: // PageTable 内の段組み。空き地のところは下の bgpanel を見せる。 ! 107: // +--------+---------+ ! 108: // | | (空き地)| ! 109: // | screen +---------+ ! 110: // | | vscroll | ! 111: // +--------+---------+ ! 112: ! 113: // イベントテーブル ! 114: wxBEGIN_EVENT_TABLE(WXPageTableWindow, inherited) ! 115: EVT_TIMER(wxID_ANY, WXPageTableWindow::OnTimer) ! 116: EVT_RADIOBUTTON(ID_SRP, WXPageTableWindow::OnRPChanged) ! 117: EVT_RADIOBUTTON(ID_URP, WXPageTableWindow::OnRPChanged) ! 118: wxEND_EVENT_TABLE() ! 119: ! 120: // コンストラクタ ! 121: WXPageTableWindow::WXPageTableWindow(wxWindow *parent, const wxString& name) ! 122: : inherited(parent, wxID_ANY, name, DEFAULT_STYLE | wxRESIZE_BORDER) ! 123: { ! 124: timer.SetOwner(this); ! 125: ! 126: mainbus = GetMainbusDevice(); ! 127: ! 128: // 幅は実行時に伸ばす。 ! 129: stat = new WXTextScreen(this, nnSize(1, 1)); ! 130: ! 131: // コントロールパネル(のまず下敷き)。 ! 132: ctrlpanel = new wxPanel(this); ! 133: ctrlpanel->SetName(name + ".CtrlPanel"); ! 134: auto *ctrlbox = new wxBoxSizer(wxHORIZONTAL); ! 135: ! 136: // SRP, URP 選択ラジオボタン。 ! 137: // 68040 はこの名前で固定。68030 は実行時に表示名を切り替える。 ! 138: auto *rpbox = new wxStaticBoxSizer(wxHORIZONTAL, ctrlpanel, ! 139: _("Root Pointer")); ! 140: radio_srp = new wxRadioButton(ctrlpanel, ID_SRP, "SRP"); ! 141: radio_urp = new wxRadioButton(ctrlpanel, ID_URP, "URP"); ! 142: rpbox->Add(radio_srp); ! 143: rpbox->Add(radio_urp); ! 144: // GTK3 標準のレンダリングだとコントロールの周りの空きがなさすぎて ! 145: // 特にスタティックボックスは読みづらいので自力で少し空ける。どうして…。 ! 146: ctrlbox->Add(rpbox, 0, wxALIGN_CENTER_VERTICAL | wxALL, 3); ! 147: ! 148: #if 0 // not yet ! 149: // アドレス欄。 ! 150: ctrlbox->Add(new wxStaticText(ctrlpanel, wxID_ANY, _("Logical Address:")), ! 151: 0, wxALIGN_CENTER_VERTICAL | wxALL, 3); ! 152: ctrlbox->Add(new wxTextCtrl(ctrlpanel, ID_LADDR, ! 153: wxEmptyString, wxDefaultPosition, wxDefaultSize, ! 154: wxTE_PROCESS_ENTER), ! 155: 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxRIGHT | wxBOTTOM, 3); ! 156: #endif ! 157: ! 158: // sizer と下敷きパネルを紐付ける。 ! 159: ctrlpanel->SetSizer(ctrlbox); ! 160: ctrlbox->SetSizeHints(ctrlpanel); ! 161: ! 162: // 表部分の下敷きパネル。 ! 163: bgpanel = new WXTextPanel(this); ! 164: ! 165: // モニタと同じ更新レートを適用。 ! 166: auto mainframe = dynamic_cast<WXMainFrame *>(parent); ! 167: SetRate(mainframe->GetMonitorRate()); ! 168: ! 169: // 自前レイアウト。 ! 170: SetMyLayout(); ! 171: ! 172: // 最初に一回描画を起こす。 ! 173: wxTimerEvent dummy(timer); ! 174: AddPendingEvent(dummy); ! 175: } ! 176: ! 177: // デストラクタ ! 178: WXPageTableWindow::~WXPageTableWindow() ! 179: { ! 180: } ! 181: ! 182: // 継承先のコンストラクタで table 設定後に呼ぶこと。 ! 183: void ! 184: WXPageTableWindow::ConnectTableEvents() ! 185: { ! 186: for (auto& t : table) { ! 187: // パネルで起きた LeftDClick, MouseWheel をこっちで受け取る。 ! 188: t.screen->Bind(wxEVT_LEFT_DCLICK, ! 189: &WXPageTableWindow::OnLeftDClick, this); ! 190: t.screen->Bind(wxEVT_MOUSEWHEEL, ! 191: &WXPageTableWindow::OnMouseWheel, this); ! 192: } ! 193: } ! 194: ! 195: bool ! 196: WXPageTableWindow::GetMySizeHints(wxSize *newp, wxSize *minp, wxSize *maxp, ! 197: wxSize *incp) ! 198: { ! 199: int ctrl_minx = ctrlpanel->GetMinSize().x; ! 200: int ctrl_y = ctrlpanel->GetSize().y; ! 201: #if 0 ! 202: int stat_y = stat->GetSize().y; ! 203: #else ! 204: int stat_y = 0; ! 205: #endif ! 206: int table_y = ctrl_y + stat_y; ! 207: ! 208: int new_x = 0; ! 209: int new_y = table_y; ! 210: int min_y = table_y; ! 211: int max_y = table_y; ! 212: ! 213: // テーブルがない場合でも、メッセージを表示するため ! 214: // 計算上1段分はあることにする。 ! 215: for (int i = 0, end = table_count ?: 1; i < end; i++) { ! 216: const auto& t = table[i]; ! 217: new_x += t.screen->GetSize().x; ! 218: new_x += t.vscroll->GetSize().x; ! 219: } ! 220: if (new_x < ctrl_minx) { ! 221: new_x = ctrl_minx; ! 222: } ! 223: ! 224: new_y += table[0].screen->GetScreenHeight(32 + HEAD_ROW); ! 225: ! 226: // 高さの最小は (ヘッダ分と) TextScreen 2行分にしておく。 ! 227: min_y += table[0].screen->GetScreenHeight(1 + HEAD_ROW); ! 228: ! 229: // 高さの最大はエントリ分。 ! 230: int row = max_rows > 0 ? (max_rows + HEAD_ROW) : (32 + HEAD_ROW); ! 231: max_y += table[0].screen->GetScreenHeight(row); ! 232: ! 233: int inc_y = table[0].screen->GetFontHeight(); ! 234: ! 235: wxSize newsize(new_x, new_y); ! 236: wxSize minsize(new_x, min_y); ! 237: wxSize maxsize(new_x, max_y); ! 238: wxSize incsize(0, inc_y); ! 239: ! 240: if (newp) *newp = newsize; ! 241: if (minp) *minp = minsize; ! 242: if (maxp) *maxp = maxsize; ! 243: if (incp) *incp = incsize; ! 244: return true; ! 245: } ! 246: ! 247: bool ! 248: WXPageTableWindow::Layout() ! 249: { ! 250: if (MyLayout() == false) { ! 251: // コントロールを配置。 ! 252: wxSize client = GetClientSize(); ! 253: int ctrl_y = ctrlpanel->GetSize().y; ! 254: #if 0 ! 255: int stat_y = stat->GetSize().y; ! 256: #else ! 257: int stat_y = 0; ! 258: #endif ! 259: int table_y = ctrl_y + stat_y; ! 260: int table_h = client.y - table_y; ! 261: ! 262: ctrlpanel->SetSize(0, 0, client.x, ctrl_y); ! 263: #if 0 ! 264: stat->SetSize(0, ctrl_y, client.x, stat_y); ! 265: #else ! 266: stat->Hide(); ! 267: #endif ! 268: ! 269: // 背景パネル。 ! 270: // テーブル数が 0 だと無効メッセージの表示を兼ねる。 ! 271: bgpanel->SetSize(0, table_y, client.x, table_h); ! 272: if (table_count == 0) { ! 273: bgpanel->DrawStringSJIS(UD_BLACK, ! 274: WXTextScreen::DefaultPadding, WXTextScreen::DefaultPadding, ! 275: "MMU TC Not Configured"); ! 276: } else { ! 277: bgpanel->Fill(); ! 278: } ! 279: ! 280: int x = 0; ! 281: int i; ! 282: for (i = 0; i < table_count; i++) { ! 283: auto& t = table[i]; ! 284: ! 285: int screen_w = t.screen->GetSize().x; ! 286: t.screen->SetSize(x, table_y, screen_w, table_h); ! 287: x += screen_w; ! 288: ! 289: int vscroll_w = t.vscroll->GetSize().x; ! 290: // スクロールバーの上端を表の上端と揃える。 ! 291: int head_h = t.screen->GetFontHeight() * HEAD_ROW ! 292: + t.screen->GetPaddingTop(); ! 293: t.vscroll->SetSize(x, table_y + head_h, ! 294: vscroll_w, table_h - head_h); ! 295: x += vscroll_w; ! 296: ! 297: int thumbsize = std::min(t.count, t.screen->GetRow() - HEAD_ROW); ! 298: t.vscroll->SetScrollParam(thumbsize, t.count, thumbsize); ! 299: ! 300: t.Show(); ! 301: } ! 302: for (; i < table.size(); i++) { ! 303: auto& t = table[i]; ! 304: t.Hide(); ! 305: } ! 306: ! 307: DoRefresh(); ! 308: } ! 309: return true; ! 310: } ! 311: ! 312: // 画面更新頻度を Hz で設定する。 ! 313: void ! 314: WXPageTableWindow::SetRate(int hz) ! 315: { ! 316: timer.Start(1000 / hz); ! 317: } ! 318: ! 319: void ! 320: WXPageTableWindow::OnTimer(wxTimerEvent& event) ! 321: { ! 322: DoRefresh(); ! 323: } ! 324: ! 325: // ルートポインタのラジオボタン変更イベント ! 326: void ! 327: WXPageTableWindow::OnRPChanged(wxCommandEvent& event) ! 328: { ! 329: show_urp = (event.GetId() == ID_URP); ! 330: DoRefresh(); ! 331: } ! 332: ! 333: // テーブルパネル上で起きたダブルクリックイベント ! 334: void ! 335: WXPageTableWindow::OnLeftDClick(wxMouseEvent& event) ! 336: { ! 337: // 対応するテーブルを探す。 ! 338: auto *sender = event.GetEventObject(); ! 339: for (auto& t : table) { ! 340: if (sender == t.screen) { ! 341: auto pxpos = event.GetPosition(); ! 342: auto y = t.screen->GetTextPosition(pxpos).y - HEAD_ROW; ! 343: if (y >= 0) { ! 344: // この行を選択。 ! 345: t.cursor = t.ViewTop() + y; ! 346: DoRefresh(); ! 347: } ! 348: break; ! 349: } ! 350: } ! 351: } ! 352: ! 353: // テーブルパネル上で起きたマウスホイールイベント ! 354: void ! 355: WXPageTableWindow::OnMouseWheel(wxMouseEvent& event) ! 356: { ! 357: // 対応するスクロールバーに再送して処理してもらう。 ! 358: auto *sender = event.GetEventObject(); ! 359: for (auto& t : table) { ! 360: if (sender == t.screen) { ! 361: wxPostEvent(t.vscroll, event); ! 362: break; ! 363: } ! 364: } ! 365: } ! 366: ! 367: ! 368: // ! 369: // ページテーブルウィンドウ (68030) ! 370: // ! 371: ! 372: // コンストラクタ ! 373: WXPageTable68030Window::WXPageTable68030Window(wxWindow *parent, ! 374: const wxString& name) ! 375: : inherited(parent, name) ! 376: { ! 377: mpu = dynamic_cast<MPU68030Device *>(GetMPUDevice()); ! 378: ! 379: // 68030 はバラエティ豊かすぎてフルサポートは困難なので ! 380: // とりあえず最大 3段として、過剰分は表示で誤魔化す…。 ! 381: table.emplace_back(this, 0, 41); ! 382: table.emplace_back(this, 1, 41); ! 383: table.emplace_back(this, 2, 41); ! 384: ConnectTableEvents(); ! 385: ! 386: // 最初に一度 MPU の現状を適用する。 ! 387: // (以降はタイマー内で毎回チェックする) ! 388: Reconfig(mpu->GetTC()); ! 389: ! 390: // ウィンドウサイズを確定させる。 ! 391: FontChanged(); ! 392: } ! 393: ! 394: // デストラクタ ! 395: WXPageTable68030Window::~WXPageTable68030Window() ! 396: { ! 397: } ! 398: ! 399: // MMU の構成を適用する。 ! 400: void ! 401: WXPageTable68030Window::Reconfig(uint32 new_tc_value) ! 402: { ! 403: tc_value = new_tc_value; ! 404: ! 405: // TC の構成が正しくて E がオフならグレーで表示とかは出来るが、 ! 406: // (E がオフで) TC の構成が無効なら出来ることは何もない。 ! 407: m68030TC new_tc; ! 408: new_tc.Set(new_tc_value); ! 409: if (new_tc.ConfigOK() == false) { ! 410: // 構成が無効。 ! 411: tc_status = TC_NOT_CONFIG; ! 412: max_rows = 8; ! 413: for (auto& t : table) { ! 414: t.Clear(); ! 415: t.count = max_rows; ! 416: } ! 417: table_count = 0; ! 418: } else { ! 419: if (new_tc.e) { ! 420: tc_status = TC_ENABLE; ! 421: } else { ! 422: tc_status = TC_DISABLE; ! 423: } ! 424: ! 425: for (auto& t : table) { ! 426: t.Clear(); ! 427: } ! 428: table_count = new_tc.termlv + 1; ! 429: ! 430: int total_bits = new_tc.is; ! 431: max_rows = 0; ! 432: for (uint i = 0; i < table_count; i++) { ! 433: auto& t = table[i]; ! 434: ! 435: // ビット位置。 ! 436: t.bitlen = new_tc.tix[t.lv]; ! 437: total_bits += t.bitlen; ! 438: t.bitpos = 32 - total_bits; ! 439: ! 440: // 行数。 ! 441: t.count = 1U << t.bitlen; ! 442: max_rows = std::max(max_rows, t.count); ! 443: ! 444: // 見出し。 ! 445: t.title = string_format("TI%c (%u bit)", 'A' + t.lv, t.bitlen); ! 446: t.head = "LAddress At Address Flag DT"; ! 447: ! 448: // 次段アドレスのマスクは固定。 ! 449: t.mask = ~0x000f; ! 450: } ! 451: } ! 452: ! 453: // ルートポインタの表示。68030 のルートポインタは ! 454: // (TC.SRE && スーパーバイザ状態) なら SRP、それ以外は CRP という構造。 ! 455: if (new_tc.sre) { ! 456: radio_srp->SetLabel(_("Supervisor (SRP)")); ! 457: } else { ! 458: radio_srp->SetLabel(_("Supervisor (CRP)")); ! 459: } ! 460: radio_urp->SetLabel(_("User (CRP)")); ! 461: ! 462: Fit(); ! 463: } ! 464: ! 465: // 画面を更新して再描画する。 ! 466: void ! 467: WXPageTable68030Window::DoRefresh() ! 468: { ! 469: // MMU 構成に変更があれば再構築。 ! 470: uint32 new_tc_value = mpu->GetTC(); ! 471: if (tc_value != new_tc_value) { ! 472: Reconfig(new_tc_value); ! 473: } ! 474: ! 475: for (auto& t : table) { ! 476: t.base = 0xffffffff; ! 477: } ! 478: ! 479: if (tc_status != TC_NOT_CONFIG) { ! 480: if (mpu->mmu_tc.sre && show_urp == false) { ! 481: table[0].base = mpu->GetSRPl(); ! 482: } else { ! 483: table[0].base = mpu->GetCRPl(); ! 484: } ! 485: table[0].base &= table[0].mask; ! 486: ! 487: uint64 data2 = mainbus->Peek4(table[0].GetAddr()); ! 488: if ((int64)data2 >= 0 && (data2 & 0x03) != 0) { ! 489: table[1].base = data2 & table[0].mask; ! 490: } ! 491: } ! 492: ! 493: uint32 laddr = 0; ! 494: for (auto& t : table) { ! 495: // この段の論理アドレスの可変部分の文字列長を求める。 ! 496: int ln = 8 - (t.bitpos / 4); ! 497: ! 498: auto& screen = t.screen->GetScreen(); ! 499: screen.Clear(); ! 500: ! 501: TA attr_t = (tc_status == TC_DISABLE) ? TA::Disable : TA::Normal; ! 502: screen.Puts(0, 0, attr_t, (const char *)t.title.mb_str()); ! 503: screen.Puts(1, 1, attr_t, (const char *)t.head.mb_str()); ! 504: // 構成無効ならタイトルメッセージだけ表示。 ! 505: if (tc_status == TC_NOT_CONFIG) { ! 506: continue; ! 507: } ! 508: ! 509: const int end = std::min(screen.GetRow(), t.count + HEAD_ROW); ! 510: for (uint y = HEAD_ROW, i = t.ViewTop(); y < end; y++, i++) { ! 511: uint32 addr; ! 512: uint32 data; ! 513: if (__predict_false(t.base == 0xffffffff)) { ! 514: addr = t.base; ! 515: data = 0; ! 516: } else { ! 517: addr = t.GetAddr(i); ! 518: data = mainbus->Peek4(addr); ! 519: } ! 520: TA attr_i; ! 521: TA attr_a; ! 522: TA attr_v; ! 523: if (__predict_true(tc_status == TC_ENABLE)) { ! 524: attr_i = TA::Normal; ! 525: attr_a = TA::Normal; ! 526: attr_v = TA::Normal; ! 527: } else { ! 528: attr_i = TA::Disable; ! 529: attr_a = TA::Disable; ! 530: attr_v = TA::Disable; ! 531: } ! 532: if (__predict_false(i == t.cursor)) { ! 533: attr_i = TA::Reverse; ! 534: attr_a = TA::Reverse; ! 535: attr_v = TA::Reverse; ! 536: } ! 537: if (__predict_false((int64)data < 0)) { ! 538: attr_a = TA::Disable; ! 539: attr_v = TA::Disable; ! 540: } else if ((data & 0x03) == 0) { ! 541: attr_v = TA::Disable; ! 542: } ! 543: ! 544: char lbuf[16]; ! 545: snprintf(lbuf, sizeof(lbuf), "[%08x0] ", laddr | (i << t.bitpos)); ! 546: lbuf[1 + ln] = '\''; ! 547: screen.Puts(0, y, attr_i, lbuf); ! 548: screen.Print(12, y, attr_a, "$%08x ", addr); ! 549: screen.Print(22, y, attr_v, "%08x ", (uint32)data & t.mask); ! 550: int x = 31; ! 551: uint32 dt = data & 0x03; ! 552: // 68030 は実際には何段目がページではなくて、 ! 553: // DT=0x01 のディスクリプタに出会ったらそれがページディスクリプタ ! 554: // という構造なので、ディスクリプタによって書式を変えない方がいい。 ! 555: if (dt == 1) { ! 556: screen.Putc(x++, y, attr_v, (data & 0x40) ? 'C' : '-'); ! 557: screen.Putc(x++, y, attr_v, (data & 0x10) ? 'M' : '-'); ! 558: } else { ! 559: screen.Putc(x++, y, attr_v, ' '); ! 560: screen.Putc(x++, y, attr_v, ' '); ! 561: } ! 562: screen.Putc(x++, y, attr_v, (data & 0x08) ? 'U' : '-'); ! 563: screen.Putc(x++, y, attr_v, (data & 0x04) ? 'P' : '-'); ! 564: static const char * const dtstr[4] = { ! 565: // 反転カーソルの見栄えのため空白込みで長さを揃える。 ! 566: "-----", ! 567: "Page ", ! 568: "Short", ! 569: "Long ", ! 570: }; ! 571: screen.Putc(x++, y, attr_v, ' '); ! 572: screen.Puts(x, y, attr_v, dtstr[dt]); ! 573: } ! 574: ! 575: // 次段の論理アドレス。 ! 576: laddr |= (t.cursor << t.bitpos); ! 577: } ! 578: ! 579: Refresh(); ! 580: } ! 581: ! 582: ! 583: // ! 584: // ページテーブルウィンドウ (68040) ! 585: // ! 586: ! 587: // コンストラクタ ! 588: WXPageTable68040Window::WXPageTable68040Window(wxWindow *parent, ! 589: const wxString& name) ! 590: : inherited(parent, name) ! 591: { ! 592: mpu = dynamic_cast<MPU68040Device *>(GetMPUDevice()); ! 593: ! 594: // 68040 は 3段固定。 ! 595: table.emplace_back(this, 0, 33); ! 596: table.emplace_back(this, 1, 33); ! 597: table.emplace_back(this, 2, 36); ! 598: ConnectTableEvents(); ! 599: ! 600: // 最初に一度 MPU の現状を適用する。 ! 601: // (以降はタイマー内で毎回チェックする) ! 602: Reconfig(mpu->GetTC()); ! 603: ! 604: // ウィンドウサイズを確定させる。 ! 605: FontChanged(); ! 606: } ! 607: ! 608: // デストラクタ ! 609: WXPageTable68040Window::~WXPageTable68040Window() ! 610: { ! 611: } ! 612: ! 613: // MMU の構成を適用する。 ! 614: void ! 615: WXPageTable68040Window::Reconfig(uint32 new_tc_value) ! 616: { ! 617: tc_value = new_tc_value; ! 618: ! 619: // 68040 の MMU に構成不能状態はない。 ! 620: if ((new_tc_value & m68040TC::E)) { ! 621: tc_status = TC_ENABLE; ! 622: } else { ! 623: tc_status = TC_DISABLE; ! 624: } ! 625: if ((new_tc_value & m68040TC::P)) { ! 626: ps4k = false; ! 627: } else { ! 628: ps4k = true; ! 629: } ! 630: ! 631: // 各テーブルの行数と見出し。 ! 632: table_count = 3; ! 633: table[0].bitlen = 7; ! 634: table[1].bitlen = 7; ! 635: table[0].bitpos = 25; ! 636: table[1].bitpos = 18; ! 637: table[0].title = "TIA (7 bit)"; ! 638: table[1].title = "TIB (7 bit)"; ! 639: if (ps4k) { ! 640: table[2].bitlen = 6; ! 641: table[2].bitpos = 12; ! 642: table[2].title = "TIC (6 bit,PS=4K)"; ! 643: } else { ! 644: table[2].bitlen = 5; ! 645: table[2].bitpos = 13; ! 646: table[2].title = "TIC (5 bit,PS=8K)"; ! 647: } ! 648: ! 649: for (auto& t : table) { ! 650: t.count = 1U << t.bitlen; ! 651: } ! 652: max_rows = table[0].count; ! 653: ! 654: table[0].head = "LAddress At TableAddr"; ! 655: table[1].head = "LAddress At TableAddr"; ! 656: table[2].head = "LAddress At PageAddr"; ! 657: ! 658: // 各テーブルのアドレスマスク。 ! 659: table[0].mask = ~0x1ff; ! 660: if (ps4k) { ! 661: table[1].mask = ~0x00ff; ! 662: table[2].mask = ~0x0fff; ! 663: } else { ! 664: table[1].mask = ~0x007f; ! 665: table[2].mask = ~0x1fff; ! 666: } ! 667: ! 668: Fit(); ! 669: } ! 670: ! 671: ! 672: // 画面を更新して再描画する。 ! 673: // ! 674: // 68040 のツリーは 3段階固定で 7:7:6 (4K/page) か 7:7:5 (8K/page)。 ! 675: // ! 676: // 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 ! 677: // +-------+-------+-------+-------+-------+-------+-------+-------+ ! 678: // |A A A A A A A|B B B B B B B|C C C C C:C| | ! 679: // +-------+-------+-------+-------+-------+-------+-------+-------+ ! 680: void ! 681: WXPageTable68040Window::DoRefresh() ! 682: { ! 683: // MMU 構成に変更があれば再構築。 ! 684: uint32 new_tc_value = mpu->GetTC(); ! 685: if (tc_value != new_tc_value) { ! 686: Reconfig(new_tc_value); ! 687: } ! 688: ! 689: table[1].base = 0xffffffff; ! 690: table[2].base = 0xffffffff; ! 691: if (mpu->mmu_tc->e == false) { ! 692: table[0].base = 0xffffffff; ! 693: } else { ! 694: if (show_urp) { ! 695: table[0].base = mpu->GetURP(); ! 696: } else { ! 697: table[0].base = mpu->GetSRP(); ! 698: } ! 699: uint64 data2 = mainbus->Peek4(table[0].GetAddr()); ! 700: if ((int64)data2 >= 0 && (data2 & 0x02)) { ! 701: table[1].base = data2 & table[0].mask; ! 702: } ! 703: if (table[1].base != 0xffffffff) { ! 704: uint64 data3 = mainbus->Peek4(table[1].GetAddr()); ! 705: if ((int64)data3 >= 0 && (data3 & 0x02)) { ! 706: table[2].base = data3 & table[1].mask; ! 707: } ! 708: } ! 709: } ! 710: ! 711: for (auto& t : table) { ! 712: // 論理アドレスの上位部分 (の表示用に下のほうを切り落としたやつ)。 ! 713: uint32 laddr; ! 714: uint32 valid; ! 715: switch (t.lv) { ! 716: case 0: ! 717: laddr = 0; ! 718: valid = 0x0002; ! 719: break; ! 720: case 1: ! 721: laddr = (table[0].cursor << 9); ! 722: valid = 0x0002; ! 723: break; ! 724: case 2: ! 725: laddr = (table[0].cursor << 13) | (table[1].cursor << 6); ! 726: valid = 0x0001; ! 727: break; ! 728: default: ! 729: __unreachable(); ! 730: } ! 731: ! 732: auto& screen = t.screen->GetScreen(); ! 733: screen.Clear(); ! 734: ! 735: TA attr_t = (tc_status == TC_DISABLE) ? TA::Disable : TA::Normal; ! 736: screen.Puts(0, 0, attr_t, (const char *)t.title.mb_str()); ! 737: screen.Puts(1, 1, attr_t, (const char *)t.head.mb_str()); ! 738: ! 739: const int end = std::min(screen.GetRow(), t.count + HEAD_ROW); ! 740: for (uint y = HEAD_ROW, i = t.ViewTop(); y < end; y++, i++) { ! 741: uint32 addr; ! 742: uint32 data; ! 743: if (__predict_false(t.base == 0xffffffff)) { ! 744: addr = t.base; ! 745: data = 0; ! 746: } else { ! 747: addr = t.GetAddr(i); ! 748: data = mainbus->Peek4(addr); ! 749: } ! 750: TA attr_i; ! 751: TA attr_a; ! 752: TA attr_v; ! 753: if (__predict_true(tc_status == TC_ENABLE)) { ! 754: attr_i = TA::Normal; ! 755: attr_a = TA::Normal; ! 756: attr_v = TA::Normal; ! 757: } else { ! 758: attr_i = TA::Disable; ! 759: attr_a = TA::Disable; ! 760: attr_v = TA::Disable; ! 761: } ! 762: if (__predict_false(i == t.cursor)) { ! 763: attr_i = TA::Reverse; ! 764: attr_a = TA::Reverse; ! 765: attr_v = TA::Reverse; ! 766: } ! 767: if (__predict_false((int64)data < 0)) { ! 768: attr_a = TA::Disable; ! 769: attr_v = TA::Disable; ! 770: } else if ((data & valid) == 0) { ! 771: attr_v = TA::Disable; ! 772: } ! 773: ! 774: // 表示は段ごとに微妙に違う。 ! 775: char lbuf[16]; ! 776: switch (t.lv) { ! 777: case 0: ! 778: snprintf(lbuf, sizeof(lbuf), "[%02x'000000] ", (i << 1)); ! 779: break; ! 780: case 1: ! 781: snprintf(lbuf, sizeof(lbuf), "[%04x'0000] ", laddr | (i << 2)); ! 782: break; ! 783: case 2: ! 784: snprintf(lbuf, sizeof(lbuf), "[%05x'000] ", ! 785: laddr | (__predict_true(ps4k) ? i : (i << 1))); ! 786: break; ! 787: default: ! 788: __unreachable(); ! 789: } ! 790: screen.Puts( 0, y, attr_i, lbuf); ! 791: screen.Print(12, y, attr_a, "$%08x ", addr); ! 792: screen.Print(22, y, attr_v, "%08x ", (uint32)data & t.mask); ! 793: int x = 31; ! 794: if (t.lv == 2) { ! 795: screen.Putc(x++, y, attr_v, (data & 0x400) ? 'G' : '-'); ! 796: screen.Putc(x++, y, attr_v, (data & 0x080) ? 'S' : '-'); ! 797: screen.Putc(x++, y, attr_v, (data & 0x010) ? 'M' : '-'); ! 798: } ! 799: screen.Putc(x++, y, attr_v, (data & 0x08) ? 'U' : '-'); ! 800: screen.Putc(x++, y, attr_v, (data & 0x04) ? 'W' : '-'); ! 801: } ! 802: } ! 803: ! 804: Refresh(); ! 805: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.