--- nono/wx/wxmainframe.cpp 2026/04/29 17:05:23 1.1.1.17 +++ nono/wx/wxmainframe.cpp 2026/04/29 17:05:58 1.1.1.25 @@ -10,36 +10,45 @@ #include "wxmainframe.h" #include "fontmanager.h" +#include "wxaccstatmonitor.h" #include "wxdipswwindow.h" #include "wxdumpmonitor.h" +#include "wxgvrammonitor.h" #include "wxlcdwindow.h" #include "wxlogmonitor.h" #include "wxlogsetting.h" #include "wxmainview.h" #include "wxmonitor.h" #include "wxmpumonitor.h" +#include "wxpagetablemonitor.h" #include "wxpalettemonitor.h" -#include "wxplanemonitor.h" #include "wxromwindow.h" #include "wxsoftkey.h" #include "wxstatuspanel.h" +#include "wxthreadmonitor.h" +#include "wxtvrammonitor.h" #include "wxuimessage.h" #include "wxversion.h" #include "config.h" #include "fdc.h" #include "fdd.h" +#include "hostcom.h" +#include "hostnet.h" +#include "hostsound.h" #include "mainapp.h" #include "mpu.h" +#include "netdriver_slirp.h" #include "nmi.h" #include "power.h" -#include "spc.h" +#include "scsidev.h" +#include "scsidomain.h" #include "syncer.h" #include -// ID は 0 から (wxID_LOWEST = 5000 未満まで) 使えるっぽい。 +// ID は 1 から (wxID_LOWEST = 5000 未満まで) 使えるっぽい +// (wxGTK は 0 から使用可能だが wxOSX は 0 が不可)。 // メニュー ID のうちウィンドウのオープン状態を維持する必要があるものは -// (ID が 0 から使えるのなら) 0 から割り当てて配列で管理してしまうのが -// 手っ取り早い。 +// 0 (付近) から割り当てて 0 から始まる配列で管理してしまうのが手っ取り早い。 // ウィンドウに割り当てるウィンドウ ID とメニューイベントで飛んでくる // メニュー ID は互いに干渉しないはずなので、同じ値を使うことでメニューと // ウィンドウの紐付けをする。 @@ -80,6 +89,51 @@ enum { ID_INPUT_JP, ID_INPUT_END, + ID_HOSTNET0_START, + ID_HOSTNET0_USERMODE, + ID_HOSTNET0_TAP, + ID_HOSTNET0_BPF, + ID_HOSTNET0_AFPACKET, + ID_HOSTNET0_NONE, // 最後に置くこと + + ID_HOSTNET1_START, + ID_HOSTNET1_USERMODE, + ID_HOSTNET1_TAP, + ID_HOSTNET1_BPF, + ID_HOSTNET1_AFPACKET, + ID_HOSTNET1_NONE, // 最後に置くこと + + ID_HOSTCOM0_START, + ID_HOSTCOM0_TCP, + ID_HOSTCOM0_STDIO, + ID_HOSTCOM0_CONSOLE, + ID_HOSTCOM0_NONE, // 最後に置くこと + + ID_HOSTCOM1_START, + ID_HOSTCOM1_TCP, + ID_HOSTCOM1_STDIO, + ID_HOSTCOM1_CONSOLE, + ID_HOSTCOM1_NONE, // 最後に置くこと + + ID_HOSTCOM2_START, + ID_HOSTCOM2_TCP, + ID_HOSTCOM2_STDIO, + ID_HOSTCOM2_CONSOLE, + ID_HOSTCOM2_NONE, // 最後に置くこと + + ID_HOSTCOM_DBG_START, + ID_HOSTCOM_DBG_TCP, + ID_HOSTCOM_DBG_STDIO, + ID_HOSTCOM_DBG_CONSOLE, // 存在しないけど HOSTCOMn と揃える必要がある。 + ID_HOSTCOM_DBG_NONE, // 最後に置くこと。 + + ID_HOSTSOUND_START, + ID_HOSTSOUND_NETBSD, + ID_HOSTSOUND_SNDIO, + ID_HOSTSOUND_ALSA, + ID_HOSTSOUND_WAV, + ID_HOSTSOUND_NONE, // 最後に置くこと + ID_SCALE_START, ID_SCALE_END = ID_SCALE_START + 6, @@ -89,6 +143,8 @@ enum { ID_FONTSIZE_24, ID_FONTSIZE_END, + ID_DEVICE_EMPTY, + ID_MONRATE_START, ID_MONRATE_END = ID_MONRATE_START + 4, @@ -170,6 +226,20 @@ wxBEGIN_EVENT_TABLE(WXMainFrame, inherit WXMainFrame::OnMenuInput) EVT_UPDATE_UI_RANGE(ID_INPUT_START + 1, ID_INPUT_END -1, WXMainFrame::OnMenuInputUI) + + EVT_MENU_RANGE(ID_HOSTNET0_START + 1, ID_HOSTNET1_NONE, + WXMainFrame::OnMenuHostNet) + EVT_UPDATE_UI_RANGE(ID_HOSTNET0_START + 1, ID_HOSTNET1_NONE, + WXMainFrame::OnMenuHostNetUI) + EVT_MENU_RANGE(ID_HOSTCOM0_START + 1, ID_HOSTCOM2_NONE, + WXMainFrame::OnMenuHostCom) + EVT_UPDATE_UI_RANGE(ID_HOSTCOM0_START + 1, ID_HOSTCOM2_NONE, + WXMainFrame::OnMenuHostComUI) + EVT_MENU_RANGE(ID_HOSTSOUND_START + 1, ID_HOSTSOUND_NONE, + WXMainFrame::OnMenuHostSound) + EVT_UPDATE_UI_RANGE(ID_HOSTSOUND_START + 1, ID_HOSTSOUND_NONE, + WXMainFrame::OnMenuHostSoundUI) + EVT_MENU_RANGE(ID_SCALE_START, ID_SCALE_END, WXMainFrame::OnMenuScale) EVT_UPDATE_UI_RANGE(ID_SCALE_START, ID_SCALE_END, @@ -214,6 +284,12 @@ wxBEGIN_EVENT_TABLE(WXMainFrame, inherit EVT_UPDATE_UI(ID_KEYBOARD_CONNECT, WXMainFrame::OnKeyboardConnectUI) EVT_MENU_RANGE(0, ID_SUBWIN_END, WXMainFrame::OnWindow) EVT_UPDATE_UI_RANGE(0, ID_SUBWIN_END, WXMainFrame::OnWindowUI) + + EVT_MENU_RANGE(ID_HOSTCOM_DBG_START + 1, ID_HOSTCOM_DBG_NONE, + WXMainFrame::OnMenuHostCom) + EVT_UPDATE_UI_RANGE(ID_HOSTCOM_DBG_START + 1, ID_HOSTCOM_DBG_NONE, + WXMainFrame::OnMenuHostComUI) + EVT_MENU(wxID_ABOUT, WXMainFrame::OnAbout) wxEND_EVENT_TABLE() @@ -222,11 +298,22 @@ WXMainFrame::WXMainFrame(wxWindow *paren wxDEFAULT_FRAME_STYLE & ~wxMAXIMIZE_BOX & ~wxRESIZE_BORDER) { // デバイスを取得 - mpu = GetMPUDevice(); power = GetPowerDevice(); syncer = GetSyncer(); // デバイスを取得。こっちはあるかどうかを調べる keyboard = gMainApp.FindObject(OBJ_KEYBOARD); + for (uint i = 0; i < hostnet.size(); i++) { + hostnet[i] = gMainApp.FindObject(OBJ_HOSTNET(i)); + } + for (uint i = 0; i < hostcom.size(); i++) { + hostcom[i] = gMainApp.FindObject(OBJ_HOSTCOM(i)); + } + hostcom_dbg = gMainApp.FindObject(OBJ_HOSTCOM_DBG); + hostsound = gMainApp.FindObject(OBJ_HOSTSOUND); + + // メイン MPU 名を取得。メニューとタイトルによく出てくるので。 + // "88xx0" とか "88200" は別処理。 + mpuname = GetMPUDevice()->GetMPUName(); // メニュー wxMenuBar *menubar = new wxMenuBar(); @@ -250,7 +337,7 @@ WXMainFrame::WXMainFrame(wxWindow *paren menuVM->Append(ID_NMI_BUTTON, _("Push &Interrupt button")); } menuVM->AppendSeparator(); - menuVM->Append(ID_RESTART_VM, _("&Restart VM (For developers)"), ""); + menuVM->Append(ID_RESTART_VM, _("Re&start VM (For developers)"), ""); menuVM->AppendSeparator(); menuVM->Append(ID_EXIT, _("E&xit")); menubar->Append(menuVM, _("&VM")); @@ -264,6 +351,13 @@ WXMainFrame::WXMainFrame(wxWindow *paren menuSetInput->AppendRadioItem(ID_INPUT_JP, _("&JP Keyboard")); menuSet->AppendSubMenu(menuSetInput, _("&Key Input")); } + for (uint i = 0; i < hostnet.size(); i++) { + CreateHostNetMenu(menuSet, i); + } + for (uint i = 0; i < hostcom.size(); i++) { + CreateHostComMenu(menuSet, i); + } + CreateHostSoundMenu(menuSet); menubar->Append(menuSet, _("&Setting")); // メニュー > 表示 @@ -291,7 +385,7 @@ WXMainFrame::WXMainFrame(wxWindow *paren menuFontSize->AppendRadioItem(ID_FONTSIZE_24, "2&4"); menuDisplay->AppendSubMenu(menuFontSize, _("&Font Size")); wxMenu *menuMonRate = new wxMenu(); - user_idx = CreateMonRateTable(); + CreateMonRateTable(); for (int i = 0, end = monrates.size(); i < end; i++) { std::string text; switch (monrates[i]) { @@ -327,6 +421,13 @@ WXMainFrame::WXMainFrame(wxWindow *paren menuOper->AppendCheckItem(ID_KEYBOARD_CONNECT, _("Connect &Keyboard")); menuDevice->AppendSubMenu(menuOper, _("&Operation")); } + // アイテムが何もなければ本当はメニューバーのアイテムを無効にしたいが、 + // それは出来ないっぽい。何かアイテムを置かないと変なパネルが出たりする。 + if (menuDevice->GetMenuItems().IsEmpty()) { + // TRANSLATORS: This is "Device > Nothing" in the menubar. + menuDevice->Append(ID_DEVICE_EMPTY, _("Nothing")); + menuDevice->Enable(ID_DEVICE_EMPTY, false); + } menubar->Append(menuDevice, _("&Device")); #define AppendIfSeparator(menu, vmcap_) do { \ @@ -340,38 +441,49 @@ WXMainFrame::WXMainFrame(wxWindow *paren AppendIf(menuMonitor, ID_MONITOR_SCHEDULER, _("&Scheduler")); wxMenu *menuMPU = new wxMenu(); - AppendIf(menuMPU, ID_MONITOR_MPUREG, _("&Register")); + AppendIf(menuMPU, ID_MONITOR_MPUREG, _("&Registers")); AppendIf(menuMPU, ID_MONITOR_MPUATC, "&ATC"); - AppendIf(menuMPU, ID_MONITOR_MPUCACHE, _("Cache")); - AppendIf(menuMPU, ID_MONITOR_INTERRUPT, _("&Interrupt")); + AppendIf(menuMPU, ID_SUBWIN_MPUPT, _("&Page Table")); + AppendIf(menuMPU, ID_MONITOR_MPUCACHE, _("&Caches")); + AppendIf(menuMPU, ID_MONITOR_INTERRUPT, _("&Interrupts")); AppendIfSeparator(menuMPU, VMCap::M88K); - AppendIf(menuMPU, ID_MONITOR_CMMU7, "CMMU#7" + _("(Inst)")); + AppendIf(menuMPU, ID_MONITOR_CMMU7, + "CMMU#7" + _("(Inst)") + " " + _("Registers")); AppendIf(menuMPU, ID_MONITOR_ATC7, "ATC#7"); AppendIf(menuMPU, ID_SUBWIN_CACHE7, _("Cache") + "#7"); AppendIfSeparator(menuMPU, VMCap::M88K); - AppendIf(menuMPU, ID_MONITOR_CMMU6, "CMMU#6" + _("(Data)")); + AppendIf(menuMPU, ID_MONITOR_CMMU6, + "CMMU#6" + _("(Data)") + " " + _("Registers")); AppendIf(menuMPU, ID_MONITOR_ATC6, "ATC#6"); AppendIf(menuMPU, ID_SUBWIN_CACHE6, _("Cache") + "#6"); menuMPU->AppendSeparator(); // MEMDUMPn のラベルは UpdateUI で書き直すのでここでは適当に // 埋めておく。(empty だと怒られる) - for (int i = 0; i < MAX_MEMDUMP_MONITOR; i++) { + for (uint i = 0; i < MAX_MEMDUMP_MONITOR; i++) { AppendIf(menuMPU, ID_MONITOR_MEMDUMP(i), "memdump"); } menuMPU->AppendSeparator(); AppendIf(menuMPU, ID_SUBWIN_BRHIST, _("Branch &History")); AppendIf(menuMPU, ID_SUBWIN_EXHIST, _("&Exception History")); AppendIf(menuMPU, ID_SUBWIN_VECTOR, _("&Vector Table")); - menuMonitor->AppendSubMenu(menuMPU, - (gMainApp.Has(VMCap::M68K) ? "&MPU(MC68030)" : "&MPU(MC88xx0)")); + wxString mpulabel; + if (gMainApp.Has(VMCap::M68K)) { + mpulabel = "&MPU(" + mpuname + ")"; + } else if (gMainApp.Has(VMCap::M88K)) { + mpulabel = "&MPU(MC88xx0)"; + } else { + mpulabel = "&MPU"; + } + menuMonitor->AppendSubMenu(menuMPU, mpulabel); if (gMainApp.Has(VMCap::LUNA)) { wxMenu *menuXP = new wxMenu(); - AppendIf(menuXP, ID_MONITOR_XPREG, _("&Register")); - AppendIf(menuXP, ID_MONITOR_XPINTR, _("&Interrupt")); + AppendIf(menuXP, ID_MONITOR_XPREG, _("&Registers")); + AppendIf(menuXP, ID_MONITOR_XPINTR, _("&Interrupts")); AppendIf(menuXP, ID_MONITOR_XPIO, _("Internal &Devices")); + AppendIf(menuXP, ID_MONITOR_XPASCI, "&ASCI"); menuXP->AppendSeparator(); - for (int i = 0; i < MAX_XPMEMDUMP_MONITOR; i++) { + for (uint i = 0; i < MAX_XPMEMDUMP_MONITOR; i++) { AppendIf(menuXP, ID_MONITOR_XPMEMDUMP(i), "memdump"); } menuXP->AppendSeparator(); @@ -406,64 +518,69 @@ WXMainFrame::WXMainFrame(wxWindow *paren AppendIf(menuDev, ID_MONITOR_KEYBOARD, _("Keyboard/Mouse")); AppendIf(menuDev, ID_MONITOR_LANCE, "Lance"); AppendIf(menuDev, ID_MONITOR_NEREID, "Nereid"); - for (int i = 0; i < 2; i++) { - int id = ID_MONITOR_RTL8019AS(i); - wxString name = string_format("Nereid(RTL8019AS) #%d", i); + for (uint i = 0; i < hostnet.size(); i++) { + uint id = ID_MONITOR_RTL8019AS(i); + wxString name = string_format("Nereid#%u (RTL8019AS)", i); AppendIf(menuDev, id, name); } AppendIf(menuDev, ID_MONITOR_SYSPORT, _("System Port")); AppendIf(menuDev, ID_MONITOR_AREASET, _("Areaset")); AppendIf(menuDev, ID_MONITOR_LCD, "LCD"); AppendIf(menuDev, ID_MONITOR_SYSCLK, _("System Clock")); - for (int i = 0; i < 8; i++) { - int id = ID_MONITOR_VIRTIO_BLOCK(i); - wxString name = _("VirtIO Block") + string_format(" #%d", i); + for (uint i = 0; i < 8; i++) { + uint id = ID_MONITOR_VIRTIO_BLOCK(i); + wxString name = _("VirtIO Block") + string_format(" #%u", i); AppendIf(menuDev, id, name); } AppendIf(menuDev, ID_MONITOR_VIRTIO_NET, _("VirtIO Network")); - AppendIf(menuDev, ID_MONITOR_CRTC, "CRTC"); + AppendIf(menuDev, ID_MONITOR_VIRTIO_SCSI, "VirtIO SCSI"); + AppendIf(menuDev, ID_MONITOR_VIRTIO_ENTROPY,_("VirtIO Entropy")); + AppendIf(menuDev, ID_MONITOR_CRTC, _("CRTC and Video Controller")); AppendIf(menuDev, ID_MONITOR_LUNAVC, _("Video Control")); AppendIf(menuDev, ID_MONITOR_BT45x, "Bt454/458"); AppendIf(menuDev, ID_SUBWIN_PALETTE, _("Palette Colormap")); - AppendIf(menuDev, ID_SUBWIN_TEXTPAL, _("Text Palette Colormap")); AppendIf(menuDev, ID_MONITOR_RENDERER, _("Renderer")); AppendIf(menuDev, ID_SUBWIN_LUNAFB, _("Bitmap Plane")); - AppendIf(menuDev, ID_SUBWIN_TVRAM, _("Text VRAM")); + AppendIf(menuDev, ID_SUBWIN_TVRAM, _("Text Screen")); + AppendIf(menuDev, ID_SUBWIN_GVRAM, _("Graphic Screen")); + AppendIf(menuDev, ID_MONITOR_SOUND, _("Sound")); + AppendIf(menuDev, ID_MONITOR_SSG, "SSG"); + AppendIf(menuDev, ID_MONITOR_ADPCM, "ADPCM"); AppendIf(menuDev, ID_MONITOR_ROMCONS, _("ROM Console (provisional)")); AppendIf(menuDev, ID_SUBWIN_ROM, "ROM"); // LUNA はバスが複数あるので Mainbus Device とする。 // 他の機種ではメインて言われても困るので Device とする。 if (gMainApp.Has(VMCap::LUNA)) { - menuMonitor->AppendSubMenu(menuDev, _("Mainbus De&vice")); + menuMonitor->AppendSubMenu(menuDev, _("Mainbus De&vices")); } else { - menuMonitor->AppendSubMenu(menuDev, _("De&vice")); + menuMonitor->AppendSubMenu(menuDev, _("De&vices")); } wxMenu *menuHost = new wxMenu(); AppendIf(menuHost, ID_MONITOR_WXHOSTINFO, _("Host &Information")); - if (gMainApp.IsX68030()) { - // X68030 ではネットワークは最大2つあるのでナンバリングが必要。 - // あれば表示ではなく、なければ Disable。 - for (int i = 0; i < 2; i++) { - int id = ID_MONITOR_HOSTNET(i); - wxString name = _("Host Network") + string_format(" #%d", i); - menuHost->AppendCheckItem(id, name); - if (gMonitorManager->Find(id) == NULL) { - menuHost->Enable(id, false); - } + AppendIf(menuHost, ID_SUBWIN_THREADS, _("Thread Status")); + for (uint i = 0; i < hostnet.size(); i++) { + uint id = ID_MONITOR_HOSTNET(i); + if (gMonitorManager->Find(id)) { + menuHost->AppendCheckItem(id, GetHostNetLabel(i)); + } + } + AppendIf(menuHost, ID_MONITOR_SLIRP, _("SLIRP Internal States")); + for (uint i = 0; i < hostcom.size(); i++) { + uint id = ID_MONITOR_HOSTCOM(i); + if (gMonitorManager->Find(id)) { + menuHost->AppendCheckItem(id, GetHostComLabel(i)); } - } else { - // それ以外ではネットワークは1つ固定なのでナンバリング不要 - AppendIf(menuHost, ID_MONITOR_HOSTNET(0), _("Host Network")); } - AppendIf(menuHost, ID_MONITOR_HOSTCOM, _("Host &Serial Port")); + AppendIf(menuHost, ID_MONITOR_HOSTSOUND, _("Host Sound")); menuMonitor->AppendSubMenu(menuHost, _("&Host")); wxMenu *menuDebug = new wxMenu(); - AppendIf(menuDebug, ID_SUBWIN_LOG, _("&Log")); - AppendIf(menuDebug, ID_MONITOR_BREAKPOINT, _("&Breakpoint")); + AppendIf(menuDebug, ID_MONITOR_LOG, _("&Log")); + AppendIf(menuDebug, ID_MONITOR_BREAKPOINT, _("&Breakpoints")); menuDebug->AppendSeparator(); AppendIf(menuDebug, ID_SUBWIN_LOGSETTING, _("Log Level &Setting")); + CreateHostComMenu(menuDebug, -1); menuMonitor->AppendSubMenu(menuDebug, _("&Debug")); menubar->Append(menuMonitor, _("&Monitor")); @@ -483,14 +600,14 @@ WXMainFrame::WXMainFrame(wxWindow *paren SetMenuBar(menubar); - wxString title("nono"); + frame_title = wxString("nono"); const char *vmname = gMainApp.GetVMName(); if (vmname) { - title += '('; - title += wxString(vmname); - title += ')'; + frame_title += '('; + frame_title += wxString(vmname); + frame_title += ')'; } - SetTitle(title); + SetMyTitle(false); // UpdateUI イベントは Idle 時に時折チェックされるらしいが、 // (メインビューとサブウィンドウを合わせた) タイマーイベントの粒度が @@ -506,27 +623,35 @@ WXMainFrame::WXMainFrame(wxWindow *paren // mainview のほうを先に作成すること。 mainview = new WXMainView(this); statuspanel = new WXStatusPanel(this); + // 空き地用のパネル。 + spaceL = new WXBitmapPanel(this); + spaceR = new WXBitmapPanel(this); + spaceL->Hide(); + spaceR->Hide(); + + // Sizer 使わず自前でレイアウトする。 + SetAutoLayout(true); + // mainview のスケール、statuspanel のフォントサイズはいずれも + // コンストラクタの時点で初期状態がセットされている。 // SHOW イベントを最初にも一度起こしたいため // ステータスパネルを一旦非表示にする (これで SHOW(false) イベントが飛ぶ) statuspanel->Hide(); - const ConfigItem& item_show = gConfig->Find("show-statuspanel"); - if (item_show.AsInt() != 0) { + if (gConfig->Find("show-statuspanel").AsBool()) { // 必要なら改めて表示 (これで SHOW(true) イベントが飛ぶ) statuspanel->Show(); } - // Sizer 使わず自前でレイアウトする。 - SetAutoLayout(true); + Fit(); // Activate イベントは、このトップレベルウィンドウにウィンドウフォーカスが // 来た or 外れたことを示すので、wxFrame (というかたぶん wxTopLevelWindow) // を継承している WXMainFrameに飛んでくるのだが、処理の都合上 WXMainView で // 扱いたいので、そちらに回す。 - Connect(wxEVT_ACTIVATE, wxActivateEventHandler(WXMainView::OnActivate), - NULL, mainview); + Bind(wxEVT_ACTIVATE, &WXMainView::OnActivate, mainview); // ウィンドウ表示後に続きの処理をするための単発アイドルイベント。 + // こっちは Disconnect() するので Bind() は使えない。 Connect(wxEVT_IDLE, wxIdleEventHandler(WXMainFrame::OnIdle)); // VM からの通知を接続 @@ -536,6 +661,12 @@ WXMainFrame::WXMainFrame(wxWindow *paren wxCommandEventHandler(WXMainFrame::OnInsertFailed)); WXUIMessage::Connect(UIMessage::FDD_MEDIA_FAILED, this, wxCommandEventHandler(WXMainFrame::OnInsertFailed)); + WXUIMessage::Connect(UIMessage::HOSTNET_FAILED, this, + wxCommandEventHandler(WXMainFrame::OnHostNetFailed)); + WXUIMessage::Connect(UIMessage::HOSTCOM_FAILED, this, + wxCommandEventHandler(WXMainFrame::OnHostComFailed)); + WXUIMessage::Connect(UIMessage::HOSTSOUND_FAILED, this, + wxCommandEventHandler(WXMainFrame::OnHostSoundFailed)); if (gMainApp.Has(VMCap::M68K)) { WXUIMessage::Connect(UIMessage::HALT, this, wxCommandEventHandler(WXMainFrame::OnHaltNotify)); @@ -550,6 +681,12 @@ WXMainFrame::~WXMainFrame() wxCommandEventHandler(WXMainFrame::OnInsertFailed)); WXUIMessage::Disconnect(UIMessage::FDD_MEDIA_FAILED, this, wxCommandEventHandler(WXMainFrame::OnInsertFailed)); + WXUIMessage::Disconnect(UIMessage::HOSTNET_FAILED, this, + wxCommandEventHandler(WXMainFrame::OnHostNetFailed)); + WXUIMessage::Disconnect(UIMessage::HOSTCOM_FAILED, this, + wxCommandEventHandler(WXMainFrame::OnHostComFailed)); + WXUIMessage::Disconnect(UIMessage::HOSTSOUND_FAILED, this, + wxCommandEventHandler(WXMainFrame::OnHostSoundFailed)); if (gMainApp.Has(VMCap::M68K)) { WXUIMessage::Disconnect(UIMessage::HALT, this, wxCommandEventHandler(WXMainFrame::OnHaltNotify)); @@ -578,6 +715,106 @@ WXMainFrame::AppendIf(wxMenu *menu, int } } +// HostNet 用のメニューを作成して menuSet に追加する。 +void +WXMainFrame::CreateHostNetMenu(wxMenu *menuSet, uint unit) +{ + if (hostnet[unit] == NULL) { + return; + } + + int offset; + if (unit == 0) { + offset = ID_HOSTNET0_START - ID_HOSTNET0_START; + } else { + offset = ID_HOSTNET1_START - ID_HOSTNET0_START; + } + + wxMenu *menu = new wxMenu(); +#if defined(HAVE_HOSTNET_SLIRP) + menu->AppendRadioItem(offset + ID_HOSTNET0_USERMODE, "&usermode"); +#endif +#if defined(HAVE_HOSTNET_TAP) + menu->AppendRadioItem(offset + ID_HOSTNET0_TAP, "&tap"); +#endif +#if defined(HAVE_HOSTNET_BPF) + menu->AppendRadioItem(offset + ID_HOSTNET0_BPF, "&bpf"); +#endif +#if defined(HAVE_HOSTNET_AFPACKET) + menu->AppendRadioItem(offset + ID_HOSTNET0_AFPACKET, "&afpacket"); +#endif + menu->AppendRadioItem(offset + ID_HOSTNET0_NONE, "&none"); + menuSet->AppendSubMenu(menu, GetHostNetLabel(unit)); +} + +// HostCOM 用のメニューを作成して menuSet に追加する。 +// 引数の n は COM。ただし負数ならデバッガ用。 +void +WXMainFrame::CreateHostComMenu(wxMenu *menuSet, int n) +{ + HostCOMDevice *host; + + // デバッガ用は配列では最後。 + if (n < 0) { + host = hostcom_dbg; + } else { + host = hostcom[n]; + } + + if (host == NULL) { + return; + } + + int offset; + if (n == 0) { + offset = ID_HOSTCOM0_START - ID_HOSTCOM0_START; + } else if (n == 1) { + offset = ID_HOSTCOM1_START - ID_HOSTCOM0_START; + } else if (n == 2) { + offset = ID_HOSTCOM2_START - ID_HOSTCOM0_START; + } else { + offset = ID_HOSTCOM_DBG_START - ID_HOSTCOM0_START; + } + + wxMenu *menu = new wxMenu(); + menu->AppendRadioItem(offset + ID_HOSTCOM0_TCP, "&tcp"); + menu->AppendRadioItem(offset + ID_HOSTCOM0_STDIO, "&stdio"); + if (n >= 0 && gMainApp.FindObject(OBJ_CONSOLE)) { + menu->AppendRadioItem(offset + ID_HOSTCOM0_CONSOLE, "&console"); + } + menu->AppendRadioItem(offset + ID_HOSTCOM0_NONE, "&none"); + wxString name; + if (n >= 0) { + name = GetHostComLabel(n); + } else { + name = _("&Debugger"); + } + menuSet->AppendSubMenu(menu, name); +} + +// HostSound 用のメニューを作成して menuSet に追加する。 +void +WXMainFrame::CreateHostSoundMenu(wxMenu *menuSet) +{ + if (hostsound == NULL) { + return; + } + + wxMenu *menu = new wxMenu(); +#if defined(HAVE_HOSTSOUND_NETBSD) + menu->AppendRadioItem(ID_HOSTSOUND_NETBSD, "&netbsd"); +#endif +#if defined(HAVE_HOSTSOUND_SNDIO) + menu->AppendRadioItem(ID_HOSTSOUND_SNDIO, "&sndio"); +#endif +#if defined(HAVE_HOSTSOUND_ALSA) + menu->AppendRadioItem(ID_HOSTSOUND_ALSA, "&alsa"); +#endif + menu->AppendRadioItem(ID_HOSTSOUND_WAV, "&wav"); + menu->AppendRadioItem(ID_HOSTSOUND_NONE, "&none"); + menuSet->AppendSubMenu(menu, "HostSound"); +} + // リムーバブルデバイス用のメニューを作成して menuDevice に追加する void WXMainFrame::CreateRemovableMenu(wxMenu *menuDevice) @@ -597,10 +834,10 @@ WXMainFrame::CreateRemovableMenu(wxMenu } // CD, MO - auto spc = gMainApp.FindObject(OBJ_SPC); - if (spc) { + auto scsi = gMainApp.FindObject(OBJ_SCSI); + if (scsi) { for (int id = 0; id < 8; id++) { - scsidev[id] = spc->GetTarget(id); + scsidev[id] = scsi->GetTarget(id); if (scsidev[id]) { menu = CreateSCSIRemovableMenu(id); if (menu) { @@ -670,35 +907,50 @@ WXMainFrame::Init() return false; } + statuspanel->Init(); + return true; } -bool -WXMainFrame::Layout() +void +WXMainFrame::Fit() { - if (inherited::Layout() == false) { - return false; + wxSize statsize(0, 0); + if (statuspanel->IsShown()) { + statsize = statuspanel->GetMinSize(); } + const wxSize& viewsize = mainview->GetSize(); + + wxSize size(std::max(statsize.x, viewsize.x), statsize.y + viewsize.y); + SetClientSize(size); +} - wxSize msize = statuspanel->GetMinClientSize(); - wxSize ssize = statuspanel->GetClientSize(); - wxSize vsize = mainview->GetClientSize(); +bool +WXMainFrame::Layout() +{ + const wxSize& client = GetClientSize(); + wxSize statsize(0, 0); if (statuspanel->IsShown()) { - ssize.y = msize.y; - } else { - ssize.y = 0; + statsize = statuspanel->GetSize(); + statuspanel->SetSize(0, 0, client.x, statsize.y); } - wxSize size; - size.x = std::max(msize.x, vsize.x); - size.y = ssize.y + vsize.y; - - if (ssize.y != 0) { - statuspanel->SetSize(0, 0, size.x, ssize.y); + // メインビューの方が小さければ両側に空き地を入れてセンタリングする。 + wxSize viewsize = mainview->GetSize(); + if (viewsize.x < client.x) { + int view_x = (client.x - viewsize.x) / 2; + spaceL->SetSize(0, statsize.y, view_x, viewsize.y); + spaceL->Show(); + mainview->SetSize(view_x, statsize.y, viewsize.x, viewsize.y); + int x = view_x + viewsize.x; + spaceR->SetSize(x, statsize.y, client.x - x, viewsize.y); + spaceR->Show(); + } else { + mainview->SetPosition(wxPoint(0, statsize.y)); + spaceL->Hide(); + spaceR->Hide(); } - mainview->SetSize(0, ssize.y, size.x, vsize.y); - SetClientSize(size); return true; } @@ -726,7 +978,7 @@ WXMainFrame::OnIdle(wxIdleEvent& ev) { // UIMessage の処理を開始する。 // 少なくとも WXMainFrame のコンストラクタが完了した後のほうがいいはず。 - UIMessage::Attach(&WXUIMessage::Process); + gMainApp.GetUIMessage()->StartUIMessage(&WXUIMessage::Process); // ウィンドウを表示 for (int i = 0; i < subwindow_start.size(); i++) { @@ -746,6 +998,8 @@ WXMainFrame::OnIdle(wxIdleEvent& ev) void WXMainFrame::OnClose(wxCloseEvent& event) { + // UIMessage を停止 + gMainApp.GetUIMessage()->StopUIMessage(); // ステータスパネルの更新を停止 statuspanel->Close(); // メインビューの描画を停止 @@ -836,10 +1090,10 @@ WXMainFrame::OnFullSpeed(wxCommandEvent& { if (event.IsChecked()) { // チェックが入ったので、高速モードにする - syncer->RequestFullSpeed(true); + syncer->NotifyFullSpeed(true); } else { // チェックが消えたので、通常モードにする - syncer->RequestFullSpeed(false); + syncer->NotifyFullSpeed(false); } } @@ -873,6 +1127,251 @@ WXMainFrame::OnMenuInputUI(wxUpdateUIEve } } +// メニューの「設定 > HostNet* > *」の選択肢イベント +void +WXMainFrame::OnMenuHostNet(wxCommandEvent& event) +{ + int id = event.GetId(); + uint unit; + uint choice; + + if (id <= ID_HOSTNET0_NONE) { + unit = 0; + choice = id; + } else { + unit = 1; + choice = id - ID_HOSTNET1_START + ID_HOSTNET0_START; + } + + // SLIRP モニタウィンドウはあれば閉じておく必要がある。 + if ((bool)windows[ID_MONITOR_SLIRP]) { + DoWindow(ID_MONITOR_SLIRP, false); + } + + // 設定を更新。 + std::string line = hostnet[unit]->GetConfigKey() + "-driver="; + switch (choice) { + case ID_HOSTNET0_USERMODE: line += "usermode"; break; + case ID_HOSTNET0_TAP: line += "tap"; break; + case ID_HOSTNET0_BPF: line += "bpf"; break; + case ID_HOSTNET0_AFPACKET: line += "afpacket"; break; + case ID_HOSTNET0_NONE: line += "none"; break; + default: + assert(false); + } + gConfig->UpdateRunning(line); + + // ホストスレッドに通知。 + hostnet[unit]->NotifyReselectDriver(); +} + +// メニューの「設定 > HostNet* > *」の UI +void +WXMainFrame::OnMenuHostNetUI(wxUpdateUIEvent& event) +{ + int id = event.GetId(); + uint unit; + + if (id <= ID_HOSTNET0_NONE) { + unit = 0; + } else { + unit = 1; + id = id - ID_HOSTNET1_START + ID_HOSTNET0_START; + } + + const std::string driver = hostnet[unit]->GetDriverName(); + uint selected; + if (driver == "usermode") { + selected = ID_HOSTNET0_USERMODE; + } else if (driver == "tap") { + selected = ID_HOSTNET0_TAP; + } else if (driver == "bpf") { + selected = ID_HOSTNET0_BPF; + } else if (driver == "afpacket") { + selected = ID_HOSTNET0_AFPACKET; + } else { + selected = ID_HOSTNET0_NONE; + } + + event.Check((id == selected)); +} + +// メニューの「設定 > HostCom* > *」の選択肢イベント +void +WXMainFrame::OnMenuHostCom(wxCommandEvent& event) +{ + int id = event.GetId(); + HostCOMDevice *host; + uint choice; + + if (id <= ID_HOSTCOM0_NONE) { + host = hostcom[0]; + choice = id; + } else if (id <= ID_HOSTCOM1_NONE) { + host = hostcom[1]; + choice = id - ID_HOSTCOM1_START + ID_HOSTCOM0_START; + } else if (id <= ID_HOSTCOM2_NONE) { + host = hostcom[2]; + choice = id - ID_HOSTCOM2_START + ID_HOSTCOM0_START; + } else { + host = hostcom_dbg; + choice = id - ID_HOSTCOM_DBG_START + ID_HOSTCOM0_START; + } + + // 設定を更新。 + std::string line = host->GetConfigKey() + "-driver="; + switch (choice) { + case ID_HOSTCOM0_TCP: line += "tcp"; break; + case ID_HOSTCOM0_STDIO: line += "stdio"; break; + case ID_HOSTCOM0_CONSOLE: line += "console"; break; + case ID_HOSTCOM0_NONE: line += "none"; break; + default: + assert(false); + } + gConfig->UpdateRunning(line); + + // ホストスレッドに通知。 + host->NotifyReselectDriver(); +} + +// メニューの「設定 > HostCom* > *」の UI +void +WXMainFrame::OnMenuHostComUI(wxUpdateUIEvent& event) +{ + int id = event.GetId(); + HostCOMDevice *host; + + if (id <= ID_HOSTCOM0_NONE) { + host = hostcom[0]; + } else if (id <= ID_HOSTCOM1_NONE) { + host = hostcom[1]; + id = id - ID_HOSTCOM1_START + ID_HOSTCOM0_START; + } else if (id <= ID_HOSTCOM2_NONE) { + host = hostcom[2]; + id = id - ID_HOSTCOM2_START + ID_HOSTCOM0_START; + } else { + host = hostcom_dbg; + id = id - ID_HOSTCOM_DBG_START + ID_HOSTCOM0_START; + } + + const std::string driver = host->GetDriverName(); + uint selected; + if (driver == "tcp") { + selected = ID_HOSTCOM0_TCP; + } else if (driver == "stdio") { + selected = ID_HOSTCOM0_STDIO; + } else if (driver == "console") { + selected = ID_HOSTCOM0_CONSOLE; + } else { + selected = ID_HOSTCOM0_NONE; + } + + event.Check((id == selected)); +} + +// メニューの「設定 > HostSound > *」の選択肢イベント +void +WXMainFrame::OnMenuHostSound(wxCommandEvent& event) +{ + // 設定を更新。 + std::string line = "hostsound-driver="; + switch (event.GetId()) { + case ID_HOSTSOUND_NETBSD: line += "netbsd"; break; + case ID_HOSTSOUND_SNDIO: line += "sndio"; break; + case ID_HOSTSOUND_ALSA: line += "alsa"; break; + case ID_HOSTSOUND_WAV: line += "wav"; break; + case ID_HOSTSOUND_NONE: line += "none"; break; + default: + assert(false); + } + gConfig->UpdateRunning(line); + + // ホストスレッドに通知。 + hostsound->NotifyReselectDriver(); +} + +// メニューの「設定 > HostSound > *」の UI +void +WXMainFrame::OnMenuHostSoundUI(wxUpdateUIEvent& event) +{ + int id = event.GetId(); + const std::string driver = hostsound->GetDriverName(); + int selected; + if (driver == "netbsd") { + selected = ID_HOSTSOUND_NETBSD; + } else if (driver == "sndio") { + selected = ID_HOSTSOUND_SNDIO; + } else if (driver == "alsa") { + selected = ID_HOSTSOUND_ALSA; + } else if (driver == "wav") { + selected = ID_HOSTSOUND_WAV; + } else { + selected = ID_HOSTSOUND_NONE; + } + + event.Check((id == selected)); +} + +// hostnet ドライバ起動失敗のメッセージ。 +void +WXMainFrame::OnHostNetFailed(wxCommandEvent& event) +{ + wxString hostdev; + wxString errmsg; + uint n = event.GetInt(); + + hostdev.Printf("hostnet%u", n); + errmsg = hostnet[n]->GetErrmsg(); + HostDriverFailed(hostdev, errmsg); +} + +// hostcom ドライバ起動失敗のメッセージ。 +void +WXMainFrame::OnHostComFailed(wxCommandEvent& event) +{ + wxString hostdev; + wxString errmsg; + int n = event.GetInt(); + + if (n >= 0) { + hostdev.Printf("hostcom%u", n); + errmsg = hostcom[n]->GetErrmsg(); + } else { + hostdev = "debugger"; + errmsg = hostcom_dbg->GetErrmsg(); + } + HostDriverFailed(hostdev, errmsg); +} + +// hostsound ドライバ起動失敗のメッセージ +void +WXMainFrame::OnHostSoundFailed(wxCommandEvent& event) +{ + wxString errmsg; + + errmsg = hostsound->GetErrmsg(); + HostDriverFailed("hostsound", errmsg); +} + +// ホストドライバ起動失敗のメッセージ。 +void +WXMainFrame::HostDriverFailed(const wxString& hostdev, const wxString& errmsg) +{ + wxString msg; + + msg = hostdev; + msg += ": "; + msg += _("Failed to switch the driver.\n" + "(Using 'none' instead)"); + if (!errmsg.empty()) { + msg += "\n\n"; + msg += _("Error message:"); + msg += ' '; + msg += errmsg; + } + ::wxMessageBox(msg); +} + // スケール一覧 /*static*/ std::vector WXMainFrame::view_scales { @@ -919,7 +1418,7 @@ WXMainFrame::OnMenuScale(wxCommandEvent& int idx = event.GetId() - ID_SCALE_START; mainview->DoResize(view_scales[idx]); // 再レイアウト - Layout(); + Fit(); } // メニューの「表示 > スケール > *」の共通 UI @@ -971,7 +1470,7 @@ WXMainFrame::OnMenuFontSize(wxCommandEve statuspanel->FontChanged(); // ステータスパネルの大きさが変わるので再レイアウト - Layout(); + Fit(); } } @@ -993,10 +1492,8 @@ WXMainFrame::monrates { 1, }; -// 「表示 > モニタ更新頻度」のメニュー項目作成に必要な monrates を作成し、 -// ユーザ指定値があれば monrates[] 内のインデックスを返す。 -// ユーザ指定値がなければ -1 を返す。 -int +// 「表示 > モニタ更新頻度」のメニュー項目作成に必要な monrates を作成する。 +void WXMainFrame::CreateMonRateTable() { // 設定ファイル monitor-rate で指定された値を追加。 @@ -1010,16 +1507,7 @@ WXMainFrame::CreateMonRateTable() std::sort(monrates.begin(), monrates.end(), [](int a, int b) { return a > b; } ); - - // ユーザ指定の値が何番目かを返す。指定されてなければ -1。 - for (int i = 0, end = monrates.size(); i < end; i++) { - if (monrates[i] == user_rate) { - return i; - } - } - // 見付からないことはないはずだが } - return -1; } // メニューの「表示 > モニタ更新頻度 > *」の共通イベント @@ -1029,7 +1517,7 @@ WXMainFrame::OnMenuMonRate(wxCommandEven int idx = event.GetId() - ID_MONRATE_START; monitor_rate = monrates[idx]; - // アクティブなサブウィンドウのテキストパネル全員に通知 + // アクティブなサブウィンドウのモニタパネル全員に通知。 for (int i = 0; i < ID_SUBWIN_MAX; i++) { if ((bool)windows[i]) { auto *subwin = dynamic_cast(windows[i].get()); @@ -1062,7 +1550,7 @@ WXMainFrame::OnShowStatusPanel(wxCommand statuspanel->Show(enable); // 再レイアウト - Layout(); + Fit(); } // メニューの「表示 > ステータスパネルを表示」UI @@ -1261,12 +1749,6 @@ WXMainFrame::OnMouseMode(wxCommandEvent& // enable ならチェックを付けようとして呼ばれた bool enable = event.IsChecked(); - if (enable) { - // メッセージを表示したい - } else { - // メッセージを表示したい - } - // マウスモードを設定 wxCommandEvent newev(NONO_EVT_MOUSEMODE, GetId()); newev.SetEventObject(this); @@ -1310,6 +1792,13 @@ WXMainFrame::OnWindow(wxCommandEvent& ev DoWindow(id, event.IsChecked()); } +#define SetMonitor(id, name) do { \ + try { \ + windows[id].reset(new WXMonitorWindow(this, (name), \ + gMonitorManager->Get(id))); \ + } catch (...) { } \ +} while (0) + void WXMainFrame::DoWindow(int id, bool enable) { @@ -1317,15 +1806,20 @@ WXMainFrame::DoWindow(int id, bool enabl // id はモニター ID であると同時に、windows[] 配列の添字、さらにこの // モニタウィンドウの wxWindowID としても使っている // (WXSubWindow::OnClose() 参照)。 -#define SetMonitor(id, name) \ - windows[id].reset(new WXMonitorWindow(this, (name), \ - gMonitorManager->Get(id))) if (enable) { // チェックが入ったのでウィンドウを作成 switch (id) { case ID_MONITOR_ACCSTAT: - SetMonitor(id, _("Access Status")); + // こいつだけモニタ ID を持ちつつ上位互換のサブウィンドウがある。 + try { + windows[id].reset(new + WXAccStatWindow(this, gMonitorManager->Get(id))); + } catch (...) { } + break; + + case ID_MONITOR_ADPCM: + SetMonitor(id, "ADPCM"); break; case ID_MONITOR_AREASET: @@ -1341,8 +1835,8 @@ WXMainFrame::DoWindow(int id, bool enabl case ID_MONITOR_ATC6: case ID_MONITOR_ATC7: { - int n = id - ID_MONITOR_ATC0; - wxString name(string_format("ATC#%d", n)); + uint n = id - ID_MONITOR_ATC0; + wxString name(string_format("ATC#%u", n)); if ((n & 1) == 0) { name += _("(Data)"); } else { @@ -1353,7 +1847,7 @@ WXMainFrame::DoWindow(int id, bool enabl } case ID_MONITOR_BREAKPOINT: - SetMonitor(id, _("Breakpoint")); + SetMonitor(id, _("Breakpoints")); break; case ID_MONITOR_BT45x: @@ -1369,19 +1863,21 @@ WXMainFrame::DoWindow(int id, bool enabl case ID_MONITOR_CMMU6: case ID_MONITOR_CMMU7: { - int n = id - ID_MONITOR_CMMU0; - wxString name(string_format("CMMU#%d", n)); + uint n = id - ID_MONITOR_CMMU0; + wxString name(string_format("CMMU#%u", n)); if ((n & 1) == 0) { name += _("(Data)"); } else { name += _("(Inst)"); } + name += ' '; + name += _("Registers"); SetMonitor(id, name); break; } case ID_MONITOR_CRTC: - SetMonitor(id, "CRTC"); + SetMonitor(id, _("CRTC and Video Controller")); break; case ID_MONITOR_DMAC: @@ -1392,30 +1888,35 @@ WXMainFrame::DoWindow(int id, bool enabl SetMonitor(id, "FDC (uPD72065B)"); break; - case ID_MONITOR_HOSTCOM: - SetMonitor(id, _("Host Serial Port")); + case ID_MONITOR_HOSTCOM0: + case ID_MONITOR_HOSTCOM1: + case ID_MONITOR_HOSTCOM2: + { + uint n = id - ID_MONITOR_HOSTCOM0; + SetMonitor(id, GetHostComLabel(n)); break; + } case ID_MONITOR_HOSTNET0: case ID_MONITOR_HOSTNET1: { - wxString name = _("Host Network"); - if (gMainApp.IsX68030()) { - int n = id - ID_MONITOR_HOSTNET0; - name += string_format(" #%d", n); - } - SetMonitor(id, name); + uint n = id - ID_MONITOR_HOSTNET0; + SetMonitor(id, GetHostNetLabel(n)); break; } + case ID_MONITOR_HOSTSOUND: + SetMonitor(id, _("Host Sound")); + break; + case ID_MONITOR_INTERRUPT: { wxString name; - if (gMainApp.Has(VMCap::M88K)) { - // 実際はほぼシステムコントローラなのでややこしい。 - name = "MPU " + _("Interrupt"); + if (gMainApp.Has(VMCap::M68K)) { + name = MPUName() + " " + _("Interrupts"); } else { - name = MPUName() + " " + _("Interrupt"); + // 実際はほぼシステムコントローラなのでややこしい。 + name = "MPU " + _("Interrupts"); } SetMonitor(id, name); break; @@ -1430,7 +1931,15 @@ WXMainFrame::DoWindow(int id, bool enabl break; case ID_MONITOR_LCD: - windows[id].reset(new WXLCDMonitor(this)); + try { + windows[id].reset(new WXLCDMonitor(this)); + } catch (...) { } + break; + + case ID_MONITOR_LOG: + try { + windows[id].reset(new WXLogMonitor(this)); + } catch (...) { } break; case ID_MONITOR_LUNAVC: @@ -1454,7 +1963,9 @@ WXMainFrame::DoWindow(int id, bool enabl case ID_MONITOR_XPMEMDUMP0 ... ID_MONITOR_XPMEMDUMP(MAX_XPMEMDUMP_MONITOR - 1): { - windows[id].reset(new WXMemdumpWindow(this, id)); + try { + windows[id].reset(new WXMemdumpWindow(this, id)); + } catch (...) { } break; } @@ -1471,11 +1982,11 @@ WXMainFrame::DoWindow(int id, bool enabl break; case ID_MONITOR_MPUCACHE: - SetMonitor(id, MPUName() + " " + _("Cache")); + SetMonitor(id, MPUName() + " " + _("Caches")); break; case ID_MONITOR_MPUREG: - SetMonitor(id, MPUName() + " " + _("Register")); + SetMonitor(id, MPUName() + " " + _("Registers")); break; case ID_MONITOR_NEREID: @@ -1513,8 +2024,8 @@ WXMainFrame::DoWindow(int id, bool enabl case ID_MONITOR_RTL8019AS0: case ID_MONITOR_RTL8019AS1: { - int n = id - ID_MONITOR_RTL8019AS0; - wxString name = string_format("Nereid (RTL8019AS) #%d", n); + uint n = id - ID_MONITOR_RTL8019AS0; + wxString name = string_format("Nereid#%u (RTL8019AS)", n); SetMonitor(id, name); break; } @@ -1535,10 +2046,22 @@ WXMainFrame::DoWindow(int id, bool enabl SetMonitor(id, "SIO (uPD7201)"); break; + case ID_MONITOR_SLIRP: + SetMonitor(id, _("SLIRP Internal States")); + break; + + case ID_MONITOR_SOUND: + SetMonitor(id, _("Sound")); + break; + case ID_MONITOR_SPC: SetMonitor(id, "SPC (MB89352)"); break; + case ID_MONITOR_SSG: + SetMonitor(id, "SSG (YM2149)"); + break; + case ID_MONITOR_SYSCLK: SetMonitor(id, _("System Clock")); break; @@ -1550,8 +2073,8 @@ WXMainFrame::DoWindow(int id, bool enabl case ID_MONITOR_VIRTIO_BLOCK0 ... ID_MONITOR_VIRTIO_BLOCK7: { - int n = id - ID_MONITOR_VIRTIO_BLOCK0; - wxString name = _("VirtIO Block") + string_format(" #%d", n); + uint n = id - ID_MONITOR_VIRTIO_BLOCK0; + wxString name = _("VirtIO Block") + string_format(" #%u", n); SetMonitor(id, name); break; } @@ -1560,16 +2083,28 @@ WXMainFrame::DoWindow(int id, bool enabl SetMonitor(id, _("VirtIO Network")); break; + case ID_MONITOR_VIRTIO_SCSI: + SetMonitor(id, "VirtIO SCSI"); + break; + + case ID_MONITOR_VIRTIO_ENTROPY: + SetMonitor(id, _("VirtIO Entropy")); + break; + case ID_MONITOR_WXHOSTINFO: SetMonitor(id, _("Host Information")); break; + case ID_MONITOR_XPASCI: + SetMonitor(id, "HD647180 ASCI"); + break; + case ID_MONITOR_XPREG: - SetMonitor(id, "HD647180 " + _("Register")); + SetMonitor(id, "HD647180 " + _("Registers")); break; case ID_MONITOR_XPINTR: - SetMonitor(id, "HD647180 " + _("Interrupt")); + SetMonitor(id, "HD647180 " + _("Interrupts")); break; case ID_MONITOR_XPIO: @@ -1579,16 +2114,20 @@ WXMainFrame::DoWindow(int id, bool enabl case ID_SUBWIN_BRHIST: { wxString name = MPUName() + " " + _("Branch History"); - windows[id].reset(new WXScrollMonitorWindow(this, name, - gMonitorManager->Get(id))); + try { + windows[id].reset(new WXScrollMonitorWindow(this, name, + gMonitorManager->Get(id))); + } catch (...) { } break; } case ID_SUBWIN_EXHIST: { wxString name = MPUName() + " " + _("Exception History"); - windows[id].reset(new WXScrollMonitorWindow(this, name, - gMonitorManager->Get(id))); + try { + windows[id].reset(new WXScrollMonitorWindow(this, name, + gMonitorManager->Get(id))); + } catch (...) { } break; } @@ -1601,31 +2140,43 @@ WXMainFrame::DoWindow(int id, bool enabl case ID_SUBWIN_CACHE6: case ID_SUBWIN_CACHE7: { - int n = id - ID_SUBWIN_CACHE0; + uint n = id - ID_SUBWIN_CACHE0; wxString name = _("Cache"); - name += string_format("#%d", n); + name += string_format("#%u", n); if ((n & 1) == 0) { name += _("(Data)"); } else { name += _("(Inst)"); } - windows[id].reset(new WXCacheWindow(this, name, - gMonitorManager->Get(id))); + try { + windows[id].reset(new WXCacheWindow(this, name, + gMonitorManager->Get(id))); + } catch (...) { } break; } case ID_SUBWIN_DIPSW: - windows[id].reset(new WXDipswWindow(this)); + try { + windows[id].reset(new WXDipswWindow(this)); + } catch (...) { } break; - case ID_SUBWIN_LCDPANEL: - windows[id].reset(new WXLCDWindow(this)); + case ID_SUBWIN_GVRAM: + try { + windows[id].reset(new WXGVRAMWindow(this, _("Graphic Screen"))); + } catch (...) { } break; - case ID_SUBWIN_LOG: - windows[id].reset(new WXLogMonitor(this)); + + case ID_SUBWIN_LCDPANEL: + try { + windows[id].reset(new WXLCDWindow(this)); + } catch (...) { } break; + case ID_SUBWIN_LOGSETTING: - windows[id].reset(new WXLogSettingWindow(this)); + try { + windows[id].reset(new WXLogSettingWindow(this)); + } catch (...) { } break; case ID_SUBWIN_LUNAFB: @@ -1636,71 +2187,100 @@ WXMainFrame::DoWindow(int id, bool enabl if (id == ID_SUBWIN_LUNAFB) { name = _("Bitmap Plane"); } else { - name = _("Text VRAM"); + name = _("Text Screen"); } - windows[id].reset(new WXPlaneVRAMWindow(this, name)); + try { + windows[id].reset(new WXTVRAMWindow(this, name)); + } catch (...) { } break; } - case ID_SUBWIN_NEWSIO: + case ID_SUBWIN_MPUPT: { - windows[id].reset(new WXScrollMonitorWindow(this, - _("Device Map (NEWS)"), - gMonitorManager->Get(id))); + wxString name = MPUName() + " " + _("Page Table"); + if (MPUName() == "MC68030") { + try { + windows[id].reset(new WXPageTable68030Window(this, name)); + } catch (...) { } + } else if (MPUName() == "MC68040") { + try { + windows[id].reset(new WXPageTable68040Window(this, name)); + } catch (...) { } + } else { + // not supported + } break; } + case ID_SUBWIN_NEWSIO: + try { + windows[id].reset(new WXScrollMonitorWindow(this, + _("Device Map (NEWS)"), + gMonitorManager->Get(id))); + } catch (...) { } + break; + case ID_SUBWIN_PALETTE: - case ID_SUBWIN_TEXTPAL: - { - // 呼び方が違うので名前と ID が違う - wxString name; - if (id == ID_SUBWIN_TEXTPAL) { - name = _("Text Palette Colormap"); - } else { - name = _("Palette Colormap"); - } - windows[id].reset(new WXPaletteWindow(this, name)); + try { + windows[id].reset(new WXPaletteWindow(this, + _("Palette Colormap"))); + } catch (...) { } break; - } case ID_SUBWIN_ROM: - windows[id].reset(new WXROMWindow(this)); + try { + windows[id].reset(new WXROMWindow(this)); + } catch (...) { } break; case ID_SUBWIN_SOFTKEY: - windows[id].reset(new WXSoftKeyWindow(this, gMainApp.GetVMType())); + try { + windows[id].reset(new WXSoftKeyWindow(this, + gMainApp.GetVMType())); + } catch (...) { } + break; + + case ID_SUBWIN_THREADS: + try { + windows[id].reset(new WXThreadMonitorWindow(this)); + } catch (...) { } break; case ID_SUBWIN_VECTOR: { wxString name = MPUName() + " " + _("Vector Table"); - windows[id].reset(new WXScrollMonitorWindow(this, name, - gMonitorManager->Get(id))); + try { + windows[id].reset(new WXScrollMonitorWindow(this, name, + gMonitorManager->Get(id))); + } catch (...) { } break; } case ID_SUBWIN_X68KIO: - { - windows[id].reset(new WXScrollMonitorWindow(this, - _("Device Map (24bit space)"), - gMonitorManager->Get(id))); + try { + windows[id].reset(new WXScrollMonitorWindow(this, + _("Device Map (24bit space)"), + gMonitorManager->Get(id))); + } catch (...) { } break; - } case ID_SUBWIN_XPBRHIST: { wxString name = "HD647180 " + _("Branch History"); - windows[id].reset(new WXScrollMonitorWindow(this, name, - gMonitorManager->Get(id))); + try { + windows[id].reset(new WXScrollMonitorWindow(this, name, + gMonitorManager->Get(id))); + } catch (...) { } break; } case ID_SUBWIN_XPEXHIST: { wxString name = "HD647180 " + _("Exception History"); - windows[id].reset(new WXScrollMonitorWindow(this, name, - gMonitorManager->Get(id))); + try { + windows[id].reset(new WXScrollMonitorWindow(this, name, + gMonitorManager->Get(id))); + } catch (...) { } break; } @@ -1724,22 +2304,29 @@ WXMainFrame::OnWindowUI(wxUpdateUIEvent& // ウィンドウが存在していればチェックを表示 event.Check((bool)windows[id]); + // SLIRP モニタだけ無効状態がある。 +#if defined(HAVE_HOSTNET_SLIRP) + if (__predict_false(id == ID_MONITOR_SLIRP)) { + event.Enable(NetDriverSlirp::IsOccupied()); + } +#endif + if (IS_MONITOR_MEMDUMP(id) || IS_MONITOR_XPMEMDUMP(id)) { // メニューに現在のアドレスを載せる // (ウィンドウの生存期間外にも呼ばれることに注意) auto mon = gMonitorManager->Get(id); - auto *memdump = dynamic_cast(mon.obj); + auto *memdump = dynamic_cast(mon->obj); assert(memdump); - uint32 addr = memdump->GetAddr(); + uint32 addr = memdump->GetAddr().Addr(); - int n; + uint n; wxString text = _("Memory Dump"); if (IS_MONITOR_XPMEMDUMP(id)) { n = id - ID_MONITOR_XPMEMDUMP0; - text += string_format(" &%d: $%05x", n, addr); + text += string_format(" &%u: $%05x", n, addr); } else { n = id - ID_MONITOR_MEMDUMP0; - text += string_format(" &%d: $%08x", n, addr); + text += string_format(" &%u: $%08x", n, addr); } event.SetText(text); } @@ -1826,14 +2413,6 @@ WXMainFrame::DeleteWindow(wxWindow *win) } } -// メイン MPU 名を返す。メニューとタイトルによく出てくるので。 -// 88xx0 とか 88200 は別処理。 -wxString -WXMainFrame::MPUName() const -{ - return mpu->GetMPUName(); -} - // m680x0 ダブルバスフォールト処理 void WXMainFrame::OnHaltNotify(wxCommandEvent& event) @@ -1843,6 +2422,36 @@ WXMainFrame::OnHaltNotify(wxCommandEvent wxICON_EXCLAMATION); } +// HostNet に対する表示用テキストを返す。 +wxString +WXMainFrame::GetHostNetLabel(uint n) const +{ + return wxString(string_format("HostNet%u: ", n) + + hostnet[n]->GetPortName()); +} + +// HostCOM に対する表示用テキストを返す。 +// デバッガ用は呼び出し側で処理すること。 +wxString +WXMainFrame::GetHostComLabel(uint n) const +{ + assert((int)n >= 0); + return wxString(string_format("HostCom%u: ", n) + + hostcom[n]->GetPortName()); +} + +// メインウィンドウのタイトルを (mousemode によって) 変更する。 +void +WXMainFrame::SetMyTitle(bool mousemode) +{ + wxString new_title = frame_title; + if (mousemode) { + // メッセージを表示したい + new_title += " (CTRL + F12 to quit mouse mode)"; + } + SetTitle(new_title); +} + // 起動時にオープンするサブウィンドウ (-M オプション) /*static*/ std::array WXMainFrame::subwindow_start;