Added multiple breakpoints feature and their key bindings
[clinton/Virtual-Jaguar-Rx.git] / src / gui / debug / cpubrowser.cpp
1 //
2 // cpubrowser.cpp - Jaguar CPU browser
3 //
4 // by James Hammons
5 // (C) 2012 Underground Software
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 // JPM = Jean-Paul Mari <djipi.mari@gmail.com>
9 //
10 // Who When What
11 // --- ---------- -----------------------------------------------------------
12 // JLH 08/14/2012 Created this file
13 // JPM 08/09/2017 Added windows display detection in order to avoid the refresh
14 // JPM 10/13/2018 Added BPM hit counts
15 //
16
17 // STILL TO DO:
18 //
19
20 #include "cpubrowser.h"
21 //#include "memory.h"
22 #include "m68000/m68kinterface.h"
23 #include "dsp.h"
24 #include "gpu.h"
25 #include "jaguar.h"
26
27
28 CPUBrowserWindow::CPUBrowserWindow(QWidget * parent/*= 0*/): QWidget(parent, Qt::Dialog),
29 layout(new QVBoxLayout), text(new QLabel),
30 refresh(new QPushButton(tr("Refresh"))),
31 bpm(new QCheckBox(tr("BPM"))), bpmAddress(new QLineEdit),
32 bpmContinue(new QPushButton(tr("Resume")))
33 {
34 setWindowTitle(tr("CPU Browser"));
35
36 // Need to set the size as well...
37 // resize(560, 480);
38
39 // Limit input to 6 hex digits
40 bpmAddress->setInputMask("hhhhhh");
41 QHBoxLayout * hbox1 = new QHBoxLayout;
42 hbox1->addWidget(bpm);
43 hbox1->addWidget(bpmAddress);
44 hbox1->addWidget(bpmContinue);
45
46 QFont fixedFont("Lucida Console", 8, QFont::Normal);
47 // QFont fixedFont("", 8, QFont::Normal);
48 fixedFont.setStyleHint(QFont::TypeWriter);
49 text->setFont(fixedFont);
50 //// layout->setSizeConstraint(QLayout::SetFixedSize);
51 setLayout(layout);
52
53 layout->addWidget(text);
54 layout->addLayout(hbox1);
55 layout->addWidget(refresh);
56
57 connect(refresh, SIGNAL(clicked()), this, SLOT(RefreshContents()));
58 connect(bpm, SIGNAL(clicked(bool)), this, SLOT(HandleBPM(bool)));
59 connect(bpmAddress, SIGNAL(textChanged(const QString &)), this, SLOT(HandleBPMAddress(const QString &)));
60 connect(bpmContinue, SIGNAL(clicked()), this, SLOT(HandleBPMContinue()));
61 }
62
63
64 void CPUBrowserWindow::RefreshContents(void)
65 {
66 char string[2048];
67 QString s;
68
69 if (isVisible())
70 {
71 // 68K
72 uint32_t m68kPC = m68k_get_reg(NULL, M68K_REG_PC);
73 uint32_t m68kSR = m68k_get_reg(NULL, M68K_REG_SR);
74 sprintf(string, "PC: %06X&nbsp;&nbsp;SR: %04X<br><br>", m68kPC, m68kSR);
75 s += QString(string);
76 /*
77 SR format:
78 +--+--+--+--+ +--+--+--+--+ +--+--+--+--+ +--+--+--+--+
79 |T1|T0| S| M| |--|I2|I1|I0| |--|--|--| X| | N| Z| V| C|
80 +--+--+--+--+ +--+--+--+--+ +--+--+--+--+ +--+--+--+--+
81 T - Trace (T1 only in 68K, T0 = 0)
82 S - Supervisor flag
83 M - Master/Interrupt flag (= 0 in 68K)
84 I - Interrupt level mask
85 X - Extend flag
86 N - Negative flag
87 Z - Zero flag
88 V - Overflow flag
89 C - Carry flag
90 */
91
92 uint32_t m68kA0 = m68k_get_reg(NULL, M68K_REG_A0);
93 uint32_t m68kA1 = m68k_get_reg(NULL, M68K_REG_A1);
94 uint32_t m68kA2 = m68k_get_reg(NULL, M68K_REG_A2);
95 uint32_t m68kA3 = m68k_get_reg(NULL, M68K_REG_A3);
96 sprintf(string, "A0: %08X&nbsp;&nbsp;A1: %08X&nbsp;&nbsp;A2: %08X&nbsp;&nbsp;A3: %08X<br>", m68kA0, m68kA1, m68kA2, m68kA3);
97 s += QString(string);
98
99 uint32_t m68kA4 = m68k_get_reg(NULL, M68K_REG_A4);
100 uint32_t m68kA5 = m68k_get_reg(NULL, M68K_REG_A5);
101 uint32_t m68kA6 = m68k_get_reg(NULL, M68K_REG_A6);
102 uint32_t m68kA7 = m68k_get_reg(NULL, M68K_REG_A7);
103 sprintf(string, "A4: %08X&nbsp;&nbsp;A5: %08X&nbsp;&nbsp;A6: %08X&nbsp;&nbsp;A7: %08X<br><br>", m68kA4, m68kA5, m68kA6, m68kA7);
104 s += QString(string);
105
106 uint32_t m68kD0 = m68k_get_reg(NULL, M68K_REG_D0);
107 uint32_t m68kD1 = m68k_get_reg(NULL, M68K_REG_D1);
108 uint32_t m68kD2 = m68k_get_reg(NULL, M68K_REG_D2);
109 uint32_t m68kD3 = m68k_get_reg(NULL, M68K_REG_D3);
110 sprintf(string, "D0: %08X&nbsp;&nbsp;D1: %08X&nbsp;&nbsp;D2: %08X&nbsp;&nbsp;D3: %08X<br>", m68kD0, m68kD1, m68kD2, m68kD3);
111 s += QString(string);
112
113 uint32_t m68kD4 = m68k_get_reg(NULL, M68K_REG_D4);
114 uint32_t m68kD5 = m68k_get_reg(NULL, M68K_REG_D5);
115 uint32_t m68kD6 = m68k_get_reg(NULL, M68K_REG_D6);
116 uint32_t m68kD7 = m68k_get_reg(NULL, M68K_REG_D7);
117 sprintf(string, "D4: %08X&nbsp;&nbsp;D5: %08X&nbsp;&nbsp;D6: %08X&nbsp;&nbsp;D7: %08X<br><br>", m68kD4, m68kD5, m68kD6, m68kD7);
118 s += QString(string);
119
120 // GPU
121 sprintf(string, "GPU PC: %06X&nbsp;&nbsp;FLAGS: %04X&nbsp;&nbsp;SR: %04X<br><br>", GPUReadLong(0xF02110, DEBUG), GPUReadLong(0xF02100, DEBUG), GPUReadLong(0xF02114, DEBUG));
122 s += QString(string);
123 /*
124 GPU Flags:
125 0 - Zero flag
126 1 - Carry flag
127 2 - Negative flag
128 3 - IMASK (writing 0 clears, 1 has no effect)
129 4-8 - IRQ enable 0 - 4
130 9-13 - IRQ latch clear 0 - 4
131 14 - REGPAGE
132 15 - DMAEN
133
134 GPU Control:
135 0 - GPU Go
136 1 - CPUINT
137 2 - GPUINT0
138 3 - Single Step
139 4 - Single step go
140 5 - Unused
141 6-10 - IRQ Latch 0 - 4
142 11 - Bus Hog
143 12-15 - Version
144 */
145
146 sprintf(string, "Bank 0:<br>"
147 "R00: %08X&nbsp;&nbsp;R01: %08X&nbsp;&nbsp;R02: %08X&nbsp;&nbsp;R03: %08X<br>"
148 "R04: %08X&nbsp;&nbsp;R05: %08X&nbsp;&nbsp;R06: %08X&nbsp;&nbsp;R07: %08X<br>"
149 "R08: %08X&nbsp;&nbsp;R09: %08X&nbsp;&nbsp;R10: %08X&nbsp;&nbsp;R11: %08X<br>"
150 "R12: %08X&nbsp;&nbsp;R13: %08X&nbsp;&nbsp;R14: %08X&nbsp;&nbsp;R15: %08X<br>"
151 "R16: %08X&nbsp;&nbsp;R17: %08X&nbsp;&nbsp;R18: %08X&nbsp;&nbsp;R19: %08X<br>"
152 "R20: %08X&nbsp;&nbsp;R21: %08X&nbsp;&nbsp;R22: %08X&nbsp;&nbsp;R23: %08X<br>"
153 "R24: %08X&nbsp;&nbsp;R25: %08X&nbsp;&nbsp;R26: %08X&nbsp;&nbsp;R27: %08X<br>"
154 "R28: %08X&nbsp;&nbsp;R29: %08X&nbsp;&nbsp;R30: %08X&nbsp;&nbsp;R31: %08X<br><br>",
155 gpu_reg_bank_0[0], gpu_reg_bank_0[1], gpu_reg_bank_0[2], gpu_reg_bank_0[3],
156 gpu_reg_bank_0[4], gpu_reg_bank_0[5], gpu_reg_bank_0[6], gpu_reg_bank_0[7],
157 gpu_reg_bank_0[8], gpu_reg_bank_0[9], gpu_reg_bank_0[10], gpu_reg_bank_0[11],
158 gpu_reg_bank_0[12], gpu_reg_bank_0[13], gpu_reg_bank_0[14], gpu_reg_bank_0[15],
159 gpu_reg_bank_0[16], gpu_reg_bank_0[17], gpu_reg_bank_0[18], gpu_reg_bank_0[19],
160 gpu_reg_bank_0[20], gpu_reg_bank_0[21], gpu_reg_bank_0[22], gpu_reg_bank_0[23],
161 gpu_reg_bank_0[24], gpu_reg_bank_0[25], gpu_reg_bank_0[26], gpu_reg_bank_0[27],
162 gpu_reg_bank_0[28], gpu_reg_bank_0[29], gpu_reg_bank_0[30], gpu_reg_bank_0[31]);
163 s += QString(string);
164
165 sprintf(string, "Bank 1:<br>"
166 "R00: %08X&nbsp;&nbsp;R01: %08X&nbsp;&nbsp;R02: %08X&nbsp;&nbsp;R03: %08X<br>"
167 "R04: %08X&nbsp;&nbsp;R05: %08X&nbsp;&nbsp;R06: %08X&nbsp;&nbsp;R07: %08X<br>"
168 "R08: %08X&nbsp;&nbsp;R09: %08X&nbsp;&nbsp;R10: %08X&nbsp;&nbsp;R11: %08X<br>"
169 "R12: %08X&nbsp;&nbsp;R13: %08X&nbsp;&nbsp;R14: %08X&nbsp;&nbsp;R15: %08X<br>"
170 "R16: %08X&nbsp;&nbsp;R17: %08X&nbsp;&nbsp;R18: %08X&nbsp;&nbsp;R19: %08X<br>"
171 "R20: %08X&nbsp;&nbsp;R21: %08X&nbsp;&nbsp;R22: %08X&nbsp;&nbsp;R23: %08X<br>"
172 "R24: %08X&nbsp;&nbsp;R25: %08X&nbsp;&nbsp;R26: %08X&nbsp;&nbsp;R27: %08X<br>"
173 "R28: %08X&nbsp;&nbsp;R29: %08X&nbsp;&nbsp;R30: %08X&nbsp;&nbsp;R31: %08X<br><br>",
174 gpu_reg_bank_1[0], gpu_reg_bank_1[1], gpu_reg_bank_1[2], gpu_reg_bank_1[3],
175 gpu_reg_bank_1[4], gpu_reg_bank_1[5], gpu_reg_bank_1[6], gpu_reg_bank_1[7],
176 gpu_reg_bank_1[8], gpu_reg_bank_1[9], gpu_reg_bank_1[10], gpu_reg_bank_1[11],
177 gpu_reg_bank_1[12], gpu_reg_bank_1[13], gpu_reg_bank_1[14], gpu_reg_bank_1[15],
178 gpu_reg_bank_1[16], gpu_reg_bank_1[17], gpu_reg_bank_1[18], gpu_reg_bank_1[19],
179 gpu_reg_bank_1[20], gpu_reg_bank_1[21], gpu_reg_bank_1[22], gpu_reg_bank_1[23],
180 gpu_reg_bank_1[24], gpu_reg_bank_1[25], gpu_reg_bank_1[26], gpu_reg_bank_1[27],
181 gpu_reg_bank_1[28], gpu_reg_bank_1[29], gpu_reg_bank_1[30], gpu_reg_bank_1[31]);
182 s += QString(string);
183
184 // DSP
185 sprintf(string, "DSP PC: %06X&nbsp;&nbsp;FLAGS: %05X&nbsp;&nbsp;SR: %05X<br><br>", DSPReadLong(0xF1A110, DEBUG), DSPReadLong(0xF1A100, DEBUG), DSPReadLong(0xF1A114, DEBUG));
186 s += QString(string);
187 /*
188 DSP Flags:
189 0 - Zero flag
190 1 - Carry flag
191 2 - Negative flag
192 3 - IMASK (writing 0 clears, 1 has no effect)
193 4-8 - IRQ enable 0 - 4
194 9-13 - IRQ latch clear 0 - 4
195 14 - REGPAGE
196 15 - DMAEN
197 16 - IRQ enable 5
198 17 - IRQ latch clear 5
199
200 DSP Control:
201 0 - DSP Go
202 1 - CPUINT
203 2 - DSPINT0
204 3 - Single Step
205 4 - Single step go
206 5 - Unused
207 6-10 - IRQ Latch 0 - 4
208 11 - Bus Hog
209 12-15 - Version
210 16 - IRQ Latch 5
211 */
212
213 sprintf(string, "Bank 0:<br>"
214 "R00: %08X&nbsp;&nbsp;R01: %08X&nbsp;&nbsp;R02: %08X&nbsp;&nbsp;R03: %08X<br>"
215 "R04: %08X&nbsp;&nbsp;R05: %08X&nbsp;&nbsp;R06: %08X&nbsp;&nbsp;R07: %08X<br>"
216 "R08: %08X&nbsp;&nbsp;R09: %08X&nbsp;&nbsp;R10: %08X&nbsp;&nbsp;R11: %08X<br>"
217 "R12: %08X&nbsp;&nbsp;R13: %08X&nbsp;&nbsp;R14: %08X&nbsp;&nbsp;R15: %08X<br>"
218 "R16: %08X&nbsp;&nbsp;R17: %08X&nbsp;&nbsp;R18: %08X&nbsp;&nbsp;R19: %08X<br>"
219 "R20: %08X&nbsp;&nbsp;R21: %08X&nbsp;&nbsp;R22: %08X&nbsp;&nbsp;R23: %08X<br>"
220 "R24: %08X&nbsp;&nbsp;R25: %08X&nbsp;&nbsp;R26: %08X&nbsp;&nbsp;R27: %08X<br>"
221 "R28: %08X&nbsp;&nbsp;R29: %08X&nbsp;&nbsp;R30: %08X&nbsp;&nbsp;R31: %08X<br><br>",
222 dsp_reg_bank_0[0], dsp_reg_bank_0[1], dsp_reg_bank_0[2], dsp_reg_bank_0[3],
223 dsp_reg_bank_0[4], dsp_reg_bank_0[5], dsp_reg_bank_0[6], dsp_reg_bank_0[7],
224 dsp_reg_bank_0[8], dsp_reg_bank_0[9], dsp_reg_bank_0[10], dsp_reg_bank_0[11],
225 dsp_reg_bank_0[12], dsp_reg_bank_0[13], dsp_reg_bank_0[14], dsp_reg_bank_0[15],
226 dsp_reg_bank_0[16], dsp_reg_bank_0[17], dsp_reg_bank_0[18], dsp_reg_bank_0[19],
227 dsp_reg_bank_0[20], dsp_reg_bank_0[21], dsp_reg_bank_0[22], dsp_reg_bank_0[23],
228 dsp_reg_bank_0[24], dsp_reg_bank_0[25], dsp_reg_bank_0[26], dsp_reg_bank_0[27],
229 dsp_reg_bank_0[28], dsp_reg_bank_0[29], dsp_reg_bank_0[30], dsp_reg_bank_0[31]);
230 s += QString(string);
231
232 sprintf(string, "Bank 1:<br>"
233 "R00: %08X&nbsp;&nbsp;R01: %08X&nbsp;&nbsp;R02: %08X&nbsp;&nbsp;R03: %08X<br>"
234 "R04: %08X&nbsp;&nbsp;R05: %08X&nbsp;&nbsp;R06: %08X&nbsp;&nbsp;R07: %08X<br>"
235 "R08: %08X&nbsp;&nbsp;R09: %08X&nbsp;&nbsp;R10: %08X&nbsp;&nbsp;R11: %08X<br>"
236 "R12: %08X&nbsp;&nbsp;R13: %08X&nbsp;&nbsp;R14: %08X&nbsp;&nbsp;R15: %08X<br>"
237 "R16: %08X&nbsp;&nbsp;R17: %08X&nbsp;&nbsp;R18: %08X&nbsp;&nbsp;R19: %08X<br>"
238 "R20: %08X&nbsp;&nbsp;R21: %08X&nbsp;&nbsp;R22: %08X&nbsp;&nbsp;R23: %08X<br>"
239 "R24: %08X&nbsp;&nbsp;R25: %08X&nbsp;&nbsp;R26: %08X&nbsp;&nbsp;R27: %08X<br>"
240 "R28: %08X&nbsp;&nbsp;R29: %08X&nbsp;&nbsp;R30: %08X&nbsp;&nbsp;R31: %08X<br>",
241 dsp_reg_bank_1[0], dsp_reg_bank_1[1], dsp_reg_bank_1[2], dsp_reg_bank_1[3],
242 dsp_reg_bank_1[4], dsp_reg_bank_1[5], dsp_reg_bank_1[6], dsp_reg_bank_1[7],
243 dsp_reg_bank_1[8], dsp_reg_bank_1[9], dsp_reg_bank_1[10], dsp_reg_bank_1[11],
244 dsp_reg_bank_1[12], dsp_reg_bank_1[13], dsp_reg_bank_1[14], dsp_reg_bank_1[15],
245 dsp_reg_bank_1[16], dsp_reg_bank_1[17], dsp_reg_bank_1[18], dsp_reg_bank_1[19],
246 dsp_reg_bank_1[20], dsp_reg_bank_1[21], dsp_reg_bank_1[22], dsp_reg_bank_1[23],
247 dsp_reg_bank_1[24], dsp_reg_bank_1[25], dsp_reg_bank_1[26], dsp_reg_bank_1[27],
248 dsp_reg_bank_1[28], dsp_reg_bank_1[29], dsp_reg_bank_1[30], dsp_reg_bank_1[31]);
249 s += QString(string);
250
251 text->clear();
252 text->setText(s);
253 }
254 }
255
256
257 //
258 void CPUBrowserWindow::HoldBPM(void)
259 {
260 bpmSaveActive = bpmActive;
261 bpmActive = false;
262 }
263
264
265 //
266 void CPUBrowserWindow::UnholdBPM(void)
267 {
268 bpmActive = bpmSaveActive;
269 }
270
271
272 // Disable BPM
273 void CPUBrowserWindow::DisableBPM(void)
274 {
275 // Uncheck the BPM checkbox and handle BPM
276 if (bpm->checkState())
277 {
278 bpm->setCheckState(Qt::Unchecked);
279 }
280 HandleBPM(false);
281 }
282
283
284 // BPM reset
285 // Disable checkbox and breakpoint address
286 void CPUBrowserWindow::ResetBPM(void)
287 {
288 DisableBPM();
289 bpmAddress->setText("");
290 }
291
292
293 // Toggle breakpoint set
294 void CPUBrowserWindow::HandleBPM(bool state)
295 {
296 bpmSaveActive = bpmActive = state;
297 bpmHitCounts = 0;
298
299 if (bpmActive)
300 {
301 printf("BPM Set: $%06X\n", bpmAddress1);
302 }
303 else
304 {
305 printf("BPM Unset: $%06X\n", bpmAddress1);
306 }
307 }
308
309
310 // Breakpoint address set and reset the hit counts
311 void CPUBrowserWindow::HandleBPMAddress(const QString & newText)
312 {
313 bool ok;
314 bpmAddress1 = newText.toUInt(&ok, 16);
315 }
316
317
318 void CPUBrowserWindow::HandleBPMContinue(void)
319 {
320 M68KDebugResume();
321 }
322
323
324 //
325 void CPUBrowserWindow::keyPressEvent(QKeyEvent * e)
326 {
327 if (e->key() == Qt::Key_Escape)
328 {
329 hide();
330 }
331 else
332 {
333 if (e->key() == Qt::Key_Return)
334 {
335 HandleBPM(true);
336 bpm->setChecked(true);
337 }
338 #if 0
339 else if (e->key() == Qt::Key_PageUp)
340 {
341 memBase -= 480;
342
343 if (memBase < 0)
344 memBase = 0;
345
346 RefreshContents();
347 }
348 else if (e->key() == Qt::Key_PageDown)
349 {
350 memBase += 480;
351
352 if (memBase > (0x200000 - 480))
353 memBase = 0x200000 - 480;
354
355 RefreshContents();
356 }
357 else if (e->key() == Qt::Key_Up || e->key() == Qt::Key_Minus)
358 {
359 memBase -= 16;
360
361 if (memBase < 0)
362 memBase = 0;
363
364 RefreshContents();
365 }
366 else if (e->key() == Qt::Key_Down || e->key() == Qt::Key_Equal)
367 {
368 memBase += 16;
369
370 if (memBase > (0x200000 - 480))
371 memBase = 0x200000 - 480;
372
373 RefreshContents();
374 }
375 #endif
376 }
377 }
378