|
|
1.1 root 1: //
2: // nono
1.1.1.4 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.11 root 7: //
8: // メモリダンプウィンドウ
9: //
10:
1.1 root 11: #include "wxdumpmonitor.h"
1.1.1.13 root 12: #include "mainapp.h"
13: #include "mainbus.h"
1.1.1.15! root 14: #include "monitor.h"
! 15: #include "mpu680x0.h"
1.1 root 16:
17: enum {
1.1.1.11 root 18: ID_TEXT = IDGROUP_MEMDUMP,
1.1.1.13 root 19: ID_PREVLINE,
20: ID_PREVPAGE,
21: ID_NEXTLINE,
22: ID_NEXTPAGE,
23: ID_FORMAT,
24:
25: ID_EDIT,
1.1.1.11 root 26:
27: ID_local_end, // 最後に置く (チェック用)
1.1 root 28: };
1.1.1.12 root 29: static_assert(ID_local_end - 1 <= (int)IDGROUP_MEMDUMP_END, "ID exceeded");
1.1 root 30:
31: // イベントテーブル
32: wxBEGIN_EVENT_TABLE(WXMemdumpWindow, inherited)
33: EVT_TEXT_ENTER(ID_TEXT, WXMemdumpWindow::OnTextEnter)
1.1.1.13 root 34: EVT_COMMAND(ID_PREVLINE, NONO_EVT_BUTTON, WXMemdumpWindow::OnPrevLine)
35: EVT_COMMAND(ID_PREVPAGE, NONO_EVT_BUTTON, WXMemdumpWindow::OnPrevPage)
36: EVT_COMMAND(ID_NEXTLINE, NONO_EVT_BUTTON, WXMemdumpWindow::OnNextLine)
37: EVT_COMMAND(ID_NEXTPAGE, NONO_EVT_BUTTON, WXMemdumpWindow::OnNextPage)
38: EVT_CHOICE(ID_FORMAT, WXMemdumpWindow::OnFormat)
1.1 root 39: wxEND_EVENT_TABLE()
40:
41: // コンストラクタ
1.1.1.9 root 42: // (タイトルは UpdateAddr() でセットする)
1.1.1.13 root 43: WXMemdumpWindow::WXMemdumpWindow(wxWindow *parent, int monid_)
1.1.1.12 root 44: : inherited(parent, wxID_ANY, wxEmptyString,
45: DEFAULT_STYLE | wxRESIZE_BORDER)
1.1 root 46: {
1.1.1.13 root 47: monid = monid_;
48: if (IS_MONITOR_XPMEMDUMP(monid)) {
49: myidx = monid - ID_MONITOR_XPMEMDUMP0;
50: } else {
51: myidx = monid - ID_MONITOR_MEMDUMP0;
52: }
53:
54: // ↓ topsizer
55: // +--------------------------------------------+
56: // |上枠 → |
57: // |+-----+------+-----+----------+-----+------+|
58: // ||余白 | "<<" | "<" | アドレス | ">" | ">>" ||
59: // |+-----+------+-----+----------+-----+------+|
60: // +--------------------------------------------+
61: // | TextScreen |
62: // +--------------------------------------------+
1.1.1.11 root 63:
64: auto *topsizer = new wxBoxSizer(wxVERTICAL);
1.1.1.5 root 65:
1.1.1.9 root 66: // 上枠用の下敷きパネル
1.1.1.13 root 67: auto *ctrlpanel = new wxPanel(this);
1.1.1.15! root 68: ctrlpanel->SetName("WXMemdumpWindow.CtrlPanel");
1.1.1.11 root 69: topsizer->Add(ctrlpanel, 0, wxEXPAND);
1.1.1.9 root 70:
1.1.1.5 root 71: // 上枠用の横 sizer
72: ctrlbox = new wxBoxSizer(wxHORIZONTAL);
1.1 root 73:
74: // アドレスコントロール
1.1.1.13 root 75: addrctrl = new wxTextCtrl(ctrlpanel, ID_TEXT,
1.1 root 76: wxEmptyString, wxDefaultPosition, wxDefaultSize,
77: wxTE_PROCESS_ENTER);
1.1.1.13 root 78: buttons[0] = new WXButton(ctrlpanel, ID_PREVPAGE, wxDefaultSize, "<<");
79: buttons[1] = new WXButton(ctrlpanel, ID_PREVLINE, wxDefaultSize, "<");
80: buttons[2] = new WXButton(ctrlpanel, ID_NEXTLINE, wxDefaultSize, ">");
81: buttons[3] = new WXButton(ctrlpanel, ID_NEXTPAGE, wxDefaultSize, ">>");
82:
83: ctrlbox->AddSpacer(3);
84: ctrlbox->Add(buttons[0], 0, wxALIGN_CENTER);
85: ctrlbox->Add(buttons[1], 0, wxALIGN_CENTER);
86: ctrlbox->AddSpacer(3);
87: ctrlbox->Add(addrctrl, 0, wxALIGN_CENTER);
88: ctrlbox->AddSpacer(3);
89: ctrlbox->Add(buttons[2], 0, wxALIGN_CENTER);
90: ctrlbox->Add(buttons[3], 0, wxALIGN_CENTER);
91: ctrlbox->AddSpacer(3);
92:
93: // 表示形式 (機種によって選択肢と名前が異なる)
94: if (gMainApp.Has(VMCap::M68K)) {
1.1.1.15! root 95: auto mpu680x0 = GetMPU680x0Device(GetMPUDevice());
1.1.1.13 root 96: fmts.emplace_back(Memdump::Byte, _("Byte"));
97: fmts.emplace_back(Memdump::Word, _("Word"));
98: fmts.emplace_back(Memdump::Long, _("Long Word"));
1.1.1.15! root 99: switch (mpu680x0->GetMPUType()) {
! 100: case m680x0MPUType::M68030:
! 101: fmts.emplace_back(Memdump::M68030PageShort,
! 102: _("MMU Descriptor (Short Format)"));
! 103: break;
! 104: case m680x0MPUType::M68040:
! 105: fmts.emplace_back(Memdump::M68040TableDesc,
! 106: _("MMU Table Descriptor"));
! 107: fmts.emplace_back(Memdump::M68040PageDesc,
! 108: _("MMU Page Descriptor"));
! 109: break;
! 110: default:
! 111: break;
! 112: }
! 113: fmts.emplace_back(Memdump::M680x0Disasm, _("680x0 Disassemble"));
1.1.1.13 root 114: } else {
115: fmts.emplace_back(Memdump::Byte, _("Byte"));
116: fmts.emplace_back(Memdump::Word, _("Half Word"));
117: fmts.emplace_back(Memdump::Long, _("Word"));
118: fmts.emplace_back(Memdump::M88200Page, _("88200 Descriptor"));
119: fmts.emplace_back(Memdump::M88100Disasm, _("88100 Disassemble"));
120: }
121: if (gMainApp.Has(VMCap::LUNA)) {
122: fmts.emplace_back(Memdump::HD64180Disasm, _("HD64180 Disassemble"));
123: }
124:
125: // fmts から名前だけの配列を作る
126: std::vector<wxString> fmt_choice;
127: for (auto p : fmts) {
128: fmt_choice.push_back(p.second);
129: }
130: fmtctrl = new wxChoice(ctrlpanel, ID_FORMAT,
131: wxDefaultPosition, wxDefaultSize,
132: fmt_choice.size(), &fmt_choice[0]);
133: ctrlbox->Add(fmtctrl, 0, wxALIGN_CENTER);
1.1 root 134:
1.1.1.9 root 135: // 上枠の sizer と下敷きを紐付ける
136: ctrlpanel->SetSizer(ctrlbox);
137: ctrlbox->SetSizeHints(ctrlpanel);
138:
1.1.1.13 root 139: screen = new WXMonitorPanel(this, gMonitorManager->Get(monid));
1.1.1.11 root 140: topsizer->Add(screen, 1, wxEXPAND);
1.1 root 141:
1.1.1.4 root 142: SetSizer(topsizer);
1.1 root 143:
1.1.1.11 root 144: // ウィンドウサイズを確定させる
145: fixed_height = ctrlbox->GetSize().y;
1.1.1.13 root 146: FontChanged();
1.1.1.11 root 147: DoSize();
148:
1.1.1.13 root 149: // パネルに来るマウスイベントをこっちに回す
150: screen->Connect(wxEVT_MOUSEWHEEL,
151: wxMouseEventHandler(WXMemdumpWindow::OnMouseWheel), NULL, this);
152: screen->Connect(wxEVT_LEFT_DCLICK,
153: wxMouseEventHandler(WXMemdumpWindow::OnDClick), NULL, this);
154:
155: // メモリダンプオブジェクトを取得
156: auto mon = screen->GetMonitor();
1.1.1.15! root 157: memdump = dynamic_cast<MemdumpMonitor *>(mon->obj);
1.1.1.13 root 158: assert(memdump);
159:
160: // 初期値をコントロールに設定
161: auto fmt = memdump->GetFormat();
162: fmtctrl->SetSelection(Format2Selection(fmt));
163: DoFormat(fmt);
1.1.1.9 root 164: UpdateAddr();
1.1 root 165: }
166:
167: // デストラクタ
168: WXMemdumpWindow::~WXMemdumpWindow()
169: {
170: }
171:
1.1.1.12 root 172: bool
173: WXMemdumpWindow::Layout()
174: {
175: // 縦リサイズ可能レイアウト
176: return LayoutTextVResize(screen, fixed_height);
177: }
178:
1.1.1.13 root 179: void
180: WXMemdumpWindow::FontChanged()
181: {
182: inherited::FontChanged();
183:
184: // 最小 24x24 にしてみる
185: wxSize sz(screen->GetFontWidth() * 2 + 4,
186: screen->GetFontHeight() + 4);
187: if (sz.x < 24)
188: sz.x = 24;
189: if (sz.y < 24)
190: sz.y = 24;
191: for (auto *btn : buttons) {
192: btn->SetClientSize(sz);
193: btn->SetMinClientSize(sz);
194: btn->FontChanged();
195: }
196: }
197:
1.1 root 198: // テキスト入力イベント
199: void
200: WXMemdumpWindow::OnTextEnter(wxCommandEvent& event)
201: {
202: // 入力文字列(16進文字列)を数値に変換
1.1.1.5 root 203: const wxString& wstr = event.GetString();
1.1.1.6 root 204: uint32 val = strtoul((const char *)wstr.mb_str(), NULL, 16);
1.1 root 205:
1.1.1.9 root 206: // アドレスを更新
1.1.1.13 root 207: memdump->SetAddr(val);
1.1.1.9 root 208: UpdateAddr();
1.1 root 209: }
210:
1.1.1.13 root 211: // "<"(前行) ボタン押下イベント
1.1 root 212: void
1.1.1.13 root 213: WXMemdumpWindow::OnPrevLine(wxCommandEvent& event)
1.1 root 214: {
1.1.1.13 root 215: // 1行戻る
216: memdump->Offset(memdump->GetLineOffset(-1));
1.1.1.9 root 217:
1.1.1.13 root 218: UpdateAddr();
219: }
220:
221: // "<<"(前ページ) ボタン押下イベント
222: void
223: WXMemdumpWindow::OnPrevPage(wxCommandEvent& event)
224: {
225: // 1ページ戻る
226: memdump->Offset(memdump->GetPageOffset(-1));
1.1.1.9 root 227:
228: UpdateAddr();
1.1 root 229: }
230:
1.1.1.13 root 231: // ">"(次行) ボタン押下イベント
1.1 root 232: void
1.1.1.13 root 233: WXMemdumpWindow::OnNextLine(wxCommandEvent& event)
1.1 root 234: {
1.1.1.13 root 235: // 1行進む
236: memdump->Offset(memdump->GetLineOffset(1));
237:
238: UpdateAddr();
239: }
1.1.1.9 root 240:
1.1.1.13 root 241: // ">>"(次ページ) ボタン押下イベント
242: void
243: WXMemdumpWindow::OnNextPage(wxCommandEvent& event)
244: {
245: // 1ページ進む
246: memdump->Offset(memdump->GetPageOffset(1));
1.1.1.9 root 247:
248: UpdateAddr();
1.1 root 249: }
250:
1.1.1.9 root 251: // アドレス欄の表示を更新する
252: void
253: WXMemdumpWindow::UpdateAddr()
254: {
1.1.1.13 root 255: int width;
256: std::string title;
257: if (IS_MONITOR_XPMEMDUMP(monid)) {
258: width = 5;
259: title = _("XP Memory Dump");
260: } else {
261: width = 8;
262: title = _("Main Memory Dump");
263: }
1.1.1.9 root 264:
1.1.1.14 root 265: uint32 addr = memdump->GetAddr().Addr();
1.1.1.13 root 266: std::string addrstr = strhex(addr, width);
1.1.1.9 root 267:
268: // EVT_TEXT を起こさず変更する
1.1.1.13 root 269: addrctrl->ChangeValue(addrstr);
1.1.1.9 root 270:
271: // カーソルを末尾に
272: addrctrl->SetInsertionPointEnd();
273:
274: // タイトルを変更
1.1.1.13 root 275: title += string_format(" %d: $", myidx);
276: title += addrstr;
277: SetTitle(title);
278:
279: // 即更新
280: Refresh();
1.1.1.9 root 281: }
282:
1.1.1.13 root 283: // 表示フォーマット変更イベント
284: void
285: WXMemdumpWindow::OnFormat(wxCommandEvent& event)
1.1.1.9 root 286: {
1.1.1.13 root 287: int idx = event.GetSelection();
288: DoFormat(Selection2Format(idx));
1.1 root 289: }
1.1.1.9 root 290:
1.1.1.13 root 291: // 表示フォーマット変更処理
1.1.1.9 root 292: void
1.1.1.13 root 293: WXMemdumpWindow::DoFormat(Memdump::Format fmt)
1.1.1.9 root 294: {
1.1.1.13 root 295: memdump->SetFormat(fmt);
296:
297: // SetFormat() によってアドレスが切り捨てられる場合があるので
298: // アドレス欄の表示ごと更新。
299: UpdateAddr();
300: }
301:
302: // マウスホイールイベント
303: void
304: WXMemdumpWindow::OnMouseWheel(wxMouseEvent& event)
305: {
306: int delta = event.GetWheelRotation();
307:
308: // 1回の変化で +/-120 が来る。
309: // たいていのアプリケーションで3行ずつの移動に換算することが多いようだが
310: // ここはメモリダンプなので 4行ずつにする。
311:
312: if (delta != 0) {
313: memdump->Offset(memdump->GetLineOffset(-delta / 30));
314: UpdateAddr();
315: }
316: }
317:
318: // ダブルクリックイベント
319: void
320: WXMemdumpWindow::OnDClick(wxMouseEvent& event)
321: {
322: event.Skip();
323:
324: auto fmt = memdump->GetFormat();
325:
326: // テキストの桁数、行数にする
327: wxPoint tpos = screen->GetTextPosition(event.GetPosition());
328: int x = tpos.x;
329: int y = tpos.y;
330:
331: // ウィンドウサイズを変えた時に出来る下の空き地にはヒットさせない
332: if (y >= screen->GetRow()) {
333: return;
334: }
335:
336: // アドレス部分は常に除外でいいか
337: if (x < 19) {
338: return;
339: }
340:
341: // 現在のフォーマットでのクリック位置のアドレスを求める
342: int len = 0;
343: uint64 addr = -1;
344: switch (fmt) {
345: case Memdump::Byte:
346: len = 1;
347: addr = GetAddrAtHexdump(x, y, len);
348: break;
349: case Memdump::Word:
350: len = 2;
351: addr = GetAddrAtHexdump(x, y, len);
352: break;
353: case Memdump::Long:
354: len = 4;
355: addr = GetAddrAtHexdump(x, y, len);
356: break;
357: case Memdump::M68030PageShort:
358: case Memdump::M88200Page:
359: len = 4;
360: addr = GetAddrAtPageShort(x, y);
361: break;
362:
363: case Memdump::M68030PageLong:
364: PANIC("not supported");
365: break;
366:
1.1.1.15! root 367: case Memdump::M680x0Disasm:
1.1.1.13 root 368: len = 2;
369: addr = GetAddrAtDisasm(x, y, len);
370: break;
371:
372: case Memdump::M88100Disasm:
373: len = 4;
374: addr = GetAddrAtDisasm(x, y, len);
375: break;
376:
377: case Memdump::HD64180Disasm:
378: len = 1;
379: addr = GetAddrAtDisasm(x, y, len);
380: break;
381:
382: default:
383: break;
384: }
385: if ((int64)addr < 0) {
386: return;
387: }
388: addr &= ~(len - 1);
389:
390: // このアドレスが編集可能 (≒メモリ) か?
391: if (memdump->CanPoke(addr) == false) {
392: ::wxMessageBox(_("Can not edit here"), _("Memory Edit"),
393: wxICON_EXCLAMATION | wxOK | wxOK_DEFAULT, this);
394: return;
395: }
396:
397: // 出来ればここをハイライトとかしたい
398:
399: // 現在値を(再)取得。
400: uint32 val = memdump->Peek(addr, len);
401:
402: // sizestr は表示形式ではなく単なるサイズ。(DescShort なら Long)
403: std::string sizestr;
404: switch (len) {
405: case 1:
406: sizestr = Format2String(Memdump::Byte);
407: break;
408: case 2:
409: sizestr = Format2String(Memdump::Word);
410: break;
411: case 4:
412: sizestr = Format2String(Memdump::Long);
413: break;
414: default:
415: PANIC("corrupted len=%d", len);
416: }
417:
418: // 編集
419: auto dlg = new MemEditDialog(this, addr, val, len, sizestr);
420: if (dlg->ShowModal() == wxID_OK) {
421: uint32 data = dlg->GetData();
422:
423: // 更新
1.1.1.14 root 424: if (memdump->Poke(addr, data, len) == false) {
1.1.1.13 root 425: ::wxMessageBox(_("Could not edit"), _("Memory Edit"),
426: wxICON_EXCLAMATION | wxOK | wxOK_DEFAULT, this);
427: }
428: }
429: }
430:
431: // 16進ダンプ画面のテキスト座標 (x, y) に対応するアドレスを返す。
432: // 対応するアドレスがない場合は (uint64)-1 を返す。
433: uint64
434: WXMemdumpWindow::GetAddrAtHexdump(int x, int y, int len)
435: {
436: if (x < 68) {
437: // 16進ダンプ部分
438:
439: // 空白部分なら除外
440: x -= 19;
441: if (x % (len * 2 + 1) == len * 2) {
442: return (uint64)-1;
443: }
444: x = (x / (len * 2 + 1)) * len;
445: } else {
446: // 文字ダンプ部分
447: x -= 68;
448: }
449:
450: if (x > 15) {
451: return (uint64)-1;
452: }
453:
1.1.1.14 root 454: return memdump->GetAddr().Addr() + (y * memdump->GetStride()) + x;
1.1.1.9 root 455: }
456:
1.1.1.13 root 457: // 32bit ページテーブル画面のテキスト座標 (x, y) に対応するアドレスを返す。
458: // 対応するアドレスがない場合は (uint64)-1 を返す。
459: uint64
460: WXMemdumpWindow::GetAddrAtPageShort(int x, int y)
461: {
462: // 32bit ページテーブルなら1行で1ロングワード。
463: // 16進の場合との親和性のため、ダンプ値のところだけ反応。
464: if (x >= 19 + 8) {
465: return (uint64)-1;
466: }
1.1.1.14 root 467: return memdump->GetAddr().Addr() + y * 4;
1.1.1.13 root 468: }
469:
470: // 逆アセンブル画面のテキスト座標 (x, y) に対応するアドレスを返す。
471: // minlen は命令の最小バイト数。
472: // 対応するアドレスがない場合は (uint64)-1 を返す。
473: uint64
474: WXMemdumpWindow::GetAddrAtDisasm(int x, int y, int minlen)
475: {
476: // 先頭から y 行目のアドレス
477: uint32 yaddr = memdump->GetLineOffset(y);
478:
479: // y 行目の命令のバイト数
480: uint32 y1addr = memdump->GetLineOffset(y + 1);
481: uint32 bytes = y1addr - yaddr;
482:
483: // 空白部分なら除外
484: x -= 19;
485:
486: if (x % (minlen * 2 + 1) == minlen * 2) {
487: return (uint64)-1;
488: }
489: x = (x / (minlen * 2 + 1)) * minlen;
490:
491: if (x >= bytes) {
492: return (uint64)-1;
493: }
494:
1.1.1.14 root 495: return memdump->GetAddr().Addr() + yaddr + x;
1.1.1.13 root 496: }
497:
498: // セレクション番号からフォーマット番号への変換
499: Memdump::Format
500: WXMemdumpWindow::Selection2Format(int idx)
501: {
502: assert(idx < fmts.size());
503: return fmts[idx].first;
504: }
505:
506: // フォーマット番号からセレクション番号への変換
507: int
508: WXMemdumpWindow::Format2Selection(Memdump::Format fmt_)
509: {
510: for (int idx = 0, end = fmts.size(); idx < end; idx++) {
511: auto p = fmts[idx];
512: if (fmt_ == p.first) {
513: return idx;
514: }
515: }
516: // ?
517: return 0;
518: }
519:
520: // フォーマット番号から文字列への変換
521: wxString
522: WXMemdumpWindow::Format2String(Memdump::Format fmt_)
523: {
524: for (int idx = 0, end = fmts.size(); idx < end; idx++) {
525: auto p = fmts[idx];
526: if (fmt_ == p.first) {
527: return p.second;
528: }
529: }
530: // ?
531: return wxEmptyString;
532: }
533:
534:
535: //
536: // 編集ダイアログ
537: //
538:
539: wxBEGIN_EVENT_TABLE(MemEditDialog, inherited)
540: EVT_TEXT_ENTER(ID_EDIT, MemEditDialog::OnTextEnter)
541: wxEND_EVENT_TABLE()
542:
543: // コンストラクタ
544: MemEditDialog::MemEditDialog(wxWindow *parent, uint32 addr, uint32 oldval,
545: int len, const std::string& sizestr)
546: : inherited(parent, wxID_ANY, _("Edit memory"))
547: {
548: auto topsizer = new wxBoxSizer(wxVERTICAL);
549:
550: auto gridsizer = new wxFlexGridSizer(2);
551: topsizer->Add(gridsizer, 0, wxEXPAND | wxALL, 3);
552:
553: gridsizer->Add(new wxStaticText(this, wxID_ANY, _("Address:")),
554: 0, wxEXPAND);
555:
556: std::string addrstr = "$";
557: addrstr += strhex(addr);
558: auto addrctrl = new wxStaticText(this, wxID_ANY, addrstr,
559: wxDefaultPosition, wxDefaultSize, wxBORDER_SUNKEN);
560: gridsizer->Add(addrctrl, 0, wxEXPAND);
561:
562: gridsizer->Add(new wxStaticText(this, wxID_ANY, _("Size:")),
563: 0, wxEXPAND);
564: gridsizer->Add(new wxStaticText(this, wxID_ANY, sizestr),
565: 0, wxEXPAND);
566:
567: gridsizer->Add(new wxStaticText(this, wxID_ANY, _("Data:")),
568: 0, wxEXPAND);
569:
570: std::string oldstr = strhex(oldval, len * 2);
571: datactrl = new wxTextCtrl(this, ID_EDIT, oldstr,
572: wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
573: gridsizer->Add(datactrl, 0, wxEXPAND);
574:
575: topsizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL | wxNO_DEFAULT),
576: 0, wxEXPAND | wxALL, 3);
577:
578: SetSizer(topsizer);
579: wxSize sz = topsizer->Fit(this);
580: SetClientSize(sz);
581: SetMinClientSize(sz);
582: }
583:
584: // デストラクタ
585: MemEditDialog::~MemEditDialog()
586: {
587: }
588:
589: // テキスト入力
590: void
591: MemEditDialog::OnTextEnter(wxCommandEvent& event)
592: {
593: EndModal(wxID_OK);
594: }
595:
596: // テキストコントロールの値を返す。
597: // 変換できなければ (uint64)-1 を返す。
598: uint64
599: MemEditDialog::GetData() const
600: {
601: unsigned long int ul;
602: char *end;
603:
604: // wxString だと地味にめんどい
605: wxString wtext = datactrl->GetValue();
606: std::string text((const char *)wtext.mb_str());
607:
608: errno = 0;
609: ul = strtoul(&text[0], &end, 16);
610: if (end == &text[0] || *end != '\0' || errno != 0) {
611: return (uint64)-1;
612: }
613: return (uint32)ul;
614: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.