Annotation of nono/wx/wxpagetablemonitor.cpp, revision 1.1.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.