~ubuntu-branches/ubuntu/trusty/openmsx-debugger/trusty

« back to all changes in this revision

Viewing changes to src/DebuggerForm.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Joost Yervante Damad
  • Date: 2007-08-10 18:32:50 UTC
  • Revision ID: james.westby@ubuntu.com-20070810183250-hepyzcrl39slr4x1
Tags: upstream-0.0.0.svn20070518
ImportĀ upstreamĀ versionĀ 0.0.0.svn20070518

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// $Id: DebuggerForm.cpp 6484 2007-05-18 11:44:34Z edwinv $
 
2
 
 
3
#include "DebuggerForm.h"
 
4
#include "DockableWidgetArea.h"
 
5
#include "DockableWidget.h"
 
6
#include "DisasmViewer.h"
 
7
#include "HexViewer.h"
 
8
#include "CPURegsViewer.h"
 
9
#include "FlagsViewer.h"
 
10
#include "StackViewer.h"
 
11
#include "SlotViewer.h"
 
12
#include "CommClient.h"
 
13
#include "ConnectDialog.h"
 
14
#include "SymbolManager.h"
 
15
#include "PreferencesDialog.h"
 
16
#include "BreakpointDialog.h"
 
17
#include "DebuggableViewer.h"
 
18
#include "Settings.h"
 
19
#include "Version.h"
 
20
#include <QAction>
 
21
#include <QMessageBox>
 
22
#include <QMenu>
 
23
#include <QMenuBar>
 
24
#include <QToolBar>
 
25
#include <QStatusBar>
 
26
#include <QWidget>
 
27
#include <QLabel>
 
28
#include <QVBoxLayout>
 
29
#include <QHBoxLayout>
 
30
#include <QString>
 
31
#include <QStringList>
 
32
#include <QSplitter>
 
33
#include <QPixmap>
 
34
 
 
35
 
 
36
class QueryPauseHandler : public SimpleCommand
 
37
{
 
38
public:
 
39
        QueryPauseHandler(DebuggerForm& form_)
 
40
                : SimpleCommand("set pause")
 
41
                , form(form_)
 
42
        {
 
43
        }
 
44
 
 
45
        virtual void replyOk(const QString& message)
 
46
        {
 
47
                bool checked = message.trimmed() == "on";
 
48
                form.systemPauseAction->setChecked(checked);
 
49
                delete this;
 
50
        }
 
51
private:
 
52
        DebuggerForm& form;
 
53
};
 
54
 
 
55
 
 
56
class QueryBreakedHandler : public SimpleCommand
 
57
{
 
58
public:
 
59
        QueryBreakedHandler(DebuggerForm& form_)
 
60
                : SimpleCommand("debug breaked")
 
61
                , form(form_)
 
62
        {
 
63
        }
 
64
 
 
65
        virtual void replyOk(const QString& message)
 
66
        {
 
67
                form.finalizeConnection(message.trimmed() == "1");
 
68
                delete this;
 
69
        }
 
70
private:
 
71
        DebuggerForm& form;
 
72
};
 
73
 
 
74
 
 
75
class ListBreakPointsHandler : public SimpleCommand
 
76
{
 
77
public:
 
78
        ListBreakPointsHandler(DebuggerForm& form_)
 
79
                : SimpleCommand("debug list_bp")
 
80
                , form(form_)
 
81
        {
 
82
        }
 
83
 
 
84
        virtual void replyOk(const QString& message)
 
85
        {
 
86
                form.breakpoints.setBreakpoints(message);
 
87
                form.disasmView->update();
 
88
                delete this;
 
89
        }
 
90
private:
 
91
        DebuggerForm& form;
 
92
};
 
93
 
 
94
class CPURegRequest : public ReadDebugBlockCommand
 
95
{
 
96
public:
 
97
        CPURegRequest(DebuggerForm& form_)
 
98
                : ReadDebugBlockCommand("{CPU regs}", 0, 28, buf)
 
99
                , form(form_)
 
100
        {
 
101
        }
 
102
 
 
103
        virtual void replyOk(const QString& message)
 
104
        {
 
105
                copyData(message);
 
106
                form.regsView->setData(buf);
 
107
                delete this;
 
108
        }
 
109
 
 
110
private:
 
111
        DebuggerForm& form;
 
112
        unsigned char buf[28];
 
113
};
 
114
 
 
115
class ListDebuggablesHandler : public SimpleCommand
 
116
{
 
117
public:
 
118
        ListDebuggablesHandler(DebuggerForm& form_)
 
119
                : SimpleCommand("debug list")
 
120
                , form(form_)
 
121
        {
 
122
        }
 
123
 
 
124
        virtual void replyOk(const QString& message)
 
125
        {
 
126
                form.setDebuggables(message);
 
127
                delete this;
 
128
        }
 
129
private:
 
130
        DebuggerForm& form;
 
131
};
 
132
 
 
133
class DebuggableSizeHandler : public SimpleCommand
 
134
{
 
135
public:
 
136
        DebuggableSizeHandler(const QString& debuggable_, DebuggerForm& form_)
 
137
                : SimpleCommand(QString("debug size %1").arg(debuggable_))
 
138
                , debuggable(debuggable_)
 
139
                , form(form_)
 
140
        {
 
141
        }
 
142
 
 
143
        virtual void replyOk(const QString& message)
 
144
        {
 
145
                form.setDebuggableSize(debuggable, message.toInt());
 
146
                delete this;
 
147
        }
 
148
private:
 
149
        QString debuggable;
 
150
        DebuggerForm& form;
 
151
};
 
152
 
 
153
 
 
154
DebuggerForm::DebuggerForm(QWidget* parent)
 
155
        : QMainWindow(parent)
 
156
        , comm(CommClient::instance())
 
157
{
 
158
        createActions();
 
159
        createMenus();
 
160
        createToolbars();
 
161
        createStatusbar();
 
162
        createForm();
 
163
}
 
164
 
 
165
void DebuggerForm::createActions()
 
166
{
 
167
        systemConnectAction = new QAction(tr("&Connect"), this);
 
168
        systemConnectAction->setShortcut(tr("Ctrl+C"));
 
169
        systemConnectAction->setStatusTip(tr("Connect to openMSX"));
 
170
        systemConnectAction->setIcon(QIcon(":/icons/connect.png"));
 
171
 
 
172
        systemDisconnectAction = new QAction(tr("&Disconnect"), this);
 
173
        systemDisconnectAction->setShortcut(tr(""));
 
174
        systemDisconnectAction->setStatusTip(tr("Disconnect from openMSX"));
 
175
        systemDisconnectAction->setIcon(QIcon(":/icons/disconnect.png"));
 
176
        systemDisconnectAction->setEnabled(false);
 
177
 
 
178
        systemPauseAction = new QAction(tr("&Pause emulator"), this);
 
179
        systemPauseAction->setShortcut(Qt::Key_Pause);
 
180
        systemPauseAction->setStatusTip(tr("Pause the emulation"));
 
181
        systemPauseAction->setIcon(QIcon(":/icons/pause.png"));
 
182
        systemPauseAction->setCheckable(true);
 
183
        systemPauseAction->setEnabled(false);
 
184
 
 
185
        systemSymbolManagerAction = new QAction(tr("&Symbol mananger ..."), this);
 
186
        systemSymbolManagerAction->setStatusTip(tr("Start the symbol manager"));
 
187
        systemSymbolManagerAction->setIcon(QIcon(":/icons/symmanager.png"));
 
188
 
 
189
        systemPreferencesAction = new QAction(tr("Pre&ferences ..."), this);
 
190
        systemPreferencesAction->setStatusTip(tr("Set the global debugger preferences"));
 
191
 
 
192
        systemQuitAction = new QAction(tr("&Quit"), this);
 
193
        systemQuitAction->setShortcut(tr("Ctrl+Q"));
 
194
        systemQuitAction->setStatusTip(tr("Quit the openMSX debugger"));
 
195
 
 
196
        viewRegistersAction = new QAction(tr("CPU &Registers"), this);
 
197
        viewRegistersAction->setStatusTip(tr("Toggle the cpu registers display"));
 
198
        viewRegistersAction->setCheckable(true);
 
199
        
 
200
        viewFlagsAction = new QAction(tr("CPU &Flags"), this);
 
201
        viewFlagsAction->setStatusTip(tr("Toggle the cpu flags display"));
 
202
        viewFlagsAction->setCheckable(true);
 
203
        
 
204
        viewStackAction = new QAction(tr("Stack"), this);
 
205
        viewStackAction->setStatusTip(tr("Toggle the stack display"));
 
206
        viewStackAction->setCheckable(true);
 
207
        
 
208
        viewSlotsAction = new QAction(tr("Slots"), this);
 
209
        viewSlotsAction->setStatusTip(tr("Toggle the slots display"));
 
210
        viewSlotsAction->setCheckable(true);
 
211
        
 
212
        viewMemoryAction = new QAction(tr("Memory"), this);
 
213
        viewMemoryAction->setStatusTip(tr("Toggle the main memory display"));
 
214
        viewMemoryAction->setCheckable(true);
 
215
 
 
216
        viewDebuggableViewerAction = new QAction(tr("Add debuggable viewer"), this);
 
217
        viewDebuggableViewerAction->setStatusTip(tr("Add a hex viewer for debuggables"));
 
218
 
 
219
        executeBreakAction = new QAction(tr("Break"), this);
 
220
        executeBreakAction->setShortcut(tr("CRTL+B"));
 
221
        executeBreakAction->setStatusTip(tr("Halt the execution and enter debug mode"));
 
222
        executeBreakAction->setIcon(QIcon(":/icons/break.png"));
 
223
        executeBreakAction->setEnabled(false);
 
224
 
 
225
        executeRunAction = new QAction(tr("Run"), this);
 
226
        executeRunAction->setShortcut(tr("F9"));
 
227
        executeRunAction->setStatusTip(tr("Leave debug mode and resume execution"));
 
228
        executeRunAction->setIcon(QIcon(":/icons/run.png"));
 
229
        executeRunAction->setEnabled(false);
 
230
 
 
231
        executeStepAction = new QAction(tr("Step into"), this);
 
232
        executeStepAction->setShortcut(tr("F7"));
 
233
        executeStepAction->setStatusTip(tr("Execute a single instruction"));
 
234
        executeStepAction->setIcon(QIcon(":/icons/stepinto.png"));
 
235
        executeStepAction->setEnabled(false);
 
236
 
 
237
        executeStepOverAction = new QAction(tr("Step over"), this);
 
238
        executeStepOverAction->setShortcut(tr("F8"));
 
239
        executeStepOverAction->setStatusTip(tr("Execute the next instruction including any called subroutines"));
 
240
        executeStepOverAction->setIcon(QIcon(":/icons/stepover.png"));
 
241
        executeStepOverAction->setEnabled(false);
 
242
 
 
243
        executeStepOutAction = new QAction(tr("Step out"), this);
 
244
        executeStepOutAction->setShortcut(tr("F11"));
 
245
        executeStepOutAction->setStatusTip(tr("Resume execution until the current routine has finished"));
 
246
        executeStepOutAction->setIcon(QIcon(":/icons/stepout.png"));
 
247
        executeStepOutAction->setEnabled(false);
 
248
 
 
249
        executeRunToAction = new QAction(tr("Run to"), this);
 
250
        executeRunToAction->setShortcut(tr("F4"));
 
251
        executeRunToAction->setStatusTip(tr("Resume execution until the selected line is reached"));
 
252
        executeRunToAction->setIcon(QIcon(":/icons/runto.png"));
 
253
        executeRunToAction->setEnabled(false);
 
254
 
 
255
        breakpointToggleAction = new QAction(tr("Toggle"), this);
 
256
        breakpointToggleAction->setShortcut(tr("F5"));
 
257
        breakpointToggleAction->setStatusTip(tr("Toggle breakpoint on/off at cursor"));
 
258
        breakpointToggleAction->setIcon(QIcon(":/icons/break.png"));
 
259
        breakpointToggleAction->setEnabled(false);
 
260
 
 
261
        breakpointAddAction = new QAction(tr("Add ..."), this);
 
262
        breakpointAddAction->setShortcut(tr("CTRL+B"));
 
263
        breakpointAddAction->setStatusTip(tr("Add a breakpoint at a location"));
 
264
        breakpointAddAction->setEnabled(false);
 
265
 
 
266
        helpAboutAction = new QAction(tr("&About"), this);
 
267
        executeRunToAction->setStatusTip(tr("Show the appliction information"));
 
268
 
 
269
        connect(systemConnectAction, SIGNAL(triggered()), this, SLOT(systemConnect()));
 
270
        connect(systemDisconnectAction, SIGNAL(triggered()), this, SLOT(systemDisconnect()));
 
271
        connect(systemPauseAction, SIGNAL(triggered()), this, SLOT(systemPause()));
 
272
        connect(systemSymbolManagerAction, SIGNAL(triggered()), this, SLOT(systemSymbolManager()));
 
273
        connect(systemPreferencesAction, SIGNAL(triggered()), this, SLOT(systemPreferences()));
 
274
        connect(systemQuitAction, SIGNAL(triggered()), this, SLOT(close()));
 
275
        connect(viewRegistersAction, SIGNAL(triggered()), this, SLOT(toggleRegisterDisplay()));
 
276
        connect(viewFlagsAction, SIGNAL(triggered()), this, SLOT(toggleFlagsDisplay()));
 
277
        connect(viewStackAction, SIGNAL(triggered()), this, SLOT(toggleStackDisplay()));
 
278
        connect(viewSlotsAction, SIGNAL(triggered()), this, SLOT(toggleSlotsDisplay()));
 
279
        connect(viewMemoryAction, SIGNAL(triggered()), this, SLOT(toggleMemoryDisplay()));
 
280
        connect(viewDebuggableViewerAction, SIGNAL(triggered()), this, SLOT(addDebuggableViewer()));
 
281
        connect(executeBreakAction, SIGNAL(triggered()), this, SLOT(executeBreak()));
 
282
        connect(executeRunAction, SIGNAL(triggered()), this, SLOT(executeRun()));
 
283
        connect(executeStepAction, SIGNAL(triggered()), this, SLOT(executeStep()));
 
284
        connect(executeStepOverAction, SIGNAL(triggered()), this, SLOT(executeStepOver()));
 
285
        connect(executeRunToAction, SIGNAL(triggered()), this, SLOT(executeRunTo()));
 
286
        connect(executeStepOutAction, SIGNAL(triggered()), this, SLOT(executeStepOut()));
 
287
        connect(breakpointToggleAction, SIGNAL(triggered()), this, SLOT(breakpointToggle()));
 
288
        connect(breakpointAddAction, SIGNAL(triggered()), this, SLOT(breakpointAdd()));
 
289
        connect(helpAboutAction, SIGNAL(triggered()), this, SLOT(showAbout()));
 
290
}
 
291
 
 
292
void DebuggerForm::createMenus()
 
293
{
 
294
        // create system menu
 
295
        systemMenu = menuBar()->addMenu(tr("&System"));
 
296
        systemMenu->addAction(systemConnectAction);
 
297
        systemMenu->addAction(systemDisconnectAction);
 
298
        systemMenu->addSeparator();
 
299
        systemMenu->addAction(systemPauseAction);
 
300
        systemMenu->addSeparator();
 
301
        systemMenu->addAction(systemSymbolManagerAction);
 
302
        systemMenu->addSeparator();
 
303
        systemMenu->addAction(systemPreferencesAction);
 
304
        systemMenu->addSeparator();
 
305
        systemMenu->addAction(systemQuitAction);
 
306
 
 
307
        // create execute menu
 
308
        viewMenu = menuBar()->addMenu(tr("&View"));
 
309
        viewMenu->addAction(viewRegistersAction);
 
310
        viewMenu->addAction(viewFlagsAction);
 
311
        viewMenu->addAction(viewStackAction);
 
312
        viewMenu->addAction(viewSlotsAction);
 
313
        viewMenu->addAction(viewMemoryAction);
 
314
        viewMenu->addSeparator();
 
315
        viewMenu->addAction(viewDebuggableViewerAction);
 
316
        connect( viewMenu, SIGNAL( aboutToShow() ), this, SLOT( updateViewMenu() ) );
 
317
        
 
318
        // create execute menu
 
319
        executeMenu = menuBar()->addMenu(tr("&Execute"));
 
320
        executeMenu->addAction(executeBreakAction);
 
321
        executeMenu->addAction(executeRunAction);
 
322
        executeMenu->addSeparator();
 
323
        executeMenu->addAction(executeStepAction);
 
324
        executeMenu->addAction(executeStepOverAction);
 
325
        executeMenu->addAction(executeStepOutAction);
 
326
        executeMenu->addAction(executeRunToAction);
 
327
 
 
328
        // create breakpoint menu
 
329
        breakpointMenu = menuBar()->addMenu(tr("&Breakpoint"));
 
330
        breakpointMenu->addAction(breakpointToggleAction);
 
331
        breakpointMenu->addAction(breakpointAddAction);
 
332
 
 
333
        // create help menu
 
334
        helpMenu = menuBar()->addMenu(tr("&Help"));
 
335
        helpMenu->addAction(helpAboutAction);
 
336
}
 
337
 
 
338
void DebuggerForm::createToolbars()
 
339
{
 
340
        // create debug toolbar
 
341
        systemToolbar = addToolBar(tr("System"));
 
342
        systemToolbar->addAction(systemConnectAction);
 
343
        systemToolbar->addAction(systemDisconnectAction);
 
344
        systemToolbar->addSeparator();
 
345
        systemToolbar->addAction(systemPauseAction);
 
346
        systemToolbar->addSeparator();
 
347
        systemToolbar->addAction(systemSymbolManagerAction);
 
348
 
 
349
        // create debug toolbar
 
350
        executeToolbar = addToolBar(tr("Execution"));
 
351
        executeToolbar->addAction(executeBreakAction);
 
352
        executeToolbar->addAction(executeRunAction);
 
353
        executeToolbar->addSeparator();
 
354
        executeToolbar->addAction(executeStepAction);
 
355
        executeToolbar->addAction(executeStepOverAction);
 
356
        executeToolbar->addAction(executeStepOutAction);
 
357
        executeToolbar->addAction(executeRunToAction);
 
358
}
 
359
 
 
360
void DebuggerForm::createStatusbar()
 
361
{
 
362
        // create the statusbar
 
363
        statusBar()->showMessage("No emulation running.");
 
364
}
 
365
 
 
366
void DebuggerForm::createForm()
 
367
{
 
368
        setWindowTitle("openMSX Debugger");
 
369
 
 
370
        mainArea = new DockableWidgetArea;
 
371
        dockMan.addDockArea( mainArea );
 
372
        setCentralWidget(mainArea);
 
373
 
 
374
        /*
 
375
         * Create main widgets and append them to the list first
 
376
         */
 
377
        DockableWidget *dw = new DockableWidget( dockMan );
 
378
 
 
379
        // create the disasm viewer widget
 
380
        disasmView = new DisasmViewer;
 
381
        dw->setWidget(disasmView);
 
382
        dw->setTitle(tr("Code view"));
 
383
        dw->setId("CODEVIEW");
 
384
        dw->setFloating(false);
 
385
        dw->setDestroyable(false);
 
386
        dw->setMovable(false);
 
387
        dw->setClosable(false);
 
388
        connect( this, SIGNAL( settingsChanged() ),
 
389
                 disasmView, SLOT( settingsChanged() ) );
 
390
        connect( this, SIGNAL( symbolsChanged() ),
 
391
                 disasmView, SLOT( symbolsChanged() ) );
 
392
        connect( dw, SIGNAL( visibilityChanged(DockableWidget*) ),
 
393
                 this, SLOT( dockWidgetVisibilityChanged(DockableWidget*) ) );
 
394
 
 
395
        // create the memory view widget
 
396
        hexView = new HexViewer;
 
397
        dw = new DockableWidget( dockMan );
 
398
        dw->setWidget(hexView);
 
399
        dw->setTitle(tr("Main memory"));
 
400
        dw->setId("MEMORY");
 
401
        dw->setFloating(false);
 
402
        dw->setDestroyable(false);
 
403
        dw->setMovable(true);
 
404
        dw->setClosable(true);
 
405
        connect( dw, SIGNAL( visibilityChanged(DockableWidget*) ),
 
406
                 this, SLOT( dockWidgetVisibilityChanged(DockableWidget*) ) );
 
407
        
 
408
        // create register viewer
 
409
        regsView = new CPURegsViewer;
 
410
        dw = new DockableWidget( dockMan );
 
411
        dw->setWidget(regsView);
 
412
        dw->setTitle(tr("CPU registers"));
 
413
        dw->setId("REGISTERS");
 
414
        dw->setFloating(false);
 
415
        dw->setDestroyable(false);
 
416
        dw->setMovable(true);
 
417
        dw->setClosable(true);
 
418
        connect( dw, SIGNAL( visibilityChanged(DockableWidget*) ),
 
419
                 this, SLOT( dockWidgetVisibilityChanged(DockableWidget*) ) );
 
420
        
 
421
        // create flags viewer
 
422
        flagsView = new FlagsViewer;
 
423
        dw = new DockableWidget( dockMan );
 
424
        dw->setWidget(flagsView);
 
425
        dw->setTitle(tr("Flags"));
 
426
        dw->setId("FLAGS");
 
427
        dw->setFloating(false);
 
428
        dw->setDestroyable(false);
 
429
        dw->setMovable(true);
 
430
        dw->setClosable(true);
 
431
        connect( dw, SIGNAL( visibilityChanged(DockableWidget*) ),
 
432
                 this, SLOT( dockWidgetVisibilityChanged(DockableWidget*) ) );
 
433
 
 
434
        // create stack viewer
 
435
        stackView = new StackViewer;
 
436
        dw = new DockableWidget( dockMan );
 
437
        dw->setWidget(stackView);
 
438
        dw->setTitle(tr("Stack"));
 
439
        dw->setId("STACK");
 
440
        dw->setFloating(false);
 
441
        dw->setDestroyable(false);
 
442
        dw->setMovable(true);
 
443
        dw->setClosable(true);
 
444
        connect( dw, SIGNAL( visibilityChanged(DockableWidget*) ),
 
445
                 this, SLOT( dockWidgetVisibilityChanged(DockableWidget*) ) );
 
446
 
 
447
        // create slot viewer
 
448
        slotView = new SlotViewer;
 
449
        dw = new DockableWidget( dockMan );
 
450
        dw->setWidget(slotView);
 
451
        dw->setTitle(tr("Memory layout"));
 
452
        dw->setId("SLOTS");
 
453
        dw->setFloating(false);
 
454
        dw->setDestroyable(false);
 
455
        dw->setMovable(true);
 
456
        dw->setClosable(true);
 
457
        connect( dw, SIGNAL( visibilityChanged(DockableWidget*) ),
 
458
                 this, SLOT( dockWidgetVisibilityChanged(DockableWidget*) ) );
 
459
 
 
460
        // restore layout
 
461
        restoreGeometry( Settings::get().value( "Layout/WindowGeometry", saveGeometry() ).toByteArray() );
 
462
        
 
463
        QStringList list = Settings::get().value( "Layout/WidgetLayout" ).toStringList();
 
464
        // defaults needed?
 
465
        if( !list.size() || !list.at(0).startsWith("CODEVIEW ") ) {
 
466
                list.clear();
 
467
                list.append( "CODEVIEW D V R 0 -1 -1" );
 
468
                list.append( "REGISTERS D V R 0 -1 -1" );
 
469
                list.append( "FLAGS D V R 0 -1 -1" );
 
470
                int regW = dockMan.findDockableWidget("REGISTERS")->sizeHint().width();
 
471
                int regH = dockMan.findDockableWidget("REGISTERS")->sizeHint().height();
 
472
                int codeW = dockMan.findDockableWidget("CODEVIEW")->sizeHint().width();
 
473
                int codeH = dockMan.findDockableWidget("CODEVIEW")->sizeHint().height();
 
474
                int flagW = dockMan.findDockableWidget("FLAGS")->sizeHint().width();
 
475
                int slotW = dockMan.findDockableWidget("SLOTS")->sizeHint().width();
 
476
                list.append( QString("SLOTS D V R 0 -1 %1").arg(regH) );
 
477
                list.append( QString("STACK D V R 0 -1 %1").arg(codeH) );
 
478
                list.append( QString("MEMORY D V B %1 %2 %3").arg(codeW)
 
479
                                                             .arg(regW + flagW + slotW)
 
480
                                                             .arg(codeH - regH) );
 
481
        }
 
482
 
 
483
        // add widgets
 
484
        for( int i = 0; i < list.size(); i++ ) {
 
485
                QStringList s = list.at(i).split(" ", QString::SkipEmptyParts);
 
486
                // get widget
 
487
                if( (dw = dockMan.findDockableWidget(s.at(0))) ) {
 
488
                        if( s.at(1) == "D" ) {
 
489
                                // dock widget
 
490
                                DockableWidgetLayout::DockSide side;
 
491
                                if( s.at(3) == "T" )
 
492
                                        side = DockableWidgetLayout::TOP;
 
493
                                else if( s.at(3) == "L" )
 
494
                                        side = DockableWidgetLayout::LEFT;
 
495
                                else if( s.at(3) == "R" )
 
496
                                        side = DockableWidgetLayout::RIGHT;
 
497
                                else 
 
498
                                        side = DockableWidgetLayout::BOTTOM;
 
499
                                dockMan.insertWidget( dw, 0, side, s.at(4).toInt(), s.at(5).toInt(), s.at(6).toInt() );
 
500
                                if( s.at(2) == "H" ) dw->hide();
 
501
                        } else if( s.at(1) == "F" ) {
 
502
                                //  float widget
 
503
                                dw->setFloating(true, s.at(2) == "V");
 
504
                                dw->resize(  s.at(5).toInt(), s.at(6).toInt() );
 
505
                                dw->move(  s.at(3).toInt(), s.at(4).toInt() );
 
506
                        }
 
507
                }
 
508
        }
 
509
 
 
510
        // disable all widgets
 
511
        connectionClosed();
 
512
 
 
513
        connect(regsView,   SIGNAL(pcChanged(quint16)),
 
514
                disasmView, SLOT(setProgramCounter(quint16)));
 
515
        connect(regsView,   SIGNAL(flagsChanged(quint8)),
 
516
                flagsView,  SLOT(setFlags(quint8)));
 
517
        connect(regsView,   SIGNAL(spChanged(quint16)),
 
518
                stackView,  SLOT(setStackPointer(quint16)));
 
519
        connect(disasmView, SIGNAL(toggleBreakpoint(int)),
 
520
                            SLOT(breakpointToggle(int)));
 
521
 
 
522
        connect(&comm, SIGNAL(connectionReady()),
 
523
                SLOT(initConnection()));
 
524
        connect(&comm, SIGNAL(updateParsed(const QString&, const QString&, const QString&)),
 
525
                SLOT(handleUpdate(const QString&, const QString&, const QString&)));
 
526
        connect(&comm, SIGNAL(connectionTerminated()),
 
527
                SLOT(connectionClosed()));
 
528
 
 
529
        // init main memory
 
530
        // added four bytes as runover buffer for dasm
 
531
        // otherwise dasm would need to check the buffer end continously.
 
532
        breakpoints.setMemoryLayout(&memLayout);
 
533
        mainMemory = new unsigned char[65536 + 4];
 
534
        memset(mainMemory, 0, 65536 + 4);
 
535
        disasmView->setMemory(mainMemory);
 
536
        disasmView->setBreakpoints(&breakpoints);
 
537
        disasmView->setMemoryLayout(&memLayout);
 
538
        disasmView->setSymbolTable(&symTable);
 
539
        hexView->setDebuggable("memory", 65536);
 
540
        stackView->setData(mainMemory, 65536);
 
541
        slotView->setMemoryLayout(&memLayout);
 
542
}
 
543
 
 
544
DebuggerForm::~DebuggerForm()
 
545
{
 
546
        delete[] mainMemory;
 
547
}
 
548
 
 
549
void DebuggerForm::closeEvent( QCloseEvent *e )
 
550
{
 
551
        // store layout
 
552
        Settings::get().setValue( "Layout/WindowGeometry", saveGeometry() );
 
553
 
 
554
        QStringList layoutList;
 
555
        // fill layout list with docked widgets
 
556
        dockMan.getConfig( 0, layoutList );
 
557
        // append floating widgets
 
558
        QList<DockableWidget*>::const_iterator it = dockMan.managedWidgets().begin();
 
559
        while( it != dockMan.managedWidgets().end() ) {
 
560
                if( (*it)->isFloating() ) {
 
561
                        QString s("%1 F %2 %3 %4 %5 %6");
 
562
                        s = s.arg( (*it)->id() );
 
563
                        if( (*it)->isHidden() )
 
564
                                s = s.arg("H");
 
565
                        else
 
566
                                s = s.arg("V");
 
567
                        s = s.arg( (*it)->x() ).arg( (*it)->y() )
 
568
                             .arg( (*it)->width() ).arg( (*it)->height() );
 
569
                        layoutList.append( s );
 
570
                }
 
571
                it++;
 
572
        }
 
573
        Settings::get().setValue( "Layout/WidgetLayout", layoutList );
 
574
        
 
575
        QMainWindow::closeEvent(e);
 
576
}
 
577
 
 
578
void DebuggerForm::initConnection()
 
579
{
 
580
        systemConnectAction->setEnabled(false);
 
581
        systemDisconnectAction->setEnabled(true);
 
582
 
 
583
        comm.sendCommand(new QueryPauseHandler(*this));
 
584
        comm.sendCommand(new QueryBreakedHandler(*this));
 
585
 
 
586
        comm.sendCommand(new SimpleCommand("update enable status"));
 
587
 
 
588
        comm.sendCommand(new ListDebuggablesHandler(*this));
 
589
 
 
590
        // define 'debug_bin2hex' proc for internal use
 
591
        comm.sendCommand(new SimpleCommand(
 
592
                "proc debug_bin2hex { input } {\n"
 
593
                "  set result \"\"\n"
 
594
                "  foreach i [split $input {}] {\n"
 
595
                "    append result [format %02X [scan $i %c]] \"\"\n"
 
596
                "  }\n"
 
597
                "  return $result\n"
 
598
                "}\n"));
 
599
 
 
600
        // define 'debug_memmapper' proc for internal use
 
601
        comm.sendCommand(new SimpleCommand(
 
602
                "proc debug_memmapper { } {\n"
 
603
                "  set result \"\"\n"
 
604
                "  for { set page 0 } { $page &lt; 4 } { incr page } {\n"
 
605
                "    set tmp [get_selected_slot $page]\n"
 
606
                "    append result [lindex $tmp 0] [lindex $tmp 1] \"\\n\"\n"
 
607
                "    if { [lsearch [debug list] \"MapperIO\"] != -1} {\n"
 
608
                "      append result [debug read \"MapperIO\" $page] \"\\n\"\n"
 
609
                "    } else {\n"
 
610
                "      append result \"0\\n\"\n"
 
611
                "    }\n"
 
612
                "  }\n"
 
613
                "  for { set ps 0 } { $ps &lt; 4 } { incr ps } {\n"
 
614
                "    if [machine_info issubslotted $ps] {\n"
 
615
                "      append result \"1\\n\"\n"
 
616
                "      for { set ss 0 } { $ss &lt; 4 } { incr ss } {\n"
 
617
                "        append result [get_mapper_size $ps $ss] \"\\n\"\n"
 
618
                "      }\n"
 
619
                "    } else {\n"
 
620
                "      append result \"0\\n\"\n"
 
621
                "      append result [get_mapper_size $ps 0] \"\\n\"\n"
 
622
                "    }\n"
 
623
                "  }\n"
 
624
                "  return $result\n"
 
625
                "}\n"));
 
626
}
 
627
 
 
628
void DebuggerForm::connectionClosed()
 
629
{
 
630
        systemPauseAction->setEnabled(false);
 
631
        executeBreakAction->setEnabled(false);
 
632
        executeRunAction->setEnabled(false);
 
633
        executeStepAction->setEnabled(false);
 
634
        executeStepOverAction->setEnabled(false);
 
635
        executeStepOutAction->setEnabled(false);
 
636
        executeRunToAction->setEnabled(false);
 
637
        systemDisconnectAction->setEnabled(false);
 
638
        systemConnectAction->setEnabled(true);
 
639
 
 
640
        QList<DockableWidget*>::const_iterator it = dockMan.managedWidgets().begin();
 
641
        while( it != dockMan.managedWidgets().end() ) {
 
642
                (*it)->widget()->setEnabled(false);
 
643
                it++;
 
644
        }
 
645
}
 
646
 
 
647
void DebuggerForm::finalizeConnection(bool halted)
 
648
{
 
649
        systemPauseAction->setEnabled(true);
 
650
        if (halted) {
 
651
                setBreakMode();
 
652
                breakOccured();
 
653
        } else {
 
654
                setRunMode();
 
655
                updateData();
 
656
        }
 
657
 
 
658
        QList<DockableWidget*>::const_iterator it = dockMan.managedWidgets().begin();
 
659
        while( it != dockMan.managedWidgets().end() ) {
 
660
                (*it)->widget()->setEnabled(true);
 
661
                it++;
 
662
        }
 
663
}
 
664
 
 
665
void DebuggerForm::handleUpdate(const QString& type, const QString& name,
 
666
                                const QString& message)
 
667
{
 
668
        if (type == "status") {
 
669
                if (name == "cpu") {
 
670
                        if (message == "suspended") {
 
671
                                breakOccured();
 
672
                        } else {
 
673
                                setRunMode();
 
674
                        }
 
675
                } else if (name == "paused") {
 
676
                        pauseStatusChanged(message == "true");
 
677
                }
 
678
        }
 
679
}
 
680
 
 
681
void DebuggerForm::pauseStatusChanged(bool isPaused)
 
682
{
 
683
        systemPauseAction->setChecked(isPaused);
 
684
}
 
685
 
 
686
void DebuggerForm::breakOccured()
 
687
{
 
688
        setBreakMode();
 
689
        updateData();
 
690
}
 
691
 
 
692
void DebuggerForm::updateData()
 
693
{
 
694
        comm.sendCommand(new ListBreakPointsHandler(*this));
 
695
 
 
696
        // update registers
 
697
        // note that a register update is processed, a signal is sent to other
 
698
        // widgets as well. Any dependent updates shoud be called before this one.
 
699
        CPURegRequest* regs = new CPURegRequest(*this);
 
700
        comm.sendCommand(regs);
 
701
 
 
702
        // refresh memory viewer
 
703
        hexView->refresh();
 
704
 
 
705
        // refresh slot viewer
 
706
        slotView->refresh();
 
707
        
 
708
        emit emulationChanged();
 
709
}
 
710
 
 
711
void DebuggerForm::setBreakMode()
 
712
{
 
713
        executeBreakAction->setEnabled(false);
 
714
        executeRunAction->setEnabled(true);
 
715
        executeStepAction->setEnabled(true);
 
716
        executeStepOverAction->setEnabled(true);
 
717
        executeStepOutAction->setEnabled(true);
 
718
        executeRunToAction->setEnabled(true);
 
719
        breakpointToggleAction->setEnabled(true);
 
720
        breakpointAddAction->setEnabled(true);
 
721
}
 
722
 
 
723
void DebuggerForm::setRunMode()
 
724
{
 
725
        executeBreakAction->setEnabled(true);
 
726
        executeRunAction->setEnabled(false);
 
727
        executeStepAction->setEnabled(false);
 
728
        executeStepOverAction->setEnabled(false);
 
729
        executeStepOutAction->setEnabled(false);
 
730
        executeRunToAction->setEnabled(false);
 
731
        breakpointToggleAction->setEnabled(false);
 
732
        breakpointAddAction->setEnabled(false);
 
733
}
 
734
 
 
735
void DebuggerForm::systemConnect()
 
736
{
 
737
        OpenMSXConnection* connection = ConnectDialog::getConnection(this);
 
738
        if (connection) {
 
739
                comm.connectToOpenMSX(connection);
 
740
        }
 
741
}
 
742
 
 
743
void DebuggerForm::systemDisconnect()
 
744
{
 
745
        comm.closeConnection();
 
746
}
 
747
 
 
748
void DebuggerForm::systemPause()
 
749
{
 
750
        comm.sendCommand(new SimpleCommand(QString("set pause ") +
 
751
                            (systemPauseAction->isChecked() ? "true" : "false")));
 
752
}
 
753
 
 
754
void DebuggerForm::systemSymbolManager()
 
755
{
 
756
        SymbolManager symManager( symTable, this );
 
757
        symManager.exec();
 
758
        emit symbolsChanged();
 
759
}
 
760
 
 
761
void DebuggerForm::systemPreferences()
 
762
{
 
763
        PreferencesDialog prefs( this );
 
764
        prefs.exec();
 
765
        emit settingsChanged();
 
766
}
 
767
 
 
768
void DebuggerForm::executeBreak()
 
769
{
 
770
        comm.sendCommand(new SimpleCommand("debug break"));
 
771
}
 
772
 
 
773
void DebuggerForm::executeRun()
 
774
{
 
775
        comm.sendCommand(new SimpleCommand("debug cont"));
 
776
        setRunMode();
 
777
}
 
778
 
 
779
void DebuggerForm::executeStep()
 
780
{
 
781
        comm.sendCommand(new SimpleCommand("debug step"));
 
782
        setRunMode();
 
783
}
 
784
 
 
785
void DebuggerForm::executeStepOver()
 
786
{
 
787
        comm.sendCommand(new SimpleCommand("step_over"));
 
788
        setRunMode();
 
789
}
 
790
 
 
791
void DebuggerForm::executeRunTo()
 
792
{
 
793
        comm.sendCommand(new SimpleCommand(
 
794
                          "run_to " + QString::number(disasmView->cursorAddress())));
 
795
        setRunMode();
 
796
}
 
797
 
 
798
void DebuggerForm::executeStepOut()
 
799
{
 
800
        // TODO
 
801
}
 
802
 
 
803
void DebuggerForm::breakpointToggle(int addr)
 
804
{
 
805
        // toggle address unspecified, use cursor address
 
806
        if (addr < 0) addr = disasmView->cursorAddress();
 
807
 
 
808
        QString cmd;
 
809
        if (breakpoints.isBreakpoint(addr)) {
 
810
                cmd = "debug remove_bp " + breakpoints.idString(addr);
 
811
        } else {
 
812
                int p = (addr & 0xC000) >> 14;
 
813
                cmd.sprintf("debug set_bp %i { [ pc_in_slot %c %c %i ] }",
 
814
                            addr, memLayout.primarySlot[p],
 
815
                            memLayout.secondarySlot[p],
 
816
                            memLayout.mapperSegment[p]);
 
817
        }
 
818
        comm.sendCommand(new SimpleCommand(cmd));
 
819
 
 
820
        comm.sendCommand(new ListBreakPointsHandler(*this));
 
821
}
 
822
 
 
823
void DebuggerForm::breakpointAdd()
 
824
{
 
825
        BreakpointDialog bpd( memLayout, this );
 
826
        if( bpd.exec() ) {
 
827
                if( bpd.address() > 0 ) {
 
828
                        QString cmd("debug set_bp %1 { [ pc_in_slot %2 %3 %4 ] }");
 
829
                        cmd = cmd.arg( bpd.address() );
 
830
 
 
831
                        if( bpd.slot() == -1 )
 
832
                                cmd = cmd.arg('X');
 
833
                        else
 
834
                                cmd = cmd.arg(bpd.slot());
 
835
 
 
836
                        if( bpd.subslot() == -1 )
 
837
                                cmd = cmd.arg('X');
 
838
                        else
 
839
                                cmd = cmd.arg(bpd.subslot());
 
840
 
 
841
                        if( bpd.segment() == -1 )
 
842
                                cmd = cmd.arg('X');
 
843
                        else
 
844
                                cmd = cmd.arg(bpd.segment());
 
845
 
 
846
                        comm.sendCommand(new SimpleCommand(cmd));
 
847
 
 
848
                        comm.sendCommand(new ListBreakPointsHandler(*this));
 
849
                }
 
850
        };
 
851
}
 
852
 
 
853
void DebuggerForm::showAbout()
 
854
{
 
855
        QMessageBox::about(
 
856
                this, "openMSX Debugger", QString(Version::FULL_VERSION.c_str())
 
857
                );
 
858
}
 
859
 
 
860
void DebuggerForm::toggleRegisterDisplay()
 
861
{
 
862
        toggleView( qobject_cast<DockableWidget*>(regsView->parentWidget()));
 
863
}
 
864
 
 
865
void DebuggerForm::toggleFlagsDisplay()
 
866
{
 
867
        toggleView( qobject_cast<DockableWidget*>(flagsView->parentWidget()));
 
868
}
 
869
 
 
870
void DebuggerForm::toggleStackDisplay()
 
871
{
 
872
        toggleView( qobject_cast<DockableWidget*>(stackView->parentWidget()));
 
873
}
 
874
 
 
875
void DebuggerForm::toggleSlotsDisplay()
 
876
{
 
877
        toggleView( qobject_cast<DockableWidget*>(slotView->parentWidget()));
 
878
}
 
879
 
 
880
void DebuggerForm::toggleMemoryDisplay()
 
881
{
 
882
        toggleView( qobject_cast<DockableWidget*>(hexView->parentWidget()));
 
883
}
 
884
 
 
885
void DebuggerForm::toggleView( DockableWidget* widget )
 
886
{
 
887
        if( widget->isHidden() ) {
 
888
                widget->show();
 
889
        } else {
 
890
                widget->hide();
 
891
        }
 
892
        dockMan.visibilityChanged( widget );
 
893
}
 
894
 
 
895
void DebuggerForm::addDebuggableViewer()
 
896
{
 
897
        // create new debuggable viewer window
 
898
        DebuggableViewer *viewer = new DebuggableViewer;
 
899
        DockableWidget *dw = new DockableWidget( dockMan );
 
900
        dw->setWidget(viewer);
 
901
        dw->setTitle(tr("Debuggable hex view"));
 
902
        dw->setId("DEBUGVIEW");
 
903
        dw->setFloating(true);
 
904
        dw->setDestroyable(true);
 
905
        dw->setMovable(true);
 
906
        dw->setClosable(true);
 
907
        connect( dw, SIGNAL( visibilityChanged(DockableWidget*) ),
 
908
                 this, SLOT( dockWidgetVisibilityChanged(DockableWidget*) ) );
 
909
        connect( this, SIGNAL( debuggablesChanged(const QMap<QString,int>&) ),
 
910
                 viewer, SLOT( setDebuggables(const QMap<QString,int>&) ) );
 
911
        connect( this, SIGNAL( emulationChanged() ),
 
912
                 viewer, SLOT( refresh() ) );
 
913
        viewer->setDebuggables( debuggables );
 
914
        viewer->setEnabled( disasmView->isEnabled() );
 
915
}
 
916
 
 
917
void DebuggerForm::dockWidgetVisibilityChanged( DockableWidget *w )
 
918
{
 
919
        dockMan.visibilityChanged( w );
 
920
        updateViewMenu();
 
921
}
 
922
 
 
923
void DebuggerForm::updateViewMenu()
 
924
{
 
925
        viewRegistersAction->setChecked( regsView->parentWidget()->isVisible() );
 
926
        viewFlagsAction->setChecked( flagsView->isVisible() );
 
927
        viewStackAction->setChecked( stackView->isVisible() );
 
928
        viewSlotsAction->setChecked( slotView->isVisible() );
 
929
        viewMemoryAction->setChecked( hexView->isVisible() );
 
930
}
 
931
 
 
932
void DebuggerForm::setDebuggables( const QString& list )
 
933
{
 
934
        debuggables.clear();
 
935
 
 
936
        // process result string
 
937
        QStringList l = list.split(" ", QString::SkipEmptyParts);
 
938
        QString d;
 
939
        for( int i = 0; i < l.size(); i++ ) {
 
940
                d = l[i];
 
941
                // combine multiple words
 
942
                if( d[0] == '{' ) {
 
943
                        while( !d.endsWith("}") ) {
 
944
                                d.push_back(' ');
 
945
                                d.append( l[++i] );
 
946
                        }
 
947
                }
 
948
                // set initial size to zero
 
949
                debuggables[d] = 0;
 
950
        }
 
951
        // find the size for all debuggables
 
952
        QMap<QString,int>::iterator it = debuggables.begin();
 
953
        while( it != debuggables.end() ) {
 
954
                comm.sendCommand(new DebuggableSizeHandler(it.key(), *this));
 
955
                it++;
 
956
        }
 
957
}
 
958
 
 
959
void DebuggerForm::setDebuggableSize(  const QString& debuggable, int size )
 
960
{
 
961
        debuggables[debuggable] = size;
 
962
        // emit update if size of last debuggable was set
 
963
        if( debuggable == debuggables.keys().last() )
 
964
                emit debuggablesChanged( debuggables );
 
965
}