CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Windows/Debugger/CtrlRegisterList.cpp
Views: 1401
1
#include <cmath>
2
#include <tchar.h>
3
4
#include "Common/System/Display.h"
5
#include "Common/Data/Encoding/Utf8.h"
6
#include "Core/Config.h"
7
#include "Core/MemMap.h"
8
#include "Core/Reporting.h"
9
#include "Windows/W32Util/ContextMenu.h"
10
#include "Windows/W32Util/Misc.h"
11
#include "Windows/InputBox.h"
12
#include "Windows/resource.h"
13
14
#include "CtrlRegisterList.h"
15
#include "Debugger_MemoryDlg.h"
16
17
#include "Debugger_Disasm.h"
18
#include "DebuggerShared.h"
19
20
#include "Windows/main.h"
21
22
enum { REGISTER_PC = 32, REGISTER_HI, REGISTER_LO, REGISTERS_END };
23
24
TCHAR CtrlRegisterList::szClassName[] = _T("CtrlRegisterList");
25
26
static constexpr UINT_PTR IDT_REDRAW = 0xC0DE0001;
27
static constexpr UINT REDRAW_DELAY = 1000 / 60;
28
29
void CtrlRegisterList::init()
30
{
31
WNDCLASSEX wc;
32
33
wc.cbSize = sizeof(wc);
34
wc.lpszClassName = szClassName;
35
wc.hInstance = GetModuleHandle(0);
36
wc.lpfnWndProc = CtrlRegisterList::wndProc;
37
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
38
wc.hIcon = 0;
39
wc.lpszMenuName = 0;
40
wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);
41
wc.style = CS_DBLCLKS;
42
wc.cbClsExtra = 0;
43
wc.cbWndExtra = sizeof(CtrlRegisterList *);
44
wc.hIconSm = 0;
45
46
RegisterClassEx(&wc);
47
}
48
49
void CtrlRegisterList::deinit()
50
{
51
//UnregisterClass(szClassName, hInst)
52
}
53
54
LRESULT CALLBACK CtrlRegisterList::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
55
{
56
CtrlRegisterList *ccp = CtrlRegisterList::getFrom(hwnd);
57
static bool lmbDown=false,rmbDown=false;
58
switch(msg)
59
{
60
case WM_NCCREATE:
61
// Allocate a new CustCtrl structure for this window.
62
ccp = new CtrlRegisterList(hwnd);
63
64
// Continue with window creation.
65
return ccp != NULL;
66
67
// Clean up when the window is destroyed.
68
case WM_NCDESTROY:
69
delete ccp;
70
break;
71
case WM_SETFONT:
72
break;
73
case WM_SIZE:
74
ccp->redraw();
75
break;
76
case WM_PAINT:
77
ccp->onPaint(wParam,lParam);
78
break;
79
/*
80
case WM_VSCROLL:
81
ccp->onVScroll(wParam,lParam);
82
break;*/
83
case WM_ERASEBKGND:
84
return FALSE;
85
case WM_KEYDOWN:
86
ccp->onKeyDown(wParam,lParam);
87
return 0;
88
case WM_KEYUP:
89
if (wParam == VK_CONTROL) ccp->ctrlDown = false;
90
return 0;
91
case WM_LBUTTONDOWN: SetFocus(hwnd); lmbDown=true; ccp->onMouseDown(wParam,lParam,1); break;
92
case WM_RBUTTONDOWN: rmbDown=true; ccp->onMouseDown(wParam,lParam,2); break;
93
case WM_MOUSEMOVE: ccp->onMouseMove(wParam,lParam,(lmbDown?1:0) | (rmbDown?2:0)); break;
94
case WM_LBUTTONUP: lmbDown=false; ccp->onMouseUp(wParam,lParam,1); break;
95
case WM_RBUTTONUP: rmbDown=false; ccp->onMouseUp(wParam,lParam,2); break;
96
case WM_LBUTTONDBLCLK: ccp->editRegisterValue(); break;
97
case WM_SETFOCUS:
98
SetFocus(hwnd);
99
ccp->hasFocus=true;
100
ccp->redraw();
101
break;
102
case WM_KILLFOCUS:
103
ccp->hasFocus=false;
104
ccp->redraw();
105
break;
106
case WM_GETDLGCODE: // want chars so that we can return 0 on key press and supress the beeping sound
107
return DLGC_WANTARROWS|DLGC_WANTCHARS;
108
109
case WM_TIMER:
110
if (wParam == IDT_REDRAW) {
111
InvalidateRect(hwnd, nullptr, FALSE);
112
UpdateWindow(hwnd);
113
ccp->redrawScheduled_ = false;
114
KillTimer(hwnd, wParam);
115
}
116
break;
117
118
default:
119
break;
120
}
121
122
return DefWindowProc(hwnd, msg, wParam, lParam);
123
}
124
125
CtrlRegisterList *CtrlRegisterList::getFrom(HWND hwnd)
126
{
127
return (CtrlRegisterList *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
128
}
129
130
CtrlRegisterList::CtrlRegisterList(HWND _wnd)
131
: wnd(_wnd) {
132
SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)this);
133
134
const float fontScale = 1.0f / g_display.dpi_scale_real_y;
135
rowHeight = g_Config.iFontHeight * fontScale;
136
int charWidth = g_Config.iFontWidth * fontScale;
137
font = CreateFont(rowHeight, charWidth, 0, 0,
138
FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH,
139
L"Lucida Console");
140
}
141
142
CtrlRegisterList::~CtrlRegisterList()
143
{
144
DeleteObject(font);
145
delete [] lastCat0Values;
146
delete [] changedCat0Regs;
147
}
148
149
void fillRect(HDC hdc, RECT *rect, COLORREF colour);
150
151
152
153
//Yeah this truly turned into a mess with the latest additions.. but it sure looks nice ;)
154
void CtrlRegisterList::onPaint(WPARAM wParam, LPARAM lParam)
155
{
156
if (!cpu)
157
return;
158
159
GetClientRect(wnd, &rect);
160
PAINTSTRUCT ps;
161
HDC hdc;
162
163
hdc = BeginPaint(wnd, &ps);
164
// TODO: Add any drawing code here...
165
int width = rect.right;
166
//numRows=(numRows&(~1)) + 1;
167
SetBkMode(hdc, TRANSPARENT);
168
DWORD bgColor = 0xffffff;
169
HPEN nullPen=CreatePen(0,0,bgColor);
170
HPEN currentPen=CreatePen(0,0,0);
171
HPEN selPen=CreatePen(0,0,0x808080);
172
173
LOGBRUSH lbr;
174
lbr.lbHatch=0; lbr.lbStyle=0;
175
lbr.lbColor=bgColor;
176
HBRUSH nullBrush=CreateBrushIndirect(&lbr);
177
lbr.lbColor=0xFFEfE8;
178
HBRUSH currentBrush=CreateBrushIndirect(&lbr);
179
lbr.lbColor=0x70FF70;
180
HBRUSH pcBrush=CreateBrushIndirect(&lbr);
181
182
HPEN oldPen=(HPEN)SelectObject(hdc,nullPen);
183
HBRUSH oldBrush=(HBRUSH)SelectObject(hdc,nullBrush);
184
185
186
HFONT oldFont = (HFONT)SelectObject(hdc,(HGDIOBJ)font);
187
// HICON breakPoint = (HICON)LoadIcon(GetModuleHandle(0),(LPCSTR)IDI_STOP);
188
// HICON breakPointDisable = (HICON)LoadIcon(GetModuleHandle(0),(LPCSTR)IDI_STOPDISABLE);
189
190
int nc = cpu->GetNumCategories();
191
for (int i=0; i<nc; i++)
192
{
193
SelectObject(hdc,i==category?currentPen:nullPen);
194
SelectObject(hdc,i==category?pcBrush:nullBrush);
195
Rectangle(hdc,width*i/nc,0,width*(i+1)/nc,rowHeight);
196
const char *name = cpu->GetCategoryName(i);
197
TextOutA(hdc,width*i/nc,1,name,(int)strlen(name));
198
}
199
200
int numRows=rect.bottom/rowHeight;
201
202
for (int i=0; i<numRows; i++)
203
{
204
int rowY1 = rowHeight*(i+1);
205
int rowY2 = rowHeight*(i+2);
206
207
208
lbr.lbColor = i==selection?0xffeee0:0xffffff;
209
210
SelectObject(hdc,currentBrush);
211
SelectObject(hdc,nullPen);
212
Rectangle(hdc,0,rowY1,16,rowY2);
213
214
if (selecting && i == selection)
215
SelectObject(hdc,selPen);
216
else
217
SelectObject(hdc,nullPen);
218
219
HBRUSH mojsBrush=CreateBrushIndirect(&lbr);
220
SelectObject(hdc,mojsBrush);
221
222
//else
223
// SelectObject(hdc,i==0 ? currentBrush : nullBrush);
224
225
Rectangle(hdc,16,rowY1,width,rowY2);
226
227
// Check for any changes in the registers.
228
if (lastPC != cpu->GetPC())
229
{
230
for (int j = 0, n = cpu->GetNumRegsInCategory(0); j < n; ++j)
231
{
232
u32 v = cpu->GetRegValue(0, j);
233
changedCat0Regs[j] = v != lastCat0Values[j];
234
lastCat0Values[j] = v;
235
}
236
237
changedCat0Regs[REGISTER_PC] = cpu->GetPC() != lastCat0Values[REGISTER_PC];
238
lastCat0Values[REGISTER_PC] = cpu->GetPC();
239
changedCat0Regs[REGISTER_HI] = cpu->GetHi() != lastCat0Values[REGISTER_HI];
240
lastCat0Values[REGISTER_HI] = cpu->GetHi();
241
changedCat0Regs[REGISTER_LO] = cpu->GetLo() != lastCat0Values[REGISTER_LO];
242
lastCat0Values[REGISTER_LO] = cpu->GetLo();
243
244
lastPC = cpu->GetPC();
245
}
246
247
SelectObject(hdc,currentBrush);
248
DeleteObject(mojsBrush);
249
if (i<cpu->GetNumRegsInCategory(category))
250
{
251
char temp[256];
252
int temp_len = snprintf(temp, sizeof(temp), "%s", cpu->GetRegName(category, i).c_str());
253
SetTextColor(hdc,0x600000);
254
TextOutA(hdc,17,rowY1,temp,temp_len);
255
SetTextColor(hdc,0x000000);
256
257
cpu->PrintRegValue(category, i, temp, sizeof(temp));
258
if (category == 0 && changedCat0Regs[i])
259
SetTextColor(hdc, 0x0000FF);
260
else
261
SetTextColor(hdc,0x004000);
262
TextOutA(hdc,77,rowY1,temp,(int)strlen(temp));
263
} else if (category == 0 && i < REGISTERS_END)
264
{
265
char temp[256];
266
int len;
267
u32 value = -1;
268
269
switch (i)
270
{
271
case REGISTER_PC:
272
value = cpu->GetPC();
273
len = snprintf(temp, sizeof(temp), "pc");
274
break;
275
case REGISTER_HI:
276
value = cpu->GetHi();
277
len = snprintf(temp, sizeof(temp), "hi");
278
break;
279
case REGISTER_LO:
280
value = cpu->GetLo();
281
len = snprintf(temp, sizeof(temp), "lo");
282
break;
283
default:
284
temp[0] = '\0';
285
len = 0;
286
break;
287
}
288
289
SetTextColor(hdc,0x600000);
290
TextOutA(hdc,17,rowY1,temp,len);
291
len = snprintf(temp, sizeof(temp), "%08X",value);
292
if (changedCat0Regs[i])
293
SetTextColor(hdc, 0x0000FF);
294
else
295
SetTextColor(hdc,0x004000);
296
TextOutA(hdc,77,rowY1,temp,(int)strlen(temp));
297
}
298
}
299
300
SelectObject(hdc,oldFont);
301
SelectObject(hdc,oldPen);
302
SelectObject(hdc,oldBrush);
303
304
DeleteObject(nullPen);
305
DeleteObject(currentPen);
306
DeleteObject(selPen);
307
308
DeleteObject(nullBrush);
309
DeleteObject(pcBrush);
310
DeleteObject(currentBrush);
311
312
// DestroyIcon(breakPoint);
313
// DestroyIcon(breakPointDisable);
314
315
EndPaint(wnd, &ps);
316
}
317
318
319
320
void CtrlRegisterList::onKeyDown(WPARAM wParam, LPARAM lParam)
321
{
322
RECT rect;
323
GetClientRect(this->wnd, &rect);
324
325
if (ctrlDown && tolower(wParam) == 'c')
326
{
327
copyRegisterValue();
328
return;
329
}
330
331
switch (wParam & 0xFFFF)
332
{
333
case VK_DOWN:
334
selection++;
335
break;
336
case VK_UP:
337
selection--;
338
break;
339
case VK_NEXT:
340
selection+=4;
341
break;
342
case VK_PRIOR:
343
selection-=4;
344
break;
345
case VK_CONTROL:
346
ctrlDown = true;
347
break;
348
default:
349
return;
350
}
351
redraw();
352
}
353
354
355
void CtrlRegisterList::redraw() {
356
if (!redrawScheduled_) {
357
SetTimer(wnd, IDT_REDRAW, REDRAW_DELAY, nullptr);
358
redrawScheduled_ = true;
359
}
360
}
361
362
u32 CtrlRegisterList::getSelectedRegValue(char *out, size_t size)
363
{
364
int reg = selection;
365
u32 val;
366
367
if (selection >= cpu->GetNumRegsInCategory(category))
368
{
369
if (category != 0 || selection >= REGISTERS_END)
370
{
371
*out = '\0';
372
return -1;
373
}
374
375
switch (selection)
376
{
377
case REGISTER_PC:
378
val = cpu->GetPC();
379
break;
380
case REGISTER_HI:
381
val = cpu->GetHi();
382
break;
383
case REGISTER_LO:
384
val = cpu->GetLo();
385
break;
386
default:
387
*out = '\0';
388
return -1;
389
}
390
}
391
else
392
val = cpu->GetRegValue(category, reg);
393
394
snprintf(out, size, "%08X", val);
395
return val;
396
}
397
398
void CtrlRegisterList::copyRegisterValue()
399
{
400
if (!Core_IsStepping())
401
{
402
MessageBox(wnd,L"Can't copy register values while the core is running.",L"Error",MB_OK);
403
return;
404
}
405
406
char temp[24];
407
getSelectedRegValue(temp, 24);
408
W32Util::CopyTextToClipboard(wnd, temp);
409
}
410
411
void CtrlRegisterList::editRegisterValue()
412
{
413
if (!Core_IsStepping())
414
{
415
MessageBox(wnd,L"Can't change registers while the core is running.",L"Error",MB_OK);
416
return;
417
}
418
419
char temp[24];
420
u32 val = getSelectedRegValue(temp, 24);
421
int reg = selection;
422
423
std::string value = temp;
424
if (InputBox_GetString(GetModuleHandle(NULL),wnd,L"Set new value",value,value)) {
425
if (parseExpression(value.c_str(),cpu,val) == false) {
426
displayExpressionError(wnd);
427
} else {
428
switch (reg)
429
{
430
case REGISTER_PC:
431
cpu->SetPC(val);
432
break;
433
case REGISTER_HI:
434
cpu->SetHi(val);
435
break;
436
case REGISTER_LO:
437
cpu->SetLo(val);
438
break;
439
default:
440
cpu->SetRegValue(category, reg, val);
441
break;
442
}
443
Reporting::NotifyDebugger();
444
redraw();
445
SendMessage(GetParent(wnd),WM_DEB_UPDATE,0,0); // registers changed -> disassembly needs to be updated
446
}
447
}
448
}
449
450
void CtrlRegisterList::onMouseDown(WPARAM wParam, LPARAM lParam, int button)
451
{
452
int x = (s16)LOWORD(lParam);
453
int y = (s16)HIWORD(lParam);
454
if (x>16)
455
{
456
oldSelection=selection;
457
458
if (y>rowHeight)
459
{
460
selection=yToIndex(y);
461
SetCapture(wnd);
462
bool oldselecting=selecting;
463
selecting=true;
464
if (!oldselecting || (selection!=oldSelection))
465
redraw();
466
}
467
else
468
{
469
RECT rc;
470
SetCapture(wnd);
471
GetWindowRect(wnd,&rc);
472
int lastCat = category;
473
category = (x*cpu->GetNumCategories())/(rc.right-rc.left);
474
if (category<0) category=0;
475
if (category>=cpu->GetNumCategories())
476
category=cpu->GetNumCategories()-1;
477
if (category!=lastCat)
478
redraw();
479
}
480
}
481
else
482
{
483
redraw();
484
}
485
}
486
487
void CtrlRegisterList::onMouseUp(WPARAM wParam, LPARAM lParam, int button)
488
{
489
int x = LOWORD(lParam);
490
int y = HIWORD(lParam);
491
492
if (button==2 && x>16)
493
{
494
//popup menu?
495
int cat = category;
496
int reg = selection;
497
u32 val;
498
if (selection < cpu->GetNumRegsInCategory(cat))
499
{
500
val = cpu->GetRegValue(cat, reg);
501
}
502
else if (cat == 0 && selection < REGISTERS_END)
503
{
504
switch (selection)
505
{
506
case REGISTER_PC:
507
val = cpu->GetPC();
508
break;
509
case REGISTER_HI:
510
val = cpu->GetHi();
511
break;
512
case REGISTER_LO:
513
val = cpu->GetLo();
514
break;
515
default:
516
return;
517
}
518
}
519
else
520
{
521
return;
522
}
523
524
switch (TriggerContextMenu(ContextMenuID::REGLIST, wnd, ContextPoint::FromEvent(lParam)))
525
{
526
case ID_REGLIST_GOTOINMEMORYVIEW:
527
SendMessage(GetParent(wnd),WM_DEB_GOTOHEXEDIT,val,0);
528
break;
529
case ID_REGLIST_GOTOINDISASM:
530
if (disasmWindow)
531
disasmWindow->Goto(val);
532
break;
533
case ID_REGLIST_COPYVALUE:
534
copyRegisterValue();
535
break;
536
case ID_REGLIST_CHANGE:
537
editRegisterValue();
538
break;
539
}
540
return;
541
}
542
if (x>16)
543
{
544
selection=yToIndex(y);
545
selecting=false;
546
ReleaseCapture();
547
redraw();
548
}
549
}
550
551
void CtrlRegisterList::onMouseMove(WPARAM wParam, LPARAM lParam, int button)
552
{
553
if (button&1)
554
{
555
int x = LOWORD(lParam);
556
int y = (signed short)HIWORD(lParam);
557
// if (x>16)
558
{
559
/*
560
if (y<0)
561
{
562
curAddress-=align;
563
redraw();
564
}
565
else if (y>rect.bottom)
566
{
567
curAddress+=align;
568
redraw();
569
}
570
else*/
571
onMouseDown(wParam,lParam,1);
572
}
573
}
574
}
575
576
577
int CtrlRegisterList::yToIndex(int y)
578
{
579
// int ydiff=y-rect.bottom/2-rowHeight/2;
580
// ydiff=(int)(floorf((float)ydiff / (float)rowHeight))+1;
581
// return curAddress + ydiff * align;
582
int n = (y/rowHeight) - 1;
583
if (n<0) n=0;
584
return n;
585
}
586
587