| 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 SR: %04X : %c%c%c%c%c%c%c<br><br>", m68kPC, m68kSR, ((m68kSR & 0x8000) ? 'T': '-'), ((m68kSR & 0x2000) ? 'S' : '-'), ((m68kSR & 0x10) ? 'X' : '-'), ((m68kSR & 0x8) ? 'N' : '-'), ((m68kSR & 0x4) ? 'Z' : '-'), ((m68kSR & 0x2) ? 'V' : '-'), ((m68kSR & 0x1) ? 'C' : '-')); |
| 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 A1: %08X A2: %08X 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 A5: %08X A6: %08X 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 D1: %08X D2: %08X 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 D5: %08X D6: %08X D7: %08X<br><br>", m68kD4, m68kD5, m68kD6, m68kD7); |
| 118 | s += QString(string); |
| 119 | |
| 120 | // GPU |
| 121 | sprintf(string, "GPU PC: %06X FLAGS: %04X 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 R01: %08X R02: %08X R03: %08X<br>" |
| 148 | "R04: %08X R05: %08X R06: %08X R07: %08X<br>" |
| 149 | "R08: %08X R09: %08X R10: %08X R11: %08X<br>" |
| 150 | "R12: %08X R13: %08X R14: %08X R15: %08X<br>" |
| 151 | "R16: %08X R17: %08X R18: %08X R19: %08X<br>" |
| 152 | "R20: %08X R21: %08X R22: %08X R23: %08X<br>" |
| 153 | "R24: %08X R25: %08X R26: %08X R27: %08X<br>" |
| 154 | "R28: %08X R29: %08X R30: %08X 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 R01: %08X R02: %08X R03: %08X<br>" |
| 167 | "R04: %08X R05: %08X R06: %08X R07: %08X<br>" |
| 168 | "R08: %08X R09: %08X R10: %08X R11: %08X<br>" |
| 169 | "R12: %08X R13: %08X R14: %08X R15: %08X<br>" |
| 170 | "R16: %08X R17: %08X R18: %08X R19: %08X<br>" |
| 171 | "R20: %08X R21: %08X R22: %08X R23: %08X<br>" |
| 172 | "R24: %08X R25: %08X R26: %08X R27: %08X<br>" |
| 173 | "R28: %08X R29: %08X R30: %08X 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 FLAGS: %05X 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 R01: %08X R02: %08X R03: %08X<br>" |
| 215 | "R04: %08X R05: %08X R06: %08X R07: %08X<br>" |
| 216 | "R08: %08X R09: %08X R10: %08X R11: %08X<br>" |
| 217 | "R12: %08X R13: %08X R14: %08X R15: %08X<br>" |
| 218 | "R16: %08X R17: %08X R18: %08X R19: %08X<br>" |
| 219 | "R20: %08X R21: %08X R22: %08X R23: %08X<br>" |
| 220 | "R24: %08X R25: %08X R26: %08X R27: %08X<br>" |
| 221 | "R28: %08X R29: %08X R30: %08X 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 R01: %08X R02: %08X R03: %08X<br>" |
| 234 | "R04: %08X R05: %08X R06: %08X R07: %08X<br>" |
| 235 | "R08: %08X R09: %08X R10: %08X R11: %08X<br>" |
| 236 | "R12: %08X R13: %08X R14: %08X R15: %08X<br>" |
| 237 | "R16: %08X R17: %08X R18: %08X R19: %08X<br>" |
| 238 | "R20: %08X R21: %08X R22: %08X R23: %08X<br>" |
| 239 | "R24: %08X R25: %08X R26: %08X R27: %08X<br>" |
| 240 | "R28: %08X R29: %08X R30: %08X 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 | |