Annotation of nono/wx/wxpagetablemonitor.cpp, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.