--- nono/wx/wxmainframe.cpp 2026/04/29 17:05:12 1.1.1.14 +++ nono/wx/wxmainframe.cpp 2026/04/29 17:05:16 1.1.1.15 @@ -10,6 +10,7 @@ #include "wxmainframe.h" #include "fontmanager.h" +#include "wxdipswwindow.h" #include "wxdumpmonitor.h" #include "wxlcdwindow.h" #include "wxlogmonitor.h" @@ -17,6 +18,7 @@ #include "wxmainview.h" #include "wxmonitor.h" #include "wxmpumonitor.h" +#include "wxpalettemonitor.h" #include "wxplanemonitor.h" #include "wxromwindow.h" #include "wxsoftkey.h" @@ -24,18 +26,15 @@ #include "wxuimessage.h" #include "wxversion.h" #include "config.h" -#include "debugger.h" #include "fdc.h" #include "fdd.h" #include "mainapp.h" -#include "mpu680x0.h" -#include "mpu88xx0.h" -#include "netdriver.h" #include "nmi.h" #include "power.h" #include "spc.h" -#include "sync.h" +#include "syncer.h" #include "vm.h" +#include // ID は 0 から (wxID_LOWEST = 5000 未満まで) 使えるっぽい。 // メニュー ID のうちウィンドウのオープン状態を維持する必要があるものは @@ -67,6 +66,7 @@ enum { ID_SUBWIN_END_DUMMY = ID_SUBWIN_END, // ここから (ウィンドウでない)メニュー ID + ID_EXIT, ID_RESTART_VM, ID_FULL_SPEED, @@ -76,21 +76,16 @@ enum { ID_INPUT_END, ID_SCALE_START, - ID_SCALE_1_00, - ID_SCALE_0_75, - ID_SCALE_0_50, - ID_SCALE_END, + ID_SCALE_END = ID_SCALE_START + 6, ID_FONTSIZE_START, // START 以降は fontsize_t と同じ順に並べること ID_FONTSIZE_12, ID_FONTSIZE_16, + ID_FONTSIZE_24, ID_FONTSIZE_END, ID_MONRATE_START, - ID_MONRATE_20, - ID_MONRATE_5, - ID_MONRATE_1, - ID_MONRATE_END, + ID_MONRATE_END = ID_MONRATE_START + 4, ID_SHOW_STATPANEL, @@ -156,11 +151,9 @@ static_assert(ID_local_end - 1 <= (int)I #define ID_CD_EJECT(id) (ID_CD_EJECT_0 + (id)) #define ID_CD_FORCE(id) (ID_CD_FORCE_0 + (id)) -WXMainFrame *gMainFrame; - wxBEGIN_EVENT_TABLE(WXMainFrame, inherited) EVT_CLOSE(WXMainFrame::OnClose) - EVT_MENU(wxID_EXIT, WXMainFrame::OnExit) + EVT_MENU(ID_EXIT, WXMainFrame::OnExit) EVT_MENU(ID_RESTART_VM, WXMainFrame::OnRestartVM) EVT_MENU(ID_FULL_SPEED, WXMainFrame::OnFullSpeed) @@ -169,17 +162,17 @@ 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_SCALE_START + 1, ID_SCALE_END - 1, + EVT_MENU_RANGE(ID_SCALE_START, ID_SCALE_END, WXMainFrame::OnMenuScale) - EVT_UPDATE_UI_RANGE(ID_SCALE_START + 1, ID_SCALE_END - 1, + EVT_UPDATE_UI_RANGE(ID_SCALE_START, ID_SCALE_END, WXMainFrame::OnMenuScaleUI) EVT_MENU_RANGE(ID_FONTSIZE_START + 1, ID_FONTSIZE_END - 1, WXMainFrame::OnMenuFontSize) EVT_UPDATE_UI_RANGE(ID_FONTSIZE_START + 1, ID_FONTSIZE_END - 1, WXMainFrame::OnMenuFontSizeUI) - EVT_MENU_RANGE(ID_MONRATE_START + 1, ID_MONRATE_END - 1, + EVT_MENU_RANGE(ID_MONRATE_START, ID_MONRATE_END, WXMainFrame::OnMenuMonRate) - EVT_UPDATE_UI_RANGE(ID_MONRATE_START + 1, ID_MONRATE_END - 1, + EVT_UPDATE_UI_RANGE(ID_MONRATE_START, ID_MONRATE_END, WXMainFrame::OnMenuMonRateUI) EVT_MENU(ID_SHOW_STATPANEL, WXMainFrame::OnShowStatusPanel) EVT_UPDATE_UI(ID_SHOW_STATPANEL, WXMainFrame::OnShowStatusPanelUI) @@ -227,38 +220,69 @@ WXMainFrame::WXMainFrame(wxWindow *paren VMType vmtype; vmtype = gMainApp.GetVMType(); + // デバイスを取得 + power = GetPowerDevice(); + syncer = GetSyncer(); + // デバイスを取得。こっちはあるかどうかを調べる + keyboard = gMainApp.FindObject(OBJ_KEYBOARD); + // メニュー wxMenuBar *menubar = new wxMenuBar(); // メニュー > ファイル wxMenu *menuFile = new wxMenu(); menuFile->Append(ID_RESTART_VM, _("&Restart VM"), ""); - menuFile->Append(wxID_EXIT, _("E&xit")); + menuFile->Append(ID_EXIT, _("E&xit")); menubar->Append(menuFile, _("&File")); // メニュー > 設定 wxMenu *menuSet = new wxMenu(); menuSet->Append(ID_FULL_SPEED, _("Full &Speed Mode"), "", wxITEM_CHECK); - wxMenu *menuSetInput = new wxMenu(); - menuSetInput->AppendRadioItem(ID_INPUT_CHAR, _("By &Character")); - menuSetInput->AppendRadioItem(ID_INPUT_JP, _("&JP Keyboard")); - menuSet->AppendSubMenu(menuSetInput, _("&Key Input")); + if (keyboard) { + wxMenu *menuSetInput = new wxMenu(); + menuSetInput->AppendRadioItem(ID_INPUT_CHAR, _("By &Character")); + menuSetInput->AppendRadioItem(ID_INPUT_JP, _("&JP Keyboard")); + menuSet->AppendSubMenu(menuSetInput, _("&Key Input")); + } menubar->Append(menuSet, _("&Setting")); // メニュー > 表示 wxMenu *menuDisplay = new wxMenu(); wxMenu *menuViewScale = new wxMenu(); - menuViewScale->Append(ID_SCALE_1_00, _("x1.&0"), "", wxITEM_CHECK); - menuViewScale->Append(ID_SCALE_0_75, _("x0.&75"), "", wxITEM_CHECK); - menuViewScale->Append(ID_SCALE_0_50, _("x0.&5"), "", wxITEM_CHECK); + int user_idx = CreateMainviewScaleTable(); + for (int i = 0, end = view_scales.size(); i < end; i++) { + std::string text; + if (i == user_idx) { + // ユーザ指定値は極力指定されたまま表示。 + text = string_format("x%g", view_scales[i]); + } else { + // プリセットの数値は "0.5", "0.75", "1.0" と都合よく整形したい。 + text = string_format("x%.2f", view_scales[i]); + if (text.size() == 5 && text[4] == '0') { + text.pop_back(); + } + } + menuViewScale->AppendRadioItem(ID_SCALE_START + i, text); + } menuDisplay->AppendSubMenu(menuViewScale, _("&Scale")); wxMenu *menuFontSize = new wxMenu(); menuFontSize->AppendRadioItem(ID_FONTSIZE_12, "1&2"); menuFontSize->AppendRadioItem(ID_FONTSIZE_16, "1&6"); + menuFontSize->AppendRadioItem(ID_FONTSIZE_24, "2&4"); menuDisplay->AppendSubMenu(menuFontSize, _("&Font Size")); wxMenu *menuMonRate = new wxMenu(); - menuMonRate->AppendRadioItem(ID_MONRATE_20, _("High (&20Hz)")); - menuMonRate->AppendRadioItem(ID_MONRATE_5, _("Middle (&5Hz)")); - menuMonRate->AppendRadioItem(ID_MONRATE_1, _("Low (&1Hz)")); + user_idx = CreateMonRateTable(); + for (int i = 0, end = monrates.size(); i < end; i++) { + std::string text; + switch (monrates[i]) { + case 20: text = _("High (&20Hz)"); break; + case 5: text = _("Middle (&5Hz)"); break; + case 1: text = _("Low (&1Hz)"); break; + default: + text = _("User specified") + string_format(" (%dHz)", monrates[i]); + break; + } + menuMonRate->AppendRadioItem(ID_MONRATE_START + i, text); + } menuDisplay->AppendSubMenu(menuMonRate, _("&Monitor Speed")); menuDisplay->Append(ID_SHOW_STATPANEL, _("Show Status &Panel"), "", wxITEM_CHECK); @@ -267,14 +291,19 @@ WXMainFrame::WXMainFrame(wxWindow *paren // メニュー > デバイス wxMenu *menuDevice = new wxMenu(); CreateRemovableMenu(menuDevice); - menuDevice->Append(ID_SUBWIN_SOFTKEY, _("Software &Keyboard"), - "", wxITEM_CHECK); - menuDevice->Append(ID_MOUSEMODE, _("&Mouse Mode\tCTRL+F12"), - "", wxITEM_CHECK); + if (keyboard) { + menuDevice->Append(ID_SUBWIN_SOFTKEY, _("Software &Keyboard"), + "", wxITEM_CHECK); + menuDevice->Append(ID_MOUSEMODE, _("&Mouse Mode\tCTRL+F12"), + "", wxITEM_CHECK); + } if (gMainApp.Has(VMCap::LUNA)) { menuDevice->Append(ID_SUBWIN_LCDPANEL, _("Front &LCD"), "", wxITEM_CHECK); } + if (gMainApp.Has(VMCap::LUNA | VMCap::NEWS)) { + menuDevice->Append(ID_SUBWIN_DIPSW, "&DIPSW", "", wxITEM_CHECK); + } menuDevice->AppendSeparator(); wxMenu *menuOper = new wxMenu(); wxItemKind power_button_kind; @@ -288,13 +317,20 @@ WXMainFrame::WXMainFrame(wxWindow *paren menuOper->Append(ID_RESET_BUTTON, _("Push &Reset button")); if (gMainApp.Has(VMCap::LUNA)) { menuOper->Append(ID_NMI_BUTTON, _("Push &ABORT button")); - } else { + } else if (gMainApp.Has(VMCap::X68030)) { menuOper->Append(ID_NMI_BUTTON, _("Push &Interrupt button")); } - menuOper->AppendSeparator(); - menuOper->Append(ID_KEYBOARD_CONNECT, _("Connect &Keyboard"), - "", wxITEM_CHECK); - menuDevice->AppendSubMenu(menuOper, _("Operation")); + // これ以降があればここにセパレータがほしい + bool sep = false; + if (keyboard) { + if (sep == false) { + menuOper->AppendSeparator(); + sep = true; + } + menuOper->Append(ID_KEYBOARD_CONNECT, _("Connect &Keyboard"), + "", wxITEM_CHECK); + } + menuDevice->AppendSubMenu(menuOper, _("&Operation")); menubar->Append(menuDevice, _("&Device")); // 機種によってモニタウィンドウを追加する @@ -313,20 +349,11 @@ WXMainFrame::WXMainFrame(wxWindow *paren // メニュー > モニター wxMenu *menuMonitor = new wxMenu(); AppendIf(menuMonitor, ID_MONITOR_SCHEDULER, _("&Scheduler")); - AppendIf(menuMonitor, ID_SUBWIN_LOG, _("&Log")); - - wxMenu *menuDebug = new wxMenu(); - AppendIf(menuDebug, ID_MONITOR_BREAKPOINT, _("&Breakpoint")); - AppendIf(menuDebug, ID_SUBWIN_BRHIST, _("Branch &History")); - AppendIf(menuDebug, ID_SUBWIN_EXHIST, _("&Exception History")); - AppendIf(menuDebug, ID_SUBWIN_VECTOR, _("&Vector Table")); - menuDebug->AppendSeparator(); - AppendIf(menuDebug, ID_SUBWIN_LOGSETTING, _("&Log Level Setting")); - menuMonitor->AppendSubMenu(menuDebug, _("&Debug")); wxMenu *menuMPU = new wxMenu(); AppendIf(menuMPU, ID_MONITOR_MPUREG, _("&Register")); AppendIf(menuMPU, ID_MONITOR_MPUATC, "&ATC"); + AppendIf(menuMPU, ID_MONITOR_INTERRUPT, _("&Interrupt")); AppendIfSeparator(menuMPU, VMCap::M88K); AppendIf(menuMPU, ID_MONITOR_CMMU7, "CMMU#7" + _("(Inst)")); AppendIf(menuMPU, ID_MONITOR_ATC7, "ATC#7"); @@ -335,38 +362,62 @@ WXMainFrame::WXMainFrame(wxWindow *paren AppendIf(menuMPU, ID_MONITOR_CMMU6, "CMMU#6" + _("(Data)")); AppendIf(menuMPU, ID_MONITOR_ATC6, "ATC#6"); AppendIf(menuMPU, ID_SUBWIN_CACHE6, _("Cache") + "#6"); - menuMonitor->AppendSubMenu(menuMPU, "MP&U"); + menuMPU->AppendSeparator(); + // MEMDUMPn のラベルは UpdateUI で書き直すのでここでは適当に + // 埋めておく。(empty だと怒られる) + for (int 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)")); + + 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_XPIO, _("Internal &Devices")); + menuXP->AppendSeparator(); + for (int i = 0; i < MAX_XPMEMDUMP_MONITOR; i++) { + AppendIf(menuXP, ID_MONITOR_XPMEMDUMP(i), "memdump"); + } + menuXP->AppendSeparator(); + AppendIf(menuXP, ID_SUBWIN_XPBRHIST, _("Branch &History")); + AppendIf(menuXP, ID_SUBWIN_XPEXHIST, _("&Exception History")); + menuMonitor->AppendSubMenu(menuXP, "XP(HD647180)"); + } - wxMenu *menuMemdump = new wxMenu(); - // MEMDUMPn のラベルは UpdateUI で書き直すのでここでは適当に埋めておく。 - // (empty だと怒られる) // MONITOR_RTC は X68k の RTC、LUNA では MONITOR_MK48T02 だが今の所 // NVRAM 側のことは表示してないのでラベルも RTC にしてある。 - for (int i = 0; i < MAX_MEMDUMP_MONITOR; i++) { - AppendIf(menuMemdump, ID_MONITOR_MEMDUMP0 + i, "memdump"); - } - menuMonitor->AppendSubMenu(menuMemdump, _("&Memory Dump")); - AppendIf(menuMonitor, ID_MONITOR_INTERRUPT, _("&Interrupt")); - AppendIf(menuMonitor, ID_MONITOR_SPC, "S&PC"); - AppendIf(menuMonitor, ID_MONITOR_SCSIDEVS, _("SCSI Devices")); - AppendIf(menuMonitor, ID_MONITOR_RTC, "&RTC"); - AppendIf(menuMonitor, ID_MONITOR_MK48T02, "&RTC"); - AppendIf(menuMonitor, ID_MONITOR_DMAC, "DM&AC"); - AppendIf(menuMonitor, ID_MONITOR_MFP, "M&FP"); - AppendIf(menuMonitor, ID_MONITOR_FDC, "F&DC"); - AppendIf(menuMonitor, ID_MONITOR_SCC, "SCC(&Z)"); - AppendIf(menuMonitor, ID_MONITOR_SIO, "SIO(&U)"); - AppendIf(menuMonitor, ID_MONITOR_PIO0, "PIO0"); - AppendIf(menuMonitor, ID_MONITOR_KEYBOARD, _("&Keyboard/Mouse")); - AppendIf(menuMonitor, ID_MONITOR_LANCE, "Lance(&E)"); - AppendIf(menuMonitor, ID_MONITOR_LCD, "LCD(&J)"); - AppendIf(menuMonitor, ID_MONITOR_SYSCLK, _("S&ystem Clock")); - AppendIf(menuMonitor, ID_MONITOR_CRTC, "CRTC"); - AppendIf(menuMonitor, ID_MONITOR_LUNAVC, _("&Video Control")); - AppendIf(menuMonitor, ID_MONITOR_RENDERER, _("Renderer")); - AppendIf(menuMonitor, ID_SUBWIN_LUNAFB, _("&Bitmap Plane")); - AppendIf(menuMonitor, ID_SUBWIN_TVRAM, _("&Text VRAM")); - AppendIf(menuMonitor, ID_SUBWIN_ROM, "ROM"); + wxMenu *menuDev = new wxMenu(); + AppendIf(menuDev, ID_MONITOR_SPC, "SPC"); + AppendIf(menuDev, ID_MONITOR_SCSIDEVS, _("SCSI Devices")); + AppendIf(menuDev, ID_MONITOR_RTC, "RTC"); + AppendIf(menuDev, ID_MONITOR_MK48T02, "RTC"); + AppendIf(menuDev, ID_MONITOR_DMAC, "DMAC"); + AppendIf(menuDev, ID_MONITOR_MFP, "MFP"); + AppendIf(menuDev, ID_MONITOR_FDC, "FDC"); + AppendIf(menuDev, ID_MONITOR_SCC, "SCC"); + AppendIf(menuDev, ID_MONITOR_SIO, "SIO"); + AppendIf(menuDev, ID_MONITOR_PIO, "PIO0/PIO1"); + AppendIf(menuDev, ID_MONITOR_KEYBOARD, _("Keyboard/Mouse")); + AppendIf(menuDev, ID_MONITOR_LANCE, "Lance"); + AppendIf(menuDev, ID_MONITOR_LCD, "LCD"); + AppendIf(menuDev, ID_MONITOR_SYSCLK, _("System Clock")); + AppendIf(menuDev, ID_MONITOR_CRTC, "CRTC"); + 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_MONITOR_ROMCONS, _("ROM Console (provisional)")); + AppendIf(menuDev, ID_SUBWIN_ROM, "ROM"); + menuMonitor->AppendSubMenu(menuDev, _("De&vice")); wxMenu *menuHost = new wxMenu(); AppendIf(menuHost, ID_MONITOR_WXHOSTINFO, _("Host &Information")); @@ -374,6 +425,13 @@ WXMainFrame::WXMainFrame(wxWindow *paren AppendIf(menuHost, ID_MONITOR_HOSTCOM, _("Host &Serial Port")); menuMonitor->AppendSubMenu(menuHost, _("&Host")); + wxMenu *menuDebug = new wxMenu(); + AppendIf(menuDebug, ID_SUBWIN_LOG, _("&Log")); + AppendIf(menuDebug, ID_MONITOR_BREAKPOINT, _("&Breakpoint")); + menuDebug->AppendSeparator(); + AppendIf(menuDebug, ID_SUBWIN_LOGSETTING, _("Log Level &Setting")); + menuMonitor->AppendSubMenu(menuDebug, _("&Debug")); + menubar->Append(menuMonitor, _("&Monitor")); // メニュー > ヘルプ @@ -400,7 +458,10 @@ WXMainFrame::WXMainFrame(wxWindow *paren title += "(LUNA-I)"; break; case VMType::LUNA88K: - title += "(LUNA88K)"; + title += "(LUNA-88K)"; + break; + case VMType::NEWS: + title += "(NWS-1750)"; break; default: break; @@ -417,37 +478,29 @@ WXMainFrame::WXMainFrame(wxWindow *paren // 念のため事象が分かりやすいように 10秒くらいにしておく。 wxUpdateUIEvent::SetUpdateInterval(10000); - // WXStatusPanel コンストラクタが gMainView を参照するので - // gMainView のほうを先に作成すること。 - gMainView = new WXMainView(this); - gStatusPanel = new WXStatusPanel(this); + // WXStatusPanel コンストラクタが mainview を参照するので + // mainview のほうを先に作成すること。 + mainview = new WXMainView(this); + statuspanel = new WXStatusPanel(this); // SHOW イベントを最初にも一度起こしたいため // ステータスパネルを一旦非表示にする (これで SHOW(false) イベントが飛ぶ) - gStatusPanel->Hide(); + statuspanel->Hide(); const ConfigItem& item_show = gConfig->Find("show-statuspanel"); if (item_show.AsInt() != 0) { // 必要なら改めて表示 (これで SHOW(true) イベントが飛ぶ) - gStatusPanel->Show(); + statuspanel->Show(); } // Sizer 使わず自前でレイアウトする。 SetAutoLayout(true); - // モニタの更新頻度は初期値だけ設定から読んで、あとはここで管理する。 - // 不正値ならデフォルトの 15Hz にしておくか - const ConfigItem& item_rate = gConfig->Find("monitor-rate"); - monitor_rate = item_rate.AsInt(); - if (monitor_rate < 1 || monitor_rate > 60) { - monitor_rate = 15; - } - // Activate イベントは、このトップレベルウィンドウにウィンドウフォーカスが // 来た or 外れたことを示すので、wxFrame (というかたぶん wxTopLevelWindow) // を継承している WXMainFrameに飛んでくるのだが、処理の都合上 WXMainView で // 扱いたいので、そちらに回す。 Connect(wxEVT_ACTIVATE, wxActivateEventHandler(WXMainView::OnActivate), - NULL, gMainView); + NULL, mainview); // ウィンドウ表示後に続きの処理をするための単発アイドルイベント。 Connect(wxEVT_IDLE, wxIdleEventHandler(WXMainFrame::OnIdle)); @@ -459,7 +512,7 @@ WXMainFrame::WXMainFrame(wxWindow *paren wxCommandEventHandler(WXMainFrame::OnInsertFailed)); WXUIMessage::Connect(UIMessage::FDD_MEDIA_FAILED, this, wxCommandEventHandler(WXMainFrame::OnInsertFailed)); - if (gMPU680x0) { + if (gMainApp.Has(VMCap::M68K)) { WXUIMessage::Connect(UIMessage::HALT, this, wxCommandEventHandler(WXMainFrame::OnHaltNotify)); } @@ -467,14 +520,14 @@ WXMainFrame::WXMainFrame(wxWindow *paren WXMainFrame::~WXMainFrame() { - WXUIMessage::Disconnect(UIMessage::APPEXIT, + WXUIMessage::Disconnect(UIMessage::APPEXIT, this, wxCommandEventHandler(WXMainFrame::OnExit)); - WXUIMessage::Disconnect(UIMessage::SCSI_MEDIA_FAILED, + WXUIMessage::Disconnect(UIMessage::SCSI_MEDIA_FAILED, this, wxCommandEventHandler(WXMainFrame::OnInsertFailed)); - WXUIMessage::Disconnect(UIMessage::FDD_MEDIA_FAILED, + WXUIMessage::Disconnect(UIMessage::FDD_MEDIA_FAILED, this, wxCommandEventHandler(WXMainFrame::OnInsertFailed)); - if (gMPU680x0) { - WXUIMessage::Disconnect(UIMessage::HALT, + if (gMainApp.Has(VMCap::M68K)) { + WXUIMessage::Disconnect(UIMessage::HALT, this, wxCommandEventHandler(WXMainFrame::OnHaltNotify)); } } @@ -487,12 +540,9 @@ WXMainFrame::CreateRemovableMenu(wxMenu bool added = false; // FD - if (gFDC) { - const std::vector& fdd_list = gFDC->GetFDD(); - for (const auto fdd : fdd_list) { - int unit = fdd->GetUnitNo(); - fdd_array[unit] = fdd; - + for (int unit = 0; unit < FDCDevice::MAX_DRIVE; unit++) { + fdd_array[unit] = gMainApp.FindObject(OBJ_FDD(unit)); + if (fdd_array[unit]) { menu = CreateFDMenu(unit); std::string label = string_format("FD%d", unit); menuDevice->AppendSubMenu(menu, label); @@ -501,15 +551,18 @@ WXMainFrame::CreateRemovableMenu(wxMenu } // CD, MO - for (int id = 0; id < 8; id++) { - scsidev[id] = gSPC->GetTarget(id); - if (scsidev[id]) { - menu = CreateSCSIRemovableMenu(id); - if (menu) { - std::string label = string_format("%s (ID%d)", - SCSI::GetDevTypeName(scsidev[id]->GetDevType()), id); - menuDevice->AppendSubMenu(menu, label); - added = true; + auto spc = gMainApp.FindObject(OBJ_SPC); + if (spc) { + for (int id = 0; id < 8; id++) { + scsidev[id] = spc->GetTarget(id); + if (scsidev[id]) { + menu = CreateSCSIRemovableMenu(id); + if (menu) { + std::string label = string_format("%s (ID%d)", + SCSI::GetDevTypeName(scsidev[id]->GetDevType()), id); + menuDevice->AppendSubMenu(menu, label); + added = true; + } } } } @@ -567,7 +620,7 @@ WXMainFrame::CreateSCSIRemovableMenu(uin bool WXMainFrame::Init() { - if (!gMainView->Init()) { + if (!mainview->Init()) { return false; } @@ -581,11 +634,11 @@ WXMainFrame::Layout() return false; } - wxSize msize = gStatusPanel->GetMinClientSize(); - wxSize ssize = gStatusPanel->GetClientSize(); - wxSize vsize = gMainView->GetClientSize(); + wxSize msize = statuspanel->GetMinClientSize(); + wxSize ssize = statuspanel->GetClientSize(); + wxSize vsize = mainview->GetClientSize(); - if (gStatusPanel->IsShown()) { + if (statuspanel->IsShown()) { ssize.y = msize.y; } else { ssize.y = 0; @@ -596,9 +649,9 @@ WXMainFrame::Layout() size.y = ssize.y + vsize.y; if (ssize.y != 0) { - gStatusPanel->SetSize(0, 0, size.x, ssize.y); + statuspanel->SetSize(0, 0, size.x, ssize.y); } - gMainView->SetSize(0, ssize.y, size.x, vsize.y); + mainview->SetSize(0, ssize.y, size.x, vsize.y); SetClientSize(size); return true; @@ -637,7 +690,7 @@ WXMainFrame::OnIdle(wxIdleEvent& ev) } // 電源投入 - gPower->PowerButton(); + power->PowerButton(); // 一度処理したら、このイベントを外す Disconnect(wxEVT_IDLE, wxIdleEventHandler(WXMainFrame::OnIdle)); @@ -648,9 +701,9 @@ void WXMainFrame::OnClose(wxCloseEvent& event) { // ステータスパネルの更新を停止 - gStatusPanel->Close(); + statuspanel->Close(); // メインビューの描画を停止 - gMainView->Close(); + mainview->Close(); // サブウィンドウを全部閉じる for (int i = 0; i < ID_SUBWIN_MAX; i++) { @@ -670,7 +723,7 @@ WXMainFrame::OnClose(wxCloseEvent& event void WXMainFrame::OnRestartVM(wxCommandEvent& event) { - gPower->MakeRestart(); + power->MakeRestart(); } // メニューの「終了」イベント @@ -687,10 +740,10 @@ WXMainFrame::OnFullSpeed(wxCommandEvent& { if (event.IsChecked()) { // チェックが入ったので、高速モードにする - gSync->RequestFullSpeed(true); + syncer->RequestFullSpeed(true); } else { // チェックが消えたので、通常モードにする - gSync->RequestFullSpeed(false); + syncer->RequestFullSpeed(false); } } @@ -698,7 +751,7 @@ WXMainFrame::OnFullSpeed(wxCommandEvent& void WXMainFrame::OnFullSpeedUI(wxUpdateUIEvent& event) { - bool is_fullspeed = gSync->GetFullSpeed(); + bool is_fullspeed = syncer->GetFullSpeed(); event.Check(is_fullspeed); } @@ -708,14 +761,14 @@ WXMainFrame::OnMenuInput(wxCommandEvent& { bool char_mode = (event.GetId() == ID_INPUT_CHAR); - gMainView->SetCharInputMode(char_mode); + mainview->SetCharInputMode(char_mode); } // メニューの「設定 > 入力 > *」の共通 UI void WXMainFrame::OnMenuInputUI(wxUpdateUIEvent& event) { - bool char_mode = gMainView->GetCharInputMode(); + bool char_mode = mainview->GetCharInputMode(); if (char_mode) { event.Check(event.GetId() == ID_INPUT_CHAR); @@ -724,26 +777,51 @@ WXMainFrame::OnMenuInputUI(wxUpdateUIEve } } +// スケール一覧 +/*static*/ std::vector +WXMainFrame::view_scales { + 0.50, + 0.75, + 1.00, + 1.50, + 2.00, +}; + +#define contains(v, key) (std::find(v.begin(), v.end(), key) != v.end()) + +// 「表示 > スケール」のメニュー項目作成に必要な view_scale を作成し、 +// ユーザ指定値があれば view_scales[] 内でのインデックスを返す。 +// ユーザ指定値がなければ -1 を返す。 +int +WXMainFrame::CreateMainviewScaleTable() +{ + // 設定ファイル mainview-scale で指定されたサイズを追加。 + // 値はこの時点で WXMainView::screen_scale にセットされている。 + double user_scale = WXMainView::screen_scale; + if (contains(view_scales, user_scale)) { + // プリセットと同じなら、このままでよい。 + } else { + // 追加したらソート。 + view_scales.push_back(user_scale); + std::sort(view_scales.begin(), view_scales.end()); + + // ユーザ指定の値が何番目かを返す。指定されてなければ -1。 + for (int i = 0, end = view_scales.size(); i < end; i++) { + if (view_scales[i] == user_scale) { + return i; + } + } + // 見付からないことはないはずだが + } + return -1; +} + // メニューの「表示 > スケール > *」の共通イベント void WXMainFrame::OnMenuScale(wxCommandEvent& event) { - double scale; - - switch (event.GetId()) { - default: - case ID_SCALE_1_00: - scale = 1.0; - break; - case ID_SCALE_0_75: - scale = 0.75; - break; - case ID_SCALE_0_50: - scale = 0.5; - break; - } - gMainView->DoResize(scale); - + int idx = event.GetId() - ID_SCALE_START; + mainview->DoResize(view_scales[idx]); // 再レイアウト Layout(); } @@ -752,15 +830,10 @@ WXMainFrame::OnMenuScale(wxCommandEvent& void WXMainFrame::OnMenuScaleUI(wxUpdateUIEvent& event) { - double current_scale = gMainView->GetScale(); + int idx = event.GetId() - ID_SCALE_START; + double current_scale = mainview->GetScale(); - if (current_scale == 1.0) { - event.Check(event.GetId() == ID_SCALE_1_00); - } else if (current_scale == 0.75) { - event.Check(event.GetId() == ID_SCALE_0_75); - } else if (current_scale == 0.5) { - event.Check(event.GetId() == ID_SCALE_0_50); - } + event.Check(view_scales[idx] == current_scale); } // メニューの「表示 > フォントサイズ > *」の共通イベント @@ -770,7 +843,7 @@ WXMainFrame::OnMenuFontSize(wxCommandEve FontId fontid; assertmsg( - ID_FONTSIZE_12 <= event.GetId() && event.GetId() <= ID_FONTSIZE_16, + ID_FONTSIZE_12 <= event.GetId() && event.GetId() <= ID_FONTSIZE_24, "event.GetId()=%d", event.GetId()); switch (event.GetId()) { case ID_FONTSIZE_12: @@ -779,6 +852,9 @@ WXMainFrame::OnMenuFontSize(wxCommandEve case ID_FONTSIZE_16: fontid = FontId::_8x16; break; + case ID_FONTSIZE_24: + fontid = FontId::_12x24; + break; default: __unreachable(); break; @@ -796,7 +872,7 @@ WXMainFrame::OnMenuFontSize(wxCommandEve } } // メインウィンドウはここで直接ステータスパネルに通知 - gStatusPanel->FontChanged(); + statuspanel->FontChanged(); // ステータスパネルの大きさが変わるので再レイアウト Layout(); @@ -813,21 +889,49 @@ WXMainFrame::OnMenuFontSizeUI(wxUpdateUI event.Check(current_size == event_size); } -// 更新頻度 ID -> 数値 (メニューのテキスト、ID と一致させること) -/*static*/ const int -WXMainFrame::IDtoMonRate[] = { - 20, // ID_MONRATE_20 - 5, // ID_MONRATE_5 - 1, // ID_MONRATE_1 +// 更新頻度一覧 +/*static*/ std::vector +WXMainFrame::monrates { + 20, + 5, + 1, }; +// 「表示 > モニタ更新頻度」のメニュー項目作成に必要な monrates を作成し、 +// ユーザ指定値があれば monrates[] 内のインデックスを返す。 +// ユーザ指定値がなければ -1 を返す。 +int +WXMainFrame::CreateMonRateTable() +{ + // 設定ファイル monitor-rate で指定された値を追加。 + // 値はこの時点で monitor_rate にセットされている。 + int user_rate = monitor_rate; + if (contains(monrates, user_rate)) { + // プリセットと同じなら、このままでよい。 + } else { + // 追加したら降順にソート。 + monrates.push_back(user_rate); + 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; +} + // メニューの「表示 > モニタ更新頻度 > *」の共通イベント void WXMainFrame::OnMenuMonRate(wxCommandEvent& event) { - int id = event.GetId(); - assert(ID_MONRATE_START < id && id < ID_MONRATE_END); - monitor_rate = IDtoMonRate[id - (ID_MONRATE_START + 1)]; + int idx = event.GetId() - ID_MONRATE_START; + monitor_rate = monrates[idx]; // アクティブなサブウィンドウのテキストパネル全員に通知 for (int i = 0; i < ID_SUBWIN_MAX; i++) { @@ -847,11 +951,9 @@ WXMainFrame::OnMenuMonRate(wxCommandEven void WXMainFrame::OnMenuMonRateUI(wxUpdateUIEvent& event) { - int id = event.GetId(); - assert(ID_MONRATE_START < id && id < ID_MONRATE_END); - int event_rate = IDtoMonRate[id - (ID_MONRATE_START + 1)]; + int idx = event.GetId() - ID_MONRATE_START; - event.Check(monitor_rate == event_rate); + event.Check(monrates[idx] == monitor_rate); } // メニューの「表示 > ステータスパネルを表示」 @@ -861,7 +963,7 @@ WXMainFrame::OnShowStatusPanel(wxCommand // enable ならチェックを付けようとして呼ばれた bool enable = event.IsChecked(); - gStatusPanel->Show(enable); + statuspanel->Show(enable); // 再レイアウト Layout(); @@ -871,7 +973,7 @@ WXMainFrame::OnShowStatusPanel(wxCommand void WXMainFrame::OnShowStatusPanelUI(wxUpdateUIEvent& event) { - event.Check(gStatusPanel->IsShown()); + event.Check(statuspanel->IsShown()); } // メニューの「デバイス > FD > 挿入」 @@ -979,7 +1081,7 @@ WXMainFrame::OnCDInsert(wxCommandEvent& wildcard = "MO images (*.img;*.mos)|*.img;*.mos;*.IMG;*.MOS"; break; default: - __unreachable(); + break; } wildcard += "|All files (*.*)|*.*"; @@ -1070,14 +1172,17 @@ WXMainFrame::OnMouseMode(wxCommandEvent& } // マウスモードを設定 - gMainView->SetMouseMode(enable); + wxCommandEvent newev(NONO_EVT_MOUSEMODE, GetId()); + newev.SetEventObject(this); + newev.SetInt(enable); + ::wxPostEvent(mainview, newev); } // メニューの「デバイス > マウスモード」UI void WXMainFrame::OnMouseModeUI(wxUpdateUIEvent& event) { - event.Check(gMainView->GetMouseMode()); + event.Check(mainview->GetMouseMode()); } // メニューの「デバイス > Push Power Button」イベント @@ -1087,21 +1192,21 @@ WXMainFrame::OnPowerButton(wxCommandEven // LUNA はモーメンタリ動作、X68030 はオルタネート動作のスイッチ。 // この違いは VM 側で吸収するのでここはボタンを押したという動作だけ // 通知する。 - gPower->PowerButton(); + power->PowerButton(); } // メニューの「デバイス > Push Power Button」UI void WXMainFrame::OnPowerButtonUI(wxUpdateUIEvent& event) { - if (gMainApp.Has(VMCap::LUNA)) { + if (gMainApp.Has(VMCap::X68030)) { + // X68030 の電源ボタンはオルタネート動作なので、 + // チェックで状態を表す。 + event.Check(power->IsPowerPressed()); + } else { // LUNA の電源ボタンはモーメンタリ動作で、電源オフ->オンの機能しかなく // さらに今の所電源オフ状態はないので、実質無効。 event.Enable(false); - } else { - // X68030 の電源ボタンはオルタネート動作なので、 - // チェックで状態を表す。 - event.Check(gPower->IsPowerPressed()); } } @@ -1110,14 +1215,15 @@ WXMainFrame::OnPowerButtonUI(wxUpdateUIE void WXMainFrame::OnResetButton(wxCommandEvent& event) { - gPower->MakeResetHard(); + power->MakeResetHard(); } // メニューの「デバイス > Push ABORT(Interrupt) Button」イベント void WXMainFrame::OnNMIButton(wxCommandEvent& event) { - gNMI->PressNMI(); + auto nmi = GetNMIDevice(); + nmi->PressNMI(); } // メニューの「デバイス > Operation > Keyboard Connect」イベント @@ -1128,14 +1234,14 @@ WXMainFrame::OnKeyboardConnect(wxCommand bool enable = event.IsChecked(); // キーボード接続を設定 - gKeyboard->Connect(enable); + keyboard->Connect(enable); } // メニューの「デバイス > Operation > Keyboard Connect」UI void WXMainFrame::OnKeyboardConnectUI(wxUpdateUIEvent& event) { - event.Check(gKeyboard->IsConnected()); + event.Check(keyboard->IsConnected()); } // メニューのウィンドウ ID 共通イベント @@ -1187,6 +1293,10 @@ WXMainFrame::DoWindow(int id, bool enabl SetMonitor(id, _("Breakpoint")); break; + case ID_MONITOR_BT45x: + SetMonitor(id, "Bt454/458"); + break; + case ID_MONITOR_CMMU0: case ID_MONITOR_CMMU1: case ID_MONITOR_CMMU2: @@ -1212,11 +1322,11 @@ WXMainFrame::DoWindow(int id, bool enabl break; case ID_MONITOR_DMAC: - SetMonitor(id, "DMAC"); + SetMonitor(id, "DMAC (HD63450)"); break; case ID_MONITOR_FDC: - SetMonitor(id, "FDC"); + SetMonitor(id, "FDC (uPD72065B)"); break; case ID_MONITOR_HOSTCOM: @@ -1228,15 +1338,24 @@ WXMainFrame::DoWindow(int id, bool enabl break; case ID_MONITOR_INTERRUPT: - SetMonitor(id, _("Interrupt")); + { + wxString name; + if (gMainApp.Has(VMCap::M88K)) { + // 実際はほぼシステムコントローラなのでややこしい。 + name = "MPU " + _("Interrupt"); + } else { + name = MPUName() + " " + _("Interrupt"); + } + SetMonitor(id, name); break; + } case ID_MONITOR_KEYBOARD: SetMonitor(id, _("Keyboard/Mouse")); break; case ID_MONITOR_LANCE: - SetMonitor(id, "LANCE"); + SetMonitor(id, "LANCE (AM7990)"); break; case ID_MONITOR_LCD: @@ -1248,31 +1367,39 @@ WXMainFrame::DoWindow(int id, bool enabl break; case ID_MONITOR_MEMDUMP0 ... - (ID_MONITOR_MEMDUMP0 + MAX_MEMDUMP_MONITOR - 1): + ID_MONITOR_MEMDUMP(MAX_MEMDUMP_MONITOR - 1): + case ID_MONITOR_XPMEMDUMP0 ... + ID_MONITOR_XPMEMDUMP(MAX_XPMEMDUMP_MONITOR - 1): { - int n = id - ID_MONITOR_MEMDUMP0; - windows[id].reset(new WXMemdumpWindow(this, n)); + windows[id].reset(new WXMemdumpWindow(this, id)); break; } case ID_MONITOR_MFP: - SetMonitor(id, "MFP"); + SetMonitor(id, "MFP (MC68901)"); break; case ID_MONITOR_MK48T02: - SetMonitor(id, "MK48T02"); + SetMonitor(id, "RTC (MK48T02)"); break; case ID_MONITOR_MPUATC: - SetMonitor(id, _("MPU (ATC)")); + SetMonitor(id, "MC68030 ATC"); break; case ID_MONITOR_MPUREG: - SetMonitor(id, _("MPU (Register)")); + { + wxString name = MPUName() + " " + _("Register"); + SetMonitor(id, name); + break; + } + + case ID_MONITOR_ROMCONS: + SetMonitor(id, _("ROM Console (provisional)")); break; - case ID_MONITOR_PIO0: - SetMonitor(id, "PIO"); + case ID_MONITOR_PIO: + SetMonitor(id, "PIO0/PIO1"); break; case ID_MONITOR_RENDERER: @@ -1280,11 +1407,11 @@ WXMainFrame::DoWindow(int id, bool enabl break; case ID_MONITOR_RTC: - SetMonitor(id, "RTC"); + SetMonitor(id, "RTC (RP5C15)"); break; case ID_MONITOR_SCC: - SetMonitor(id, "SCC"); + SetMonitor(id, "SCC (Z8530)"); break; case ID_MONITOR_SCHEDULER: @@ -1296,11 +1423,11 @@ WXMainFrame::DoWindow(int id, bool enabl break; case ID_MONITOR_SIO: - SetMonitor(id, "SIO"); + SetMonitor(id, "SIO (uPD7201)"); break; case ID_MONITOR_SPC: - SetMonitor(id, "SPC"); + SetMonitor(id, "SPC (MB89352)"); break; case ID_MONITOR_SYSCLK: @@ -1311,15 +1438,33 @@ WXMainFrame::DoWindow(int id, bool enabl SetMonitor(id, _("Host Information")); break; + case ID_MONITOR_XPREG: + SetMonitor(id, "HD647180 " + _("Register")); + break; + + case ID_MONITOR_XPINTR: + SetMonitor(id, "HD647180 " + _("Interrupt")); + break; + + case ID_MONITOR_XPIO: + SetMonitor(id, _("HD647180 Internal Devices")); + break; + case ID_SUBWIN_BRHIST: - windows[id].reset(new WXScrollMonitorWindow(this, - _("Branch History"), gMonitorManager->Get(id))); + { + wxString name = MPUName() + " " + _("Branch History"); + windows[id].reset(new WXScrollMonitorWindow(this, name, + gMonitorManager->Get(id))); break; + } case ID_SUBWIN_EXHIST: - windows[id].reset(new WXScrollMonitorWindow(this, - _("Exception History"), gMonitorManager->Get(id))); + { + wxString name = MPUName() + " " + _("Exception History"); + windows[id].reset(new WXScrollMonitorWindow(this, name, + gMonitorManager->Get(id))); break; + } case ID_SUBWIN_CACHE0: case ID_SUBWIN_CACHE1: @@ -1343,6 +1488,10 @@ WXMainFrame::DoWindow(int id, bool enabl break; } + case ID_SUBWIN_DIPSW: + windows[id].reset(new WXDipswWindow(this)); + break; + case ID_SUBWIN_LCDPANEL: windows[id].reset(new WXLCDWindow(this)); break; @@ -1367,6 +1516,20 @@ WXMainFrame::DoWindow(int id, bool enabl 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)); + break; + } + case ID_SUBWIN_ROM: windows[id].reset(new WXROMWindow(this)); break; @@ -1376,12 +1539,31 @@ WXMainFrame::DoWindow(int id, bool enabl break; case ID_SUBWIN_VECTOR: - windows[id].reset(new WXScrollMonitorWindow(this, - _("Vector Table"), gMonitorManager->Get(id))); + { + wxString name = MPUName() + " " + _("Vector Table"); + windows[id].reset(new WXScrollMonitorWindow(this, name, + gMonitorManager->Get(id))); break; + } + + case ID_SUBWIN_XPBRHIST: + { + wxString name = "HD647180 " + _("Branch History"); + windows[id].reset(new WXScrollMonitorWindow(this, name, + gMonitorManager->Get(id))); + break; + } + + case ID_SUBWIN_XPEXHIST: + { + wxString name = "HD647180 " + _("Exception History"); + windows[id].reset(new WXScrollMonitorWindow(this, name, + gMonitorManager->Get(id))); + break; + } default: - assert(false); + PANIC("'%s' not listed", Monitor::GetIdText(id)); } windows[id]->Show(); } else { @@ -1400,11 +1582,24 @@ WXMainFrame::OnWindowUI(wxUpdateUIEvent& // ウィンドウが存在していればチェックを表示 event.Check((bool)windows[id]); - if (IS_MONITOR_MEMDUMP(id)) { + if (IS_MONITOR_MEMDUMP(id) || IS_MONITOR_XPMEMDUMP(id)) { // メニューに現在のアドレスを載せる - int n = id - ID_MONITOR_MEMDUMP0; - event.SetText(string_format("%d: $%08x", n, - WXMemdumpWindow::GetStickyAddr(id))); + // (ウィンドウの生存期間外にも呼ばれることに注意) + auto mon = gMonitorManager->Get(id); + auto *memdump = dynamic_cast(mon.obj); + assert(memdump); + uint32 addr = memdump->GetAddr(); + + int n; + wxString text = _("Memory Dump"); + if (IS_MONITOR_XPMEMDUMP(id)) { + n = id - ID_MONITOR_XPMEMDUMP0; + text += string_format(" &%d: $%05x", n, addr); + } else { + n = id - ID_MONITOR_MEMDUMP0; + text += string_format(" &%d: $%08x", n, addr); + } + event.SetText(text); } } @@ -1489,6 +1684,18 @@ WXMainFrame::DeleteWindow(wxWindow *win) } } +// メイン MPU 名を返す。メニューとタイトルによく出てくるので。 +// 88xx0 とか 88200 は別処理。 +wxString +WXMainFrame::MPUName() const +{ + if (gMainApp.Has(VMCap::M88K)) { + return "MC88100"; + } else { + return "MC68030"; + } +} + // m680x0 ダブルバスフォールト処理 void WXMainFrame::OnHaltNotify(wxCommandEvent& event) @@ -1500,3 +1707,6 @@ WXMainFrame::OnHaltNotify(wxCommandEvent // 起動時にオープンするサブウィンドウ (-M オプション) /*static*/ std::array WXMainFrame::subwindow_start; + +// モニタの更新頻度 +/*static*/ int WXMainFrame::monitor_rate;