DebuggerForm.cpp 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431
  1. #include "DebuggerForm.h"
  2. #include "BitMapViewer.h"
  3. #include "DockableWidgetArea.h"
  4. #include "DockableWidget.h"
  5. #include "DisasmViewer.h"
  6. #include "MainMemoryViewer.h"
  7. #include "CPURegsViewer.h"
  8. #include "FlagsViewer.h"
  9. #include "StackViewer.h"
  10. #include "SlotViewer.h"
  11. #include "CommClient.h"
  12. #include "ConnectDialog.h"
  13. #include "SymbolManager.h"
  14. #include "PreferencesDialog.h"
  15. #include "BreakpointDialog.h"
  16. #include "GotoDialog.h"
  17. #include "DebuggableViewer.h"
  18. #include "VDPRegViewer.h"
  19. #include "VDPStatusRegViewer.h"
  20. #include "VDPCommandRegViewer.h"
  21. #include "Settings.h"
  22. #include "Version.h"
  23. #include <QAction>
  24. #include <QMessageBox>
  25. #include <QMenu>
  26. #include <QMenuBar>
  27. #include <QToolBar>
  28. #include <QStatusBar>
  29. #include <QWidget>
  30. #include <QLabel>
  31. #include <QVBoxLayout>
  32. #include <QHBoxLayout>
  33. #include <QString>
  34. #include <QStringList>
  35. #include <QSplitter>
  36. #include <QPixmap>
  37. #include <QFileDialog>
  38. #include <QCloseEvent>
  39. #include <iostream>
  40. class QueryPauseHandler : public SimpleCommand
  41. {
  42. public:
  43. QueryPauseHandler(DebuggerForm& form_)
  44. : SimpleCommand("set pause")
  45. , form(form_)
  46. {
  47. }
  48. virtual void replyOk(const QString& message)
  49. {
  50. // old openmsx versions returned 'on','false'
  51. // new versions return 'true','false'
  52. // so check for 'false'
  53. bool checked = message.trimmed() != "false";
  54. form.systemPauseAction->setChecked(checked);
  55. delete this;
  56. }
  57. private:
  58. DebuggerForm& form;
  59. };
  60. class QueryBreakedHandler : public SimpleCommand
  61. {
  62. public:
  63. QueryBreakedHandler(DebuggerForm& form_)
  64. : SimpleCommand("debug breaked")
  65. , form(form_)
  66. {
  67. }
  68. virtual void replyOk(const QString& message)
  69. {
  70. form.finalizeConnection(message.trimmed() == "1");
  71. delete this;
  72. }
  73. private:
  74. DebuggerForm& form;
  75. };
  76. class ListBreakPointsHandler : public SimpleCommand
  77. {
  78. public:
  79. ListBreakPointsHandler(DebuggerForm& form_, bool merge_ = false)
  80. : SimpleCommand("debug_list_all_breaks")
  81. , form(form_), merge(merge_)
  82. {
  83. }
  84. virtual void replyOk(const QString& message)
  85. {
  86. if (merge) {
  87. QString bps = form.session.breakpoints().mergeBreakpoints(message);
  88. if (!bps.isEmpty()) {
  89. form.comm.sendCommand(new SimpleCommand(bps));
  90. form.comm.sendCommand(new ListBreakPointsHandler(form, false));
  91. } else {
  92. form.disasmView->update();
  93. form.session.sessionModified();
  94. form.updateWindowTitle();
  95. }
  96. } else {
  97. form.session.breakpoints().setBreakpoints(message);
  98. form.disasmView->update();
  99. form.session.sessionModified();
  100. form.updateWindowTitle();
  101. }
  102. delete this;
  103. }
  104. private:
  105. DebuggerForm& form;
  106. bool merge;
  107. };
  108. class CPURegRequest : public ReadDebugBlockCommand
  109. {
  110. public:
  111. CPURegRequest(DebuggerForm& form_)
  112. : ReadDebugBlockCommand("{CPU regs}", 0, 28, buf)
  113. , form(form_)
  114. {
  115. }
  116. virtual void replyOk(const QString& message)
  117. {
  118. copyData(message);
  119. form.regsView->setData(buf);
  120. delete this;
  121. }
  122. private:
  123. DebuggerForm& form;
  124. unsigned char buf[28];
  125. };
  126. class ListDebuggablesHandler : public SimpleCommand
  127. {
  128. public:
  129. ListDebuggablesHandler(DebuggerForm& form_)
  130. : SimpleCommand("debug list")
  131. , form(form_)
  132. {
  133. }
  134. virtual void replyOk(const QString& message)
  135. {
  136. form.setDebuggables(message);
  137. delete this;
  138. }
  139. private:
  140. DebuggerForm& form;
  141. };
  142. class DebuggableSizeHandler : public SimpleCommand
  143. {
  144. public:
  145. DebuggableSizeHandler(const QString& debuggable_, DebuggerForm& form_)
  146. : SimpleCommand(QString("debug size %1").arg(debuggable_))
  147. , debuggable(debuggable_)
  148. , form(form_)
  149. {
  150. }
  151. virtual void replyOk(const QString& message)
  152. {
  153. form.setDebuggableSize(debuggable, message.toInt());
  154. delete this;
  155. }
  156. private:
  157. QString debuggable;
  158. DebuggerForm& form;
  159. };
  160. DebuggerForm::DebuggerForm(QWidget* parent)
  161. : QMainWindow(parent)
  162. , comm(CommClient::instance())
  163. {
  164. VDPRegView = NULL;
  165. VDPStatusRegView = NULL;
  166. VDPCommandRegView = NULL;
  167. createActions();
  168. createMenus();
  169. createToolbars();
  170. createStatusbar();
  171. createForm();
  172. recentFiles = Settings::get().value("MainWindow/RecentFiles").toStringList();
  173. updateRecentFiles();
  174. connect(&session.symbolTable(), SIGNAL(symbolFileChanged()), this, SLOT(symbolFileChanged()));
  175. }
  176. void DebuggerForm::createActions()
  177. {
  178. fileNewSessionAction = new QAction(tr("&New Session"), this);
  179. fileNewSessionAction->setStatusTip(tr("Clear the current session."));
  180. fileOpenSessionAction = new QAction(tr("&Open Session ..."), this);
  181. fileOpenSessionAction->setShortcut(tr("Ctrl+O"));
  182. fileOpenSessionAction->setStatusTip(tr("Clear the current session."));
  183. fileSaveSessionAction = new QAction(tr("&Save Session"), this);
  184. fileSaveSessionAction->setShortcut(tr("Ctrl+S"));
  185. fileSaveSessionAction->setStatusTip(tr("Save the the current debug session"));
  186. fileSaveSessionAsAction = new QAction(tr("Save Session &As"), this);
  187. fileSaveSessionAsAction->setStatusTip(tr("Save the debug session in a selected file"));
  188. fileQuitAction = new QAction(tr("&Quit"), this);
  189. fileQuitAction->setShortcut(tr("Ctrl+Q"));
  190. fileQuitAction->setStatusTip(tr("Quit the openMSX debugger"));
  191. for (int i = 0; i < MaxRecentFiles; ++i) {
  192. recentFileActions[i] = new QAction(this);
  193. connect(recentFileActions[i], SIGNAL(triggered()), this, SLOT(fileRecentOpen()));
  194. }
  195. systemConnectAction = new QAction(tr("&Connect"), this);
  196. systemConnectAction->setShortcut(tr("Ctrl+C"));
  197. systemConnectAction->setStatusTip(tr("Connect to openMSX"));
  198. systemConnectAction->setIcon(QIcon(":/icons/connect.png"));
  199. systemDisconnectAction = new QAction(tr("&Disconnect"), this);
  200. systemDisconnectAction->setShortcut(tr(""));
  201. systemDisconnectAction->setStatusTip(tr("Disconnect from openMSX"));
  202. systemDisconnectAction->setIcon(QIcon(":/icons/disconnect.png"));
  203. systemDisconnectAction->setEnabled(false);
  204. systemPauseAction = new QAction(tr("&Pause emulator"), this);
  205. systemPauseAction->setShortcut(Qt::Key_Pause);
  206. systemPauseAction->setStatusTip(tr("Pause the emulation"));
  207. systemPauseAction->setIcon(QIcon(":/icons/pause.png"));
  208. systemPauseAction->setCheckable(true);
  209. systemPauseAction->setEnabled(false);
  210. systemRebootAction = new QAction(tr("&Reboot emulator"), this);
  211. systemRebootAction->setStatusTip(tr("Reboot the emulation and start if needed"));
  212. systemRebootAction->setEnabled(false);
  213. systemSymbolManagerAction = new QAction(tr("&Symbol manager ..."), this);
  214. systemSymbolManagerAction->setStatusTip(tr("Start the symbol manager"));
  215. systemSymbolManagerAction->setIcon(QIcon(":/icons/symmanager.png"));
  216. systemPreferencesAction = new QAction(tr("Pre&ferences ..."), this);
  217. systemPreferencesAction->setStatusTip(tr("Set the global debugger preferences"));
  218. searchGotoAction = new QAction(tr("&Goto ..."), this);
  219. searchGotoAction->setStatusTip(tr("Jump to a specific address or label in the disassembly view"));
  220. searchGotoAction->setShortcut(tr("Ctrl+G"));
  221. viewRegistersAction = new QAction(tr("CPU &Registers"), this);
  222. viewRegistersAction->setStatusTip(tr("Toggle the cpu registers display"));
  223. viewRegistersAction->setCheckable(true);
  224. viewFlagsAction = new QAction(tr("CPU &Flags"), this);
  225. viewFlagsAction->setStatusTip(tr("Toggle the cpu flags display"));
  226. viewFlagsAction->setCheckable(true);
  227. viewStackAction = new QAction(tr("Stack"), this);
  228. viewStackAction->setStatusTip(tr("Toggle the stack display"));
  229. viewStackAction->setCheckable(true);
  230. viewSlotsAction = new QAction(tr("Slots"), this);
  231. viewSlotsAction->setStatusTip(tr("Toggle the slots display"));
  232. viewSlotsAction->setCheckable(true);
  233. viewMemoryAction = new QAction(tr("Memory"), this);
  234. viewMemoryAction->setStatusTip(tr("Toggle the main memory display"));
  235. viewMemoryAction->setCheckable(true);
  236. viewDebuggableViewerAction = new QAction(tr("Add debuggable viewer"), this);
  237. viewDebuggableViewerAction->setStatusTip(tr("Add a hex viewer for debuggables"));
  238. viewVDPStatusRegsAction = new QAction(tr("Status Registers"), this);
  239. viewVDPStatusRegsAction->setStatusTip(tr("The VDP status registers interpreted"));
  240. viewVDPStatusRegsAction->setCheckable(true);
  241. viewVDPCommandRegsAction = new QAction(tr("Command Registers"), this);
  242. viewVDPCommandRegsAction->setStatusTip(tr("Interact with the VDP command registers"));
  243. viewVDPCommandRegsAction->setCheckable(true);
  244. viewVDPRegsAction = new QAction(tr("Registers"), this);
  245. viewVDPRegsAction->setStatusTip(tr("Interact with the VDP registers"));
  246. viewVDPRegsAction->setCheckable(true);
  247. viewBitMappedAction = new QAction(tr("Bitmapped VRAM"), this);
  248. viewBitMappedAction->setStatusTip(tr("Decode VRAM as screen 5/6/7/8 image"));
  249. //viewBitMappedAction->setCheckable(true);
  250. executeBreakAction = new QAction(tr("Break"), this);
  251. executeBreakAction->setShortcut(tr("CRTL+B"));
  252. executeBreakAction->setStatusTip(tr("Halt the execution and enter debug mode"));
  253. executeBreakAction->setIcon(QIcon(":/icons/break.png"));
  254. executeBreakAction->setEnabled(false);
  255. executeRunAction = new QAction(tr("Run"), this);
  256. executeRunAction->setShortcut(tr("F9"));
  257. executeRunAction->setStatusTip(tr("Leave debug mode and resume execution"));
  258. executeRunAction->setIcon(QIcon(":/icons/run.png"));
  259. executeRunAction->setEnabled(false);
  260. executeStepAction = new QAction(tr("Step into"), this);
  261. executeStepAction->setShortcut(tr("F7"));
  262. executeStepAction->setStatusTip(tr("Execute a single instruction"));
  263. executeStepAction->setIcon(QIcon(":/icons/stepinto.png"));
  264. executeStepAction->setEnabled(false);
  265. executeStepOverAction = new QAction(tr("Step over"), this);
  266. executeStepOverAction->setShortcut(tr("F8"));
  267. executeStepOverAction->setStatusTip(tr("Execute the next instruction including any called subroutines"));
  268. executeStepOverAction->setIcon(QIcon(":/icons/stepover.png"));
  269. executeStepOverAction->setEnabled(false);
  270. executeStepOutAction = new QAction(tr("Step out"), this);
  271. executeStepOutAction->setShortcut(tr("F11"));
  272. executeStepOutAction->setStatusTip(tr("Resume execution until the current routine has finished"));
  273. executeStepOutAction->setIcon(QIcon(":/icons/stepout.png"));
  274. executeStepOutAction->setEnabled(false);
  275. executeStepBackAction = new QAction(tr("Step back"), this);
  276. executeStepBackAction->setShortcut(tr("F12"));
  277. executeStepBackAction->setStatusTip(tr("Reverse the last instruction"));
  278. executeStepBackAction->setIcon(QIcon(":/icons/stepback.png"));
  279. executeStepBackAction->setEnabled(false);
  280. executeRunToAction = new QAction(tr("Run to"), this);
  281. executeRunToAction->setShortcut(tr("F4"));
  282. executeRunToAction->setStatusTip(tr("Resume execution until the selected line is reached"));
  283. executeRunToAction->setIcon(QIcon(":/icons/runto.png"));
  284. executeRunToAction->setEnabled(false);
  285. breakpointToggleAction = new QAction(tr("Toggle"), this);
  286. breakpointToggleAction->setShortcut(tr("F5"));
  287. breakpointToggleAction->setStatusTip(tr("Toggle breakpoint on/off at cursor"));
  288. breakpointToggleAction->setIcon(QIcon(":/icons/break.png"));
  289. breakpointToggleAction->setEnabled(false);
  290. breakpointAddAction = new QAction(tr("Add ..."), this);
  291. breakpointAddAction->setShortcut(tr("CTRL+B"));
  292. breakpointAddAction->setStatusTip(tr("Add a breakpoint at a location"));
  293. breakpointAddAction->setEnabled(false);
  294. helpAboutAction = new QAction(tr("&About"), this);
  295. executeRunToAction->setStatusTip(tr("Show the appliction information"));
  296. connect(fileNewSessionAction, SIGNAL(triggered()), this, SLOT(fileNewSession()));
  297. connect(fileOpenSessionAction, SIGNAL(triggered()), this, SLOT(fileOpenSession()));
  298. connect(fileSaveSessionAction, SIGNAL(triggered()), this, SLOT(fileSaveSession()));
  299. connect(fileSaveSessionAsAction, SIGNAL(triggered()), this, SLOT(fileSaveSessionAs()));
  300. connect(fileQuitAction, SIGNAL(triggered()), this, SLOT(close()));
  301. connect(systemConnectAction, SIGNAL(triggered()), this, SLOT(systemConnect()));
  302. connect(systemDisconnectAction, SIGNAL(triggered()), this, SLOT(systemDisconnect()));
  303. connect(systemPauseAction, SIGNAL(triggered()), this, SLOT(systemPause()));
  304. connect(systemRebootAction, SIGNAL(triggered()), this, SLOT(systemReboot()));
  305. connect(systemSymbolManagerAction, SIGNAL(triggered()), this, SLOT(systemSymbolManager()));
  306. connect(systemPreferencesAction, SIGNAL(triggered()), this, SLOT(systemPreferences()));
  307. connect(searchGotoAction, SIGNAL(triggered()), this, SLOT(searchGoto()));
  308. connect(viewRegistersAction, SIGNAL(triggered()), this, SLOT(toggleRegisterDisplay()));
  309. connect(viewFlagsAction, SIGNAL(triggered()), this, SLOT(toggleFlagsDisplay()));
  310. connect(viewStackAction, SIGNAL(triggered()), this, SLOT(toggleStackDisplay()));
  311. connect(viewSlotsAction, SIGNAL(triggered()), this, SLOT(toggleSlotsDisplay()));
  312. connect(viewMemoryAction, SIGNAL(triggered()), this, SLOT(toggleMemoryDisplay()));
  313. connect(viewDebuggableViewerAction, SIGNAL(triggered()), this, SLOT(addDebuggableViewer()));
  314. connect(viewBitMappedAction, SIGNAL(triggered()), this, SLOT(toggleBitMappedDisplay()));
  315. connect(viewVDPRegsAction, SIGNAL(triggered()), this, SLOT(toggleVDPRegsDisplay()));
  316. connect(viewVDPCommandRegsAction, SIGNAL(triggered()), this, SLOT(toggleVDPCommandRegsDisplay()));
  317. connect(viewVDPStatusRegsAction, SIGNAL(triggered()), this, SLOT(toggleVDPStatusRegsDisplay()));
  318. connect(executeBreakAction, SIGNAL(triggered()), this, SLOT(executeBreak()));
  319. connect(executeRunAction, SIGNAL(triggered()), this, SLOT(executeRun()));
  320. connect(executeStepAction, SIGNAL(triggered()), this, SLOT(executeStep()));
  321. connect(executeStepOverAction, SIGNAL(triggered()), this, SLOT(executeStepOver()));
  322. connect(executeRunToAction, SIGNAL(triggered()), this, SLOT(executeRunTo()));
  323. connect(executeStepOutAction, SIGNAL(triggered()), this, SLOT(executeStepOut()));
  324. connect(executeStepBackAction, SIGNAL(triggered()), this, SLOT(executeStepBack()));
  325. connect(breakpointToggleAction, SIGNAL(triggered()), this, SLOT(breakpointToggle()));
  326. connect(breakpointAddAction, SIGNAL(triggered()), this, SLOT(breakpointAdd()));
  327. connect(helpAboutAction, SIGNAL(triggered()), this, SLOT(showAbout()));
  328. }
  329. void DebuggerForm::createMenus()
  330. {
  331. // create file menu
  332. fileMenu = menuBar()->addMenu(tr("&File"));
  333. fileMenu->addAction(fileNewSessionAction);
  334. fileMenu->addAction(fileOpenSessionAction);
  335. fileMenu->addAction(fileSaveSessionAction);
  336. fileMenu->addAction(fileSaveSessionAsAction);
  337. recentFileSeparator = fileMenu->addSeparator();
  338. for (int i = 0; i < MaxRecentFiles; ++i)
  339. fileMenu->addAction(recentFileActions[i]);
  340. fileMenu->addSeparator();
  341. fileMenu->addAction(fileQuitAction);
  342. // create system menu
  343. systemMenu = menuBar()->addMenu(tr("&System"));
  344. systemMenu->addAction(systemConnectAction);
  345. systemMenu->addAction(systemDisconnectAction);
  346. systemMenu->addSeparator();
  347. systemMenu->addAction(systemPauseAction);
  348. systemMenu->addSeparator();
  349. systemMenu->addAction(systemRebootAction);
  350. systemMenu->addSeparator();
  351. systemMenu->addAction(systemSymbolManagerAction);
  352. systemMenu->addSeparator();
  353. systemMenu->addAction(systemPreferencesAction);
  354. // create system menu
  355. searchMenu = menuBar()->addMenu(tr("Se&arch"));
  356. searchMenu->addAction(searchGotoAction);
  357. // create view menu
  358. viewMenu = menuBar()->addMenu(tr("&View"));
  359. viewMenu->addAction(viewRegistersAction);
  360. viewMenu->addAction(viewFlagsAction);
  361. viewMenu->addAction(viewStackAction);
  362. viewMenu->addAction(viewSlotsAction);
  363. viewMenu->addAction(viewMemoryAction);
  364. viewVDPDialogsMenu = viewMenu->addMenu("VDP");
  365. viewMenu->addSeparator();
  366. viewMenu->addAction(viewDebuggableViewerAction);
  367. connect(viewMenu, SIGNAL(aboutToShow()), this, SLOT(updateViewMenu()));
  368. // create VDP dialogs menu
  369. viewVDPDialogsMenu->addAction(viewVDPRegsAction);
  370. viewVDPDialogsMenu->addAction(viewVDPCommandRegsAction);
  371. viewVDPDialogsMenu->addAction(viewVDPStatusRegsAction);
  372. viewVDPDialogsMenu->addAction(viewBitMappedAction);
  373. connect(viewVDPDialogsMenu, SIGNAL(aboutToShow()), this, SLOT(updateVDPViewMenu()));
  374. // create execute menu
  375. executeMenu = menuBar()->addMenu(tr("&Execute"));
  376. executeMenu->addAction(executeBreakAction);
  377. executeMenu->addAction(executeRunAction);
  378. executeMenu->addSeparator();
  379. executeMenu->addAction(executeStepAction);
  380. executeMenu->addAction(executeStepOverAction);
  381. executeMenu->addAction(executeStepOutAction);
  382. executeMenu->addAction(executeStepBackAction);
  383. executeMenu->addAction(executeRunToAction);
  384. // create breakpoint menu
  385. breakpointMenu = menuBar()->addMenu(tr("&Breakpoint"));
  386. breakpointMenu->addAction(breakpointToggleAction);
  387. breakpointMenu->addAction(breakpointAddAction);
  388. // create help menu
  389. helpMenu = menuBar()->addMenu(tr("&Help"));
  390. helpMenu->addAction(helpAboutAction);
  391. }
  392. void DebuggerForm::createToolbars()
  393. {
  394. // create debug toolbar
  395. systemToolbar = addToolBar(tr("System"));
  396. systemToolbar->addAction(systemConnectAction);
  397. systemToolbar->addAction(systemDisconnectAction);
  398. systemToolbar->addSeparator();
  399. systemToolbar->addAction(systemPauseAction);
  400. systemToolbar->addSeparator();
  401. systemToolbar->addAction(systemSymbolManagerAction);
  402. // create debug toolbar
  403. executeToolbar = addToolBar(tr("Execution"));
  404. executeToolbar->addAction(executeBreakAction);
  405. executeToolbar->addAction(executeRunAction);
  406. executeToolbar->addSeparator();
  407. executeToolbar->addAction(executeStepAction);
  408. executeToolbar->addAction(executeStepOverAction);
  409. executeToolbar->addAction(executeStepOutAction);
  410. executeToolbar->addAction(executeStepBackAction);
  411. executeToolbar->addAction(executeRunToAction);
  412. }
  413. void DebuggerForm::createStatusbar()
  414. {
  415. // create the statusbar
  416. statusBar()->showMessage("No emulation running.");
  417. }
  418. void DebuggerForm::createForm()
  419. {
  420. updateWindowTitle();
  421. mainArea = new DockableWidgetArea();
  422. dockMan.addDockArea(mainArea);
  423. setCentralWidget(mainArea);
  424. // Create main widgets and append them to the list first
  425. DockableWidget* dw = new DockableWidget(dockMan);
  426. // create the disasm viewer widget
  427. disasmView = new DisasmViewer();
  428. dw->setWidget(disasmView);
  429. dw->setTitle(tr("Code view"));
  430. dw->setId("CODEVIEW");
  431. dw->setFloating(false);
  432. dw->setDestroyable(false);
  433. dw->setMovable(false);
  434. dw->setClosable(false);
  435. connect(this, SIGNAL(settingsChanged()),
  436. disasmView, SLOT(settingsChanged()));
  437. connect(this, SIGNAL(symbolsChanged()),
  438. disasmView, SLOT(symbolsChanged()));
  439. connect(dw, SIGNAL(visibilityChanged(DockableWidget*)),
  440. this, SLOT(dockWidgetVisibilityChanged(DockableWidget*)));
  441. // create the memory view widget
  442. mainMemoryView = new MainMemoryViewer();
  443. dw = new DockableWidget(dockMan);
  444. dw->setWidget(mainMemoryView);
  445. dw->setTitle(tr("Main memory"));
  446. dw->setId("MEMORY");
  447. dw->setFloating(false);
  448. dw->setDestroyable(false);
  449. dw->setMovable(true);
  450. dw->setClosable(true);
  451. connect(dw, SIGNAL(visibilityChanged(DockableWidget*)),
  452. this, SLOT(dockWidgetVisibilityChanged(DockableWidget*)));
  453. mainMemoryView->setSymbolTable(&session.symbolTable());
  454. // create register viewer
  455. regsView = new CPURegsViewer();
  456. dw = new DockableWidget(dockMan);
  457. dw->setWidget(regsView);
  458. dw->setTitle(tr("CPU registers"));
  459. dw->setId("REGISTERS");
  460. dw->setFloating(false);
  461. dw->setDestroyable(false);
  462. dw->setMovable(true);
  463. dw->setClosable(true);
  464. connect(dw, SIGNAL(visibilityChanged(DockableWidget*)),
  465. this, SLOT(dockWidgetVisibilityChanged(DockableWidget*)));
  466. // Hook up the register viewer with the MainMemory viewer
  467. connect(regsView, SIGNAL(registerChanged(int,int)),
  468. mainMemoryView, SLOT(registerChanged(int,int)));
  469. mainMemoryView->setRegsView(regsView);
  470. // create flags viewer
  471. flagsView = new FlagsViewer();
  472. dw = new DockableWidget(dockMan);
  473. dw->setWidget(flagsView);
  474. dw->setTitle(tr("Flags"));
  475. dw->setId("FLAGS");
  476. dw->setFloating(false);
  477. dw->setDestroyable(false);
  478. dw->setMovable(true);
  479. dw->setClosable(true);
  480. connect(dw, SIGNAL(visibilityChanged(DockableWidget*)),
  481. this, SLOT(dockWidgetVisibilityChanged(DockableWidget*)));
  482. // create stack viewer
  483. stackView = new StackViewer();
  484. dw = new DockableWidget(dockMan);
  485. dw->setWidget(stackView);
  486. dw->setTitle(tr("Stack"));
  487. dw->setId("STACK");
  488. dw->setFloating(false);
  489. dw->setDestroyable(false);
  490. dw->setMovable(true);
  491. dw->setClosable(true);
  492. connect(dw, SIGNAL(visibilityChanged(DockableWidget*)),
  493. this, SLOT(dockWidgetVisibilityChanged(DockableWidget*)));
  494. // create slot viewer
  495. slotView = new SlotViewer();
  496. dw = new DockableWidget(dockMan);
  497. dw->setWidget(slotView);
  498. dw->setTitle(tr("Memory layout"));
  499. dw->setId("SLOTS");
  500. dw->setFloating(false);
  501. dw->setDestroyable(false);
  502. dw->setMovable(true);
  503. dw->setClosable(true);
  504. connect(dw, SIGNAL(visibilityChanged(DockableWidget*)),
  505. this, SLOT(dockWidgetVisibilityChanged(DockableWidget*)));
  506. // restore layout
  507. restoreGeometry(Settings::get().value("Layout/WindowGeometry", saveGeometry()).toByteArray());
  508. QStringList list = Settings::get().value("Layout/WidgetLayout").toStringList();
  509. // defaults needed?
  510. if (list.empty() || !list.at(0).startsWith("CODEVIEW ")) {
  511. list.clear();
  512. list.append("CODEVIEW D V R 0 -1 -1");
  513. list.append("REGISTERS D V R 0 -1 -1");
  514. list.append("FLAGS D V R 0 -1 -1");
  515. int regW = dockMan.findDockableWidget("REGISTERS")->sizeHint().width();
  516. int regH = dockMan.findDockableWidget("REGISTERS")->sizeHint().height();
  517. int codeW = dockMan.findDockableWidget("CODEVIEW")->sizeHint().width();
  518. int codeH = dockMan.findDockableWidget("CODEVIEW")->sizeHint().height();
  519. int flagW = dockMan.findDockableWidget("FLAGS")->sizeHint().width();
  520. int slotW = dockMan.findDockableWidget("SLOTS")->sizeHint().width();
  521. list.append(QString("SLOTS D V R 0 -1 %1").arg(regH));
  522. list.append(QString("STACK D V R 0 -1 %1").arg(codeH));
  523. list.append(QString("MEMORY D V B %1 %2 %3").arg(codeW)
  524. .arg(regW + flagW + slotW)
  525. .arg(codeH - regH));
  526. }
  527. // add widgets
  528. for (int i = 0; i < list.size(); ++i) {
  529. QStringList s = list.at(i).split(" ", QString::SkipEmptyParts);
  530. // get widget
  531. if ((dw = dockMan.findDockableWidget(s.at(0)))) {
  532. if (s.at(1) == "D") {
  533. // dock widget
  534. DockableWidgetLayout::DockSide side;
  535. if (s.at(3) == "T") {
  536. side = DockableWidgetLayout::TOP;
  537. } else if (s.at(3) == "L") {
  538. side = DockableWidgetLayout::LEFT;
  539. } else if (s.at(3) == "R") {
  540. side = DockableWidgetLayout::RIGHT;
  541. } else {
  542. side = DockableWidgetLayout::BOTTOM;
  543. }
  544. dockMan.insertWidget(dw, 0, side, s.at(4).toInt(),
  545. s.at(5).toInt(), s.at(6).toInt());
  546. if (s.at(2) == "H") dw->hide();
  547. } else if (s.at(1) == "F") {
  548. // float widget
  549. dw->setFloating(true, s.at(2) == "V");
  550. dw->resize(s.at(5).toInt(), s.at(6).toInt());
  551. dw->move (s.at(3).toInt(), s.at(4).toInt());
  552. }
  553. }
  554. }
  555. // disable all widgets
  556. connectionClosed();
  557. connect(regsView, SIGNAL(pcChanged(quint16)),
  558. disasmView, SLOT(setProgramCounter(quint16)));
  559. connect(regsView, SIGNAL(flagsChanged(quint8)),
  560. flagsView, SLOT(setFlags(quint8)));
  561. connect(regsView, SIGNAL(spChanged(quint16)),
  562. stackView, SLOT(setStackPointer(quint16)));
  563. connect(disasmView, SIGNAL(toggleBreakpoint(int)),
  564. SLOT(breakpointToggle(int)));
  565. connect(&comm, SIGNAL(connectionReady()),
  566. SLOT(initConnection()));
  567. connect(&comm, SIGNAL(updateParsed(const QString&, const QString&, const QString&)),
  568. SLOT(handleUpdate(const QString&, const QString&, const QString&)));
  569. connect(&comm, SIGNAL(connectionTerminated()),
  570. SLOT(connectionClosed()));
  571. // init main memory
  572. // added four bytes as runover buffer for dasm
  573. // otherwise dasm would need to check the buffer end continously.
  574. session.breakpoints().setMemoryLayout(&memLayout);
  575. mainMemory = new unsigned char[65536 + 4];
  576. memset(mainMemory, 0, 65536 + 4);
  577. disasmView->setMemory(mainMemory);
  578. disasmView->setBreakpoints(&session.breakpoints());
  579. disasmView->setMemoryLayout(&memLayout);
  580. disasmView->setSymbolTable(&session.symbolTable());
  581. mainMemoryView->setDebuggable("memory", 65536);
  582. stackView->setData(mainMemory, 65536);
  583. slotView->setMemoryLayout(&memLayout);
  584. }
  585. DebuggerForm::~DebuggerForm()
  586. {
  587. delete[] mainMemory;
  588. delete mainArea;
  589. }
  590. void DebuggerForm::closeEvent(QCloseEvent* e)
  591. {
  592. // handle unsaved session
  593. fileNewSession();
  594. // cancel if session is still modified
  595. if (session.isModified()) {
  596. e->ignore();
  597. return;
  598. }
  599. // store layout
  600. Settings::get().setValue("Layout/WindowGeometry", saveGeometry());
  601. QStringList layoutList;
  602. // fill layout list with docked widgets
  603. dockMan.getConfig(0, layoutList);
  604. // append floating widgets
  605. for (QList<DockableWidget*>::const_iterator it = dockMan.managedWidgets().begin();
  606. it != dockMan.managedWidgets().end(); ++it) {
  607. if ((*it)->isFloating()) {
  608. QString s("%1 F %2 %3 %4 %5 %6");
  609. s = s.arg((*it)->id());
  610. if ((*it)->isHidden()) {
  611. s = s.arg("H");
  612. } else {
  613. s = s.arg("V");
  614. }
  615. s = s.arg((*it)->x()).arg((*it)->y())
  616. .arg((*it)->width()).arg((*it)->height());
  617. layoutList.append(s);
  618. }
  619. }
  620. Settings::get().setValue("Layout/WidgetLayout", layoutList);
  621. QMainWindow::closeEvent(e);
  622. }
  623. void DebuggerForm::updateRecentFiles()
  624. {
  625. // store settings
  626. Settings::get().setValue("MainWindow/RecentFiles", recentFiles);
  627. // update actions
  628. for(int i = 0; i < MaxRecentFiles; i++)
  629. if(i < recentFiles.size()) {
  630. recentFileActions[i]->setVisible(true);
  631. QString text = QString("&%1 %2").arg(i + 1).arg(QFileInfo(recentFiles[i]).fileName());
  632. recentFileActions[i]->setText(text);
  633. recentFileActions[i]->setData(recentFiles[i]);
  634. } else
  635. recentFileActions[i]->setVisible(false);
  636. // show separator only when recent files exist
  637. recentFileSeparator->setVisible(recentFiles.size());
  638. }
  639. void DebuggerForm::addRecentFile(const QString& file)
  640. {
  641. recentFiles.removeAll(file);
  642. recentFiles.prepend(file);
  643. while (recentFiles.size() > MaxRecentFiles)
  644. recentFiles.removeLast();
  645. updateRecentFiles();
  646. }
  647. void DebuggerForm::removeRecentFile(const QString& file)
  648. {
  649. recentFiles.removeAll(file);
  650. updateRecentFiles();
  651. }
  652. void DebuggerForm::updateWindowTitle()
  653. {
  654. QString title = "openMSX debugger [%1%2]";
  655. if (session.existsAsFile()) {
  656. title = title.arg(session.filename());
  657. } else {
  658. title = title.arg("unnamed session");
  659. }
  660. if (session.isModified()) {
  661. title = title.arg('*');
  662. } else {
  663. title = title.arg("");
  664. }
  665. setWindowTitle(title);
  666. }
  667. void DebuggerForm::initConnection()
  668. {
  669. systemConnectAction->setEnabled(false);
  670. systemDisconnectAction->setEnabled(true);
  671. comm.sendCommand(new QueryPauseHandler(*this));
  672. comm.sendCommand(new QueryBreakedHandler(*this));
  673. comm.sendCommand(new SimpleCommand("openmsx_update enable status"));
  674. comm.sendCommand(new ListDebuggablesHandler(*this));
  675. // define 'debug_bin2hex' proc for internal use
  676. comm.sendCommand(new SimpleCommand(
  677. "proc debug_bin2hex { input } {\n"
  678. " set result \"\"\n"
  679. " foreach i [split $input {}] {\n"
  680. " append result [format %02X [scan $i %c]] \"\"\n"
  681. " }\n"
  682. " return $result\n"
  683. "}\n"));
  684. // define 'debug_hex2bin' proc for internal use
  685. comm.sendCommand(new SimpleCommand(
  686. "proc debug_hex2bin { input } {\n"
  687. " set result \"\"\n"
  688. " foreach {h l} [split $input {}] {\n"
  689. " append result [binary format H2 $h$l] \"\"\n"
  690. " }\n"
  691. " return $result\n"
  692. "}\n"));
  693. // define 'debug_memmapper' proc for internal use
  694. comm.sendCommand(new SimpleCommand(
  695. "proc debug_memmapper { } {\n"
  696. " set result \"\"\n"
  697. " for { set page 0 } { $page &lt; 4 } { incr page } {\n"
  698. " set tmp [get_selected_slot $page]\n"
  699. " append result [lindex $tmp 0] [lindex $tmp 1] \"\\n\"\n"
  700. " if { [lsearch [debug list] \"MapperIO\"] != -1} {\n"
  701. " append result [debug read \"MapperIO\" $page] \"\\n\"\n"
  702. " } else {\n"
  703. " append result \"0\\n\"\n"
  704. " }\n"
  705. " }\n"
  706. " for { set ps 0 } { $ps &lt; 4 } { incr ps } {\n"
  707. " if [machine_info issubslotted $ps] {\n"
  708. " append result \"1\\n\"\n"
  709. " for { set ss 0 } { $ss &lt; 4 } { incr ss } {\n"
  710. " append result [get_mapper_size $ps $ss] \"\\n\"\n"
  711. " }\n"
  712. " } else {\n"
  713. " append result \"0\\n\"\n"
  714. " append result [get_mapper_size $ps 0] \"\\n\"\n"
  715. " }\n"
  716. " }\n"
  717. " for { set page 0 } { $page &lt; 4 } { incr page } {\n"
  718. " set tmp [get_selected_slot $page]\n"
  719. " set ss [lindex $tmp 1]\n"
  720. " if { $ss == \"X\" } { set ss 0 }\n"
  721. " set device_list [machine_info slot [lindex $tmp 0] $ss $page]\n"
  722. " set name \"[lindex $device_list 0] romblocks\"\n"
  723. " if { [lsearch [debug list] $name] != -1} {\n"
  724. " append result \"[debug read $name [expr {$page * 0x4000}] ]\\n\"\n"
  725. " append result \"[debug read $name [expr {$page * 0x4000 + 0x2000}] ]\\n\"\n"
  726. " } else {\n"
  727. " append result \"X\\nX\\n\"\n"
  728. " }\n"
  729. " }\n"
  730. " return $result\n"
  731. "}\n"));
  732. // define 'debug_list_all_breaks' proc for internal use
  733. comm.sendCommand(new SimpleCommand(
  734. "proc debug_list_all_breaks { } {\n"
  735. " set result [debug list_bp]\n"
  736. " append result [debug list_watchpoints]\n"
  737. " append result [debug list_conditions]\n"
  738. " return $result\n"
  739. "}\n"));
  740. }
  741. void DebuggerForm::connectionClosed()
  742. {
  743. systemPauseAction->setEnabled(false);
  744. systemRebootAction->setEnabled(false);
  745. executeBreakAction->setEnabled(false);
  746. executeRunAction->setEnabled(false);
  747. executeStepAction->setEnabled(false);
  748. executeStepOverAction->setEnabled(false);
  749. executeStepOutAction->setEnabled(false);
  750. executeStepBackAction->setEnabled(false);
  751. executeRunToAction->setEnabled(false);
  752. systemDisconnectAction->setEnabled(false);
  753. systemConnectAction->setEnabled(true);
  754. breakpointToggleAction->setEnabled(false);
  755. breakpointAddAction->setEnabled(false);
  756. for (QList<DockableWidget*>::const_iterator it = dockMan.managedWidgets().begin();
  757. it != dockMan.managedWidgets().end(); ++it) {
  758. (*it)->widget()->setEnabled(false);
  759. }
  760. }
  761. void DebuggerForm::finalizeConnection(bool halted)
  762. {
  763. systemPauseAction->setEnabled(true);
  764. systemRebootAction->setEnabled(true);
  765. breakpointToggleAction->setEnabled(true);
  766. breakpointAddAction->setEnabled(true);
  767. // merge breakpoints on connect
  768. mergeBreakpoints = true;
  769. if (halted) {
  770. setBreakMode();
  771. breakOccured();
  772. } else {
  773. setRunMode();
  774. updateData();
  775. }
  776. for (QList<DockableWidget*>::const_iterator it = dockMan.managedWidgets().begin();
  777. it != dockMan.managedWidgets().end(); ++it) {
  778. (*it)->widget()->setEnabled(true);
  779. }
  780. }
  781. void DebuggerForm::handleUpdate(const QString& type, const QString& name,
  782. const QString& message)
  783. {
  784. if (type == "status") {
  785. if (name == "cpu") {
  786. if (message == "suspended") {
  787. breakOccured();
  788. } else {
  789. setRunMode();
  790. }
  791. } else if (name == "paused") {
  792. pauseStatusChanged(message == "true");
  793. }
  794. }
  795. }
  796. void DebuggerForm::pauseStatusChanged(bool isPaused)
  797. {
  798. systemPauseAction->setChecked(isPaused);
  799. }
  800. void DebuggerForm::breakOccured()
  801. {
  802. setBreakMode();
  803. updateData();
  804. }
  805. void DebuggerForm::updateData()
  806. {
  807. comm.sendCommand(new ListBreakPointsHandler(*this, mergeBreakpoints));
  808. // only merge the first time after connect
  809. mergeBreakpoints = false;
  810. // refresh memory viewer
  811. mainMemoryView->refresh();
  812. // update registers
  813. // note that a register update is processed, a signal is sent to other
  814. // widgets as well. Any dependent updates shoud be called before this one.
  815. CPURegRequest* regs = new CPURegRequest(*this);
  816. comm.sendCommand(regs);
  817. // refresh slot viewer
  818. slotView->refresh();
  819. emit emulationChanged();
  820. }
  821. void DebuggerForm::setBreakMode()
  822. {
  823. executeBreakAction->setEnabled(false);
  824. executeRunAction->setEnabled(true);
  825. executeStepAction->setEnabled(true);
  826. executeStepOverAction->setEnabled(true);
  827. executeStepOutAction->setEnabled(true);
  828. executeStepBackAction->setEnabled(true);
  829. executeRunToAction->setEnabled(true);
  830. }
  831. void DebuggerForm::setRunMode()
  832. {
  833. executeBreakAction->setEnabled(true);
  834. executeRunAction->setEnabled(false);
  835. executeStepAction->setEnabled(false);
  836. executeStepOverAction->setEnabled(false);
  837. executeStepOutAction->setEnabled(false);
  838. executeStepBackAction->setEnabled(false);
  839. executeRunToAction->setEnabled(false);
  840. }
  841. void DebuggerForm::fileNewSession()
  842. {
  843. if (session.isModified()) {
  844. // save current session?
  845. int choice = QMessageBox::warning(this, tr("Unsaved session"),
  846. tr("The current session has unsaved data.\n"
  847. "Do you want to save your changes?"),
  848. QMessageBox::Save | QMessageBox::Discard |
  849. QMessageBox::Cancel, QMessageBox::Save);
  850. if (choice == QMessageBox::Cancel) {
  851. return;
  852. } else if (choice == QMessageBox::Save) {
  853. fileSaveSession();
  854. // skip new if session is still modified (save was cancelled)
  855. if (session.isModified()) return;
  856. }
  857. }
  858. session.clear();
  859. updateWindowTitle();
  860. }
  861. void DebuggerForm::fileOpenSession()
  862. {
  863. QString fileName = QFileDialog::getOpenFileName(
  864. this, tr("Open debug session"),
  865. QDir::currentPath(), tr("Debug Session Files (*.omds)"));
  866. if (!fileName.isEmpty())
  867. openSession(fileName);
  868. }
  869. void DebuggerForm::openSession(const QString& file)
  870. {
  871. fileNewSession();
  872. session.open(file);
  873. if (systemDisconnectAction->isEnabled()) {
  874. // active connection, merge loaded breakpoints
  875. comm.sendCommand(new ListBreakPointsHandler(*this, true));
  876. }
  877. // update recent
  878. if(session.existsAsFile())
  879. addRecentFile(file);
  880. else
  881. removeRecentFile(file);
  882. updateWindowTitle();
  883. }
  884. void DebuggerForm::fileSaveSession()
  885. {
  886. if (session.existsAsFile()) {
  887. session.save();
  888. } else {
  889. fileSaveSessionAs();
  890. }
  891. updateWindowTitle();
  892. }
  893. void DebuggerForm::fileSaveSessionAs()
  894. {
  895. QFileDialog d(this, tr("Save debug session"));
  896. d.setNameFilter(tr("Debug Session Files (*.omds)"));
  897. d.setDefaultSuffix("omds");
  898. d.setDirectory(QDir::currentPath());
  899. d.setAcceptMode(QFileDialog::AcceptSave);
  900. d.setFileMode(QFileDialog::AnyFile);
  901. if (d.exec()) {
  902. session.saveAs(d.selectedFiles().at(0));
  903. // update recent
  904. if(session.existsAsFile())
  905. addRecentFile(session.filename());
  906. }
  907. updateWindowTitle();
  908. }
  909. void DebuggerForm::fileRecentOpen()
  910. {
  911. QAction *action = qobject_cast<QAction *>(sender());
  912. if (action)
  913. openSession(action->data().toString());
  914. }
  915. void DebuggerForm::systemConnect()
  916. {
  917. if (OpenMSXConnection* connection = ConnectDialog::getConnection(this)) {
  918. comm.connectToOpenMSX(connection);
  919. }
  920. }
  921. void DebuggerForm::systemDisconnect()
  922. {
  923. comm.closeConnection();
  924. }
  925. void DebuggerForm::systemPause()
  926. {
  927. comm.sendCommand(new SimpleCommand(QString("set pause ") +
  928. (systemPauseAction->isChecked() ? "true" : "false")));
  929. }
  930. void DebuggerForm::systemReboot()
  931. {
  932. if (systemPauseAction->isChecked()) {
  933. systemPauseAction->trigger();
  934. }
  935. if (executeRunAction->isEnabled()) {
  936. executeRun();
  937. }
  938. comm.sendCommand(new SimpleCommand("reset"));
  939. }
  940. void DebuggerForm::systemSymbolManager()
  941. {
  942. SymbolManager symManager(session.symbolTable(), this);
  943. connect(&symManager, SIGNAL(symbolTableChanged()),
  944. &session, SLOT(sessionModified()));
  945. symManager.exec();
  946. emit symbolsChanged();
  947. updateWindowTitle();
  948. }
  949. void DebuggerForm::systemPreferences()
  950. {
  951. PreferencesDialog prefs(this);
  952. prefs.exec();
  953. emit settingsChanged();
  954. }
  955. void DebuggerForm::searchGoto()
  956. {
  957. GotoDialog gtd(memLayout, &session, this);
  958. if (gtd.exec()) {
  959. int addr = gtd.address();
  960. if ( addr >= 0) {
  961. disasmView->setCursorAddress(addr, 0, DisasmViewer::MiddleAlways);
  962. }
  963. }
  964. }
  965. void DebuggerForm::executeBreak()
  966. {
  967. comm.sendCommand(new SimpleCommand("debug break"));
  968. }
  969. void DebuggerForm::executeRun()
  970. {
  971. comm.sendCommand(new SimpleCommand("debug cont"));
  972. setRunMode();
  973. }
  974. void DebuggerForm::executeStep()
  975. {
  976. comm.sendCommand(new SimpleCommand("debug step"));
  977. setRunMode();
  978. }
  979. void DebuggerForm::executeStepOver()
  980. {
  981. SimpleCommand *sc = new SimpleCommand("step_over");
  982. connect(sc, SIGNAL(replyStatusOk(bool)), this, SLOT(handleCommandReplyStatus(bool)));
  983. comm.sendCommand(sc);
  984. setRunMode();
  985. }
  986. void DebuggerForm::executeRunTo()
  987. {
  988. comm.sendCommand(new SimpleCommand(
  989. "run_to " + QString::number(disasmView->cursorAddress())));
  990. setRunMode();
  991. }
  992. void DebuggerForm::executeStepOut()
  993. {
  994. comm.sendCommand(new SimpleCommand("step_out"));
  995. setRunMode();
  996. }
  997. void DebuggerForm::executeStepBack()
  998. {
  999. SimpleCommand *sc = new SimpleCommand("step_back");
  1000. connect(sc, SIGNAL(replyStatusOk(bool)), this, SLOT(handleCommandReplyStatus(bool)));
  1001. comm.sendCommand(sc);
  1002. setRunMode();
  1003. }
  1004. void DebuggerForm::handleCommandReplyStatus(bool status)
  1005. {
  1006. if(status) {
  1007. finalizeConnection(true);
  1008. }
  1009. }
  1010. void DebuggerForm::breakpointToggle(int addr)
  1011. {
  1012. // toggle address unspecified, use cursor address
  1013. if (addr < 0) addr = disasmView->cursorAddress();
  1014. QString cmd, id;
  1015. if (session.breakpoints().isBreakpoint(addr, &id)) {
  1016. cmd = Breakpoints::createRemoveCommand(id);
  1017. } else {
  1018. // get slot
  1019. int ps, ss, seg;
  1020. addressSlot(addr, ps, ss, seg);
  1021. // create command
  1022. cmd = Breakpoints::createSetCommand(Breakpoints::BREAKPOINT, addr, ps, ss, seg);
  1023. }
  1024. comm.sendCommand(new SimpleCommand(cmd));
  1025. comm.sendCommand(new ListBreakPointsHandler(*this));
  1026. }
  1027. void DebuggerForm::breakpointAdd()
  1028. {
  1029. BreakpointDialog bpd(memLayout, &session, this);
  1030. int addr = disasmView->cursorAddress();
  1031. int ps, ss, seg;
  1032. addressSlot(addr, ps, ss, seg);
  1033. bpd.setData(Breakpoints::BREAKPOINT, addr, ps, ss, seg);
  1034. if (bpd.exec()) {
  1035. if (bpd.address() >= 0) {
  1036. QString cmd = Breakpoints::createSetCommand(
  1037. bpd.type(), bpd.address(), bpd.slot(), bpd.subslot(), bpd.segment(),
  1038. bpd.addressEndRange(), bpd.condition() );
  1039. comm.sendCommand(new SimpleCommand(cmd));
  1040. comm.sendCommand(new ListBreakPointsHandler(*this));
  1041. }
  1042. }
  1043. }
  1044. void DebuggerForm::showAbout()
  1045. {
  1046. QMessageBox::about(
  1047. this, "openMSX Debugger", QString(Version::full().c_str()));
  1048. }
  1049. void DebuggerForm::toggleRegisterDisplay()
  1050. {
  1051. toggleView(qobject_cast<DockableWidget*>(regsView->parentWidget()));
  1052. }
  1053. void DebuggerForm::toggleFlagsDisplay()
  1054. {
  1055. toggleView(qobject_cast<DockableWidget*>(flagsView->parentWidget()));
  1056. }
  1057. void DebuggerForm::toggleStackDisplay()
  1058. {
  1059. toggleView(qobject_cast<DockableWidget*>(stackView->parentWidget()));
  1060. }
  1061. void DebuggerForm::toggleSlotsDisplay()
  1062. {
  1063. toggleView(qobject_cast<DockableWidget*>(slotView->parentWidget()));
  1064. }
  1065. void DebuggerForm::toggleBitMappedDisplay()
  1066. {
  1067. //toggleView( qobject_cast<DockableWidget*>(slotView->parentWidget()));
  1068. // not sure if this a good idea for a docable widget
  1069. // create new debuggable viewer window
  1070. BitMapViewer* viewer = new BitMapViewer();
  1071. DockableWidget* dw = new DockableWidget(dockMan);
  1072. dw->setWidget(viewer);
  1073. dw->setTitle(tr("Bitmapped VRAM View"));
  1074. dw->setId("BITMAPVRAMVIEW");
  1075. dw->setFloating(true);
  1076. dw->setDestroyable(true);
  1077. dw->setMovable(true);
  1078. dw->setClosable(true);
  1079. /*
  1080. connect( dw, SIGNAL( visibilityChanged(DockableWidget*) ),
  1081. this, SLOT( dockWidgetVisibilityChanged(DockableWidget*) ) );
  1082. connect( this, SIGNAL( debuggablesChanged(const QMap<QString,int>&) ),
  1083. viewer, SLOT( setDebuggables(const QMap<QString,int>&) ) );
  1084. */
  1085. // TODO: refresh should be being hanled by VDPDataStore...
  1086. connect(this, SIGNAL(emulationChanged()), viewer, SLOT(refresh()));
  1087. /*
  1088. viewer->setDebuggables( debuggables );
  1089. viewer->setEnabled( disasmView->isEnabled() );
  1090. */
  1091. }
  1092. void DebuggerForm::toggleVDPCommandRegsDisplay()
  1093. {
  1094. if (VDPCommandRegView == NULL) {
  1095. VDPCommandRegView = new VDPCommandRegViewer();
  1096. DockableWidget* dw = new DockableWidget(dockMan);
  1097. dw->setWidget(VDPCommandRegView);
  1098. dw->setTitle(tr("VDP registers view"));
  1099. dw->setId("VDPCommandRegView");
  1100. dw->setFloating(true);
  1101. dw->setDestroyable(false);
  1102. dw->setMovable(true);
  1103. dw->setClosable(true);
  1104. connect(this, SIGNAL(emulationChanged()),
  1105. VDPCommandRegView, SLOT(refresh()));
  1106. } else {
  1107. toggleView(qobject_cast<DockableWidget*>(VDPCommandRegView->parentWidget()));
  1108. }
  1109. }
  1110. void DebuggerForm::toggleVDPRegsDisplay()
  1111. {
  1112. if (VDPRegView == NULL) {
  1113. VDPRegView = new VDPRegViewer();
  1114. DockableWidget *dw = new DockableWidget(dockMan);
  1115. dw->setWidget(VDPRegView);
  1116. dw->setTitle(tr("VDP registers view"));
  1117. dw->setId("VDPREGVIEW");
  1118. dw->setFloating(true);
  1119. dw->setDestroyable(false);
  1120. dw->setMovable(true);
  1121. dw->setClosable(true);
  1122. connect(this, SIGNAL(emulationChanged()),
  1123. VDPRegView, SLOT(refresh()));
  1124. } else {
  1125. toggleView(qobject_cast<DockableWidget*>(VDPRegView->parentWidget()));
  1126. }
  1127. }
  1128. void DebuggerForm::toggleVDPStatusRegsDisplay()
  1129. {
  1130. if (VDPStatusRegView == NULL) {
  1131. VDPStatusRegView = new VDPStatusRegViewer();
  1132. DockableWidget* dw = new DockableWidget(dockMan);
  1133. dw->setWidget(VDPStatusRegView);
  1134. dw->setTitle(tr("VDP status registers view"));
  1135. dw->setId("VDPSTATUSREGVIEW");
  1136. dw->setFloating(true);
  1137. dw->setDestroyable(false);
  1138. dw->setMovable(true);
  1139. dw->setClosable(true);
  1140. connect(this, SIGNAL(emulationChanged()),
  1141. VDPStatusRegView, SLOT(refresh()));
  1142. } else {
  1143. toggleView(qobject_cast<DockableWidget*>(VDPStatusRegView->parentWidget()));
  1144. }
  1145. }
  1146. void DebuggerForm::toggleMemoryDisplay()
  1147. {
  1148. toggleView(qobject_cast<DockableWidget*>(mainMemoryView->parentWidget()));
  1149. }
  1150. void DebuggerForm::toggleView(DockableWidget* widget)
  1151. {
  1152. if (widget->isHidden()) {
  1153. widget->show();
  1154. } else {
  1155. widget->hide();
  1156. }
  1157. dockMan.visibilityChanged(widget);
  1158. }
  1159. void DebuggerForm::addDebuggableViewer()
  1160. {
  1161. // create new debuggable viewer window
  1162. DebuggableViewer* viewer = new DebuggableViewer();
  1163. DockableWidget* dw = new DockableWidget(dockMan);
  1164. dw->setWidget(viewer);
  1165. dw->setTitle(tr("Debuggable hex view"));
  1166. dw->setId("DEBUGVIEW");
  1167. dw->setFloating(true);
  1168. dw->setDestroyable(true);
  1169. dw->setMovable(true);
  1170. dw->setClosable(true);
  1171. connect(dw, SIGNAL(visibilityChanged(DockableWidget*)),
  1172. this, SLOT(dockWidgetVisibilityChanged(DockableWidget*)));
  1173. connect(this, SIGNAL(debuggablesChanged(const QMap<QString,int>&)),
  1174. viewer, SLOT(setDebuggables(const QMap<QString,int>&)));
  1175. connect(this, SIGNAL(emulationChanged()),
  1176. viewer, SLOT(refresh()));
  1177. viewer->setDebuggables(debuggables);
  1178. viewer->setEnabled(disasmView->isEnabled());
  1179. }
  1180. void DebuggerForm::dockWidgetVisibilityChanged(DockableWidget* w)
  1181. {
  1182. dockMan.visibilityChanged(w);
  1183. updateViewMenu();
  1184. }
  1185. void DebuggerForm::updateViewMenu()
  1186. {
  1187. viewRegistersAction->setChecked(regsView->parentWidget()->isVisible());
  1188. viewFlagsAction->setChecked(flagsView->isVisible());
  1189. viewStackAction->setChecked(stackView->isVisible());
  1190. viewSlotsAction->setChecked(slotView->isVisible());
  1191. viewMemoryAction->setChecked(mainMemoryView->isVisible());
  1192. }
  1193. void DebuggerForm::updateVDPViewMenu()
  1194. {
  1195. if (VDPCommandRegView) {
  1196. viewVDPCommandRegsAction->setChecked(VDPCommandRegView->isVisible());
  1197. }
  1198. if (VDPRegView) {
  1199. viewVDPRegsAction->setChecked(VDPRegView->isVisible());
  1200. }
  1201. if (VDPStatusRegView) {
  1202. viewVDPStatusRegsAction->setChecked(VDPStatusRegView->isVisible());
  1203. }
  1204. }
  1205. void DebuggerForm::setDebuggables(const QString& list)
  1206. {
  1207. debuggables.clear();
  1208. // process result string
  1209. QStringList l = list.split(" ", QString::SkipEmptyParts);
  1210. for (int i = 0; i < l.size(); ++i) {
  1211. QString d = l[i];
  1212. // combine multiple words
  1213. if (d[0] == '{') {
  1214. while (!d.endsWith("}")) {
  1215. d.push_back(' ');
  1216. d.append(l[++i]);
  1217. }
  1218. }
  1219. // set initial size to zero
  1220. debuggables[d] = 0;
  1221. }
  1222. // find the size for all debuggables
  1223. for (QMap<QString, int>::iterator it = debuggables.begin();
  1224. it != debuggables.end(); ++it) {
  1225. comm.sendCommand(new DebuggableSizeHandler(it.key(), *this));
  1226. }
  1227. }
  1228. void DebuggerForm::setDebuggableSize(const QString& debuggable, int size)
  1229. {
  1230. debuggables[debuggable] = size;
  1231. // emit update if size of last debuggable was set
  1232. if (debuggable == debuggables.keys().last()) {
  1233. emit debuggablesChanged(debuggables);
  1234. }
  1235. }
  1236. void DebuggerForm::symbolFileChanged()
  1237. {
  1238. static bool shown(false);
  1239. if(shown) return;
  1240. shown = true;
  1241. int choice = QMessageBox::question(this, tr("Symbol file changed"),
  1242. tr("One or more symbol file have changed.\n"
  1243. "Reload now?"),
  1244. QMessageBox::Yes | QMessageBox::No);
  1245. shown = false;
  1246. if (choice == QMessageBox::Yes)
  1247. session.symbolTable().reloadFiles();
  1248. }
  1249. void DebuggerForm::addressSlot(int addr, int& ps, int& ss, int& segment)
  1250. {
  1251. int p = (addr & 0xC000) >> 14;
  1252. ps = memLayout.primarySlot[p];
  1253. // figure out secondary slot
  1254. ss = memLayout.isSubslotted[ps] ? memLayout.secondarySlot[p] : -1;
  1255. // figure out (rom) mapper segment
  1256. segment = -1;
  1257. if (memLayout.mapperSize[ps][ss==-1 ? 0 : ss] > 0)
  1258. segment = memLayout.mapperSegment[p];
  1259. else {
  1260. int q = 2*p + ((addr & 0x2000) >> 13);
  1261. if (memLayout.romBlock[q] >= 0)
  1262. segment = memLayout.romBlock[q];
  1263. }
  1264. }