|
|
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.