1G pages support for CPU
[bochs-mirror.git] / gui / win32_enh_dbg.cc
blobe534cd714c75b1a5ecb5d6009f13ab6fd908dc97
1 // BOCHS ENHANCED DEBUGGER Ver 1.0
2 // (C) Chourdakis Michael, 2008
3 // http://www.turboirc.com
4 //
5 // Modified by Bruce Ewing
6 //
8 #include "bochs.h"
9 #include "cpu/cpu.h"
10 #include "win32dialog.h"
11 #include "wenhdbg_h.h"
13 #if BX_DEBUGGER
15 extern HWND hDebugDialog;
16 extern char *debug_cmd;
17 extern BOOL debug_cmd_ready;
19 INT_PTR CALLBACK A_DP(HWND hh2,UINT mm,WPARAM ww,LPARAM ll)
21 static ASKTEXT* as = 0;
22 switch(mm)
24 case WM_INITDIALOG:
25 as = (ASKTEXT*)ll;
26 SetWindowText(hh2,as->ti);
27 SetWindowText(GetDlgItem(hh2,101),as->as);
28 SetWindowText(GetDlgItem(hh2,102),as->re);
29 if (as->DefT)
30 SetTimer(hh2,1,as->DefT*1000,0);
31 return TRUE;
32 case WM_TIMER:
33 PostMessage(hh2,WM_COMMAND,IDOK,0);
34 KillTimer(hh2,1);
35 return TRUE;
36 case WM_COMMAND:
37 if (HIWORD(ww) == EN_UPDATE)
38 KillTimer(hh2,1);
40 if (LOWORD(ww) == IDOK)
42 GetWindowText(GetDlgItem(hh2,102),as->re,100);
43 EndDialog(hh2,IDOK);
44 return 0;
46 if (LOWORD(ww) == IDCANCEL)
48 EndDialog(hh2,IDCANCEL);
49 return 0;
52 return 0;
55 bx_bool AskText(HWND hh,const TCHAR* ti,TCHAR* as,TCHAR* re,int DefT)
57 ASKTEXT a = {ti,as,re,DefT};
58 bx_bool ret = FALSE;
59 // The dialog box needs a caret, and will destroy the one in hE_I.
60 // So destroy it myself, cleanly, and let it be recreated cleanly.
61 CallWindowProc(*wEdit, hE_I,WM_KILLFOCUS,(WPARAM) 0,0);
62 if (DialogBoxParam(GetModuleHandle(0),"DIALOG_AT",hh,A_DP,(LPARAM)&a) == IDOK)
63 ret = TRUE;
64 // recreate the caret in the Input window
65 CallWindowProc(*wEdit, hE_I,WM_SETFOCUS,(WPARAM) 0,0);
66 SetFocus(hE_O); // kludge to finish taking focus away from dialog box
67 return ret;
71 // Match stuff
72 #define MATCH_TRUE 1
73 #define MATCH_FALSE 0
74 #define MATCH_ABORT -1
76 #define NEGATE_CLASS
77 #define OPTIMIZE_JUST_STAR
79 char UCtable[256];
80 void MakeXlatTables()
82 char *p, c;
83 int i = 256;
84 while (--i >= 0) // make an upper case translation table
85 UCtable[i]= toupper(i);
86 p = AsciiHex; // then also make a "hex" table
87 for ( i = 0; i < 256; i++)
89 c = i >> 4;
90 if (c > 9)
91 c += 'A' - 10; // do all hex in uppercase
92 else
93 c += '0';
94 *(p++)= c;
95 c = i & 0xf;
96 if (c > 9)
97 c += 'A' - 10;
98 else
99 c += '0';
100 *(p++)= c;
104 int DoMatch(const char *text, const char *p, bx_bool IsCaseSensitive)
106 // probably the MOST DIFFICULT FUNCTION in TurboIRC
107 // Thanks to BitchX for copying this function
108 //int last;
109 int matched;
110 //int reverse;
111 int pT = 0;
112 int pP = 0;
114 for (; p[pP] != '\0'; pP++, pT++)
116 if (text[pT] == '\0' && p[pP] != '*')
117 return MATCH_ABORT;
118 switch (p[pP])
120 // case '\\': // Match with following char
121 // pP++;
122 // NO BREAK HERE
124 default:
125 if (IsCaseSensitive != FALSE)
127 if (text[pT] != p[pP])
128 return MATCH_FALSE;
129 else
130 continue;
132 // if (toupper(text[pT]) != toupper(p[pP]))
133 if (UCtable[(int) text[pT]] != UCtable[(int) p[pP]])
134 return MATCH_FALSE;
135 continue;
137 case '?':
138 continue;
140 case '*':
141 if (p[pP] == '*')
142 pP++;
143 if (p[pP] == '\0')
144 return MATCH_TRUE;
145 while (text[pT] != FALSE)
147 matched = DoMatch(text + pT++, p + pP, FALSE);
148 if (matched != MATCH_FALSE)
149 return matched;
151 return MATCH_ABORT;
155 return (text[pT] == '\0');
158 // This will be called from the other funcs
159 int VMatching(const char *text, const char *p, bx_bool IsCaseSensitive)
161 #ifdef OPTIMIZE_JUST_STAR
162 if (p[0] == '*' && p[1] == '\0')
163 return MATCH_TRUE;
164 #endif
165 return (DoMatch(text, p, IsCaseSensitive) == MATCH_TRUE);
168 int IsMatching(const char *text, const char *p, bx_bool IsCaseSensitive)
170 return VMatching(text, p, IsCaseSensitive);
173 // utility function for list resizing operation -- set LoX and HiX
174 // the resize operation exits if the mouse moves beyond LoX or HiX
175 void SetHorzLimits(int i)
177 if (i < BarScrx[0] + 10) // is it the left or right bar?
179 Resize_LoX = OneCharWide << 2; // set horizontal limits
180 i = ListWidthPix[(DockOrder >> 8) -1]; // col1 width
181 // calculate end of col2 - 4 charwidths in parent coordinates
182 Resize_HiX = i + ListWidthPix[CurCenterList] - (OneCharWide << 2);
183 Sizing = 1;
185 else if (i > BarScrx[1] - 10)
187 i = ListWidthPix[(DockOrder >> 8) -1]; // col1 width
188 Resize_LoX = i + (OneCharWide << 2); // set horizontal limits
189 // calculate total width - 4 charwidths in parent coordinates
190 i = ListWidthPix[0] + ListWidthPix[1] + ListWidthPix[2];
191 Resize_HiX = i - (OneCharWide << 2);
192 Sizing = 2;
194 SetCursor(hCursResize);
197 void DockResize (HWND hh, LPARAM ll) // ll is a child coordinate mouse-style Lparam
199 int i = 2; // assume either data or tree window is destination
200 void MoveLists(HWND);
201 if (hh == hL[0])
202 i = 0; // i = ListView destination index
203 else if (hh == hL[1])
204 i = 1;
206 if (Sizing >= 10) // dock operation
208 Sizing -= 10; // calculate which list initiated dock = moving window
209 if (Sizing != i) // moving window = destination window is a no-op
211 // Convert Sizing and i into a table lookup index (j)
212 // -- otherwise, the "algorithm" to compute new DockOrder is annoying
213 int j = (Sizing*2 + ((Sizing | i) & 1)) *6;
214 if (Sizing == 1)
215 j = (Sizing*4 + (i & 2)) *3;
217 // convert current DockOrder to a number from 0 to 5, add to j
218 j += ((DockOrder >> 7) - 2) &6;
219 if (((DockOrder >> 4) &3) > (DockOrder & 3))
220 j += 1;
221 DockOrder = nDock[j];
222 MoveLists(hY);
226 else // resize operation
228 int idx, totpix;
229 POINT pt;
230 pt.x = LOWORD(ll);
231 pt.y = 0;
232 ClientToScreen(hh,&pt);
233 ScreenToClient(hY,&pt); // convert to parent's coordinates
234 if (Sizing == 1)
236 idx = (DockOrder >> 8) -1; // sizing the left bar
237 totpix = ListWidthPix[idx] + ListWidthPix[CurCenterList];
238 ListWidthPix[idx] = pt.x;
239 ListWidthPix[CurCenterList] = totpix - pt.x; // reset the widths of the left and center windows
241 else
243 pt.x -= ListWidthPix[(DockOrder >> 8) -1]; // caclulate new width of center window
244 idx = (DockOrder & 3) -1;
245 totpix = ListWidthPix[idx] + ListWidthPix[CurCenterList];
246 ListWidthPix[CurCenterList] = pt.x;
247 ListWidthPix[idx] = totpix - pt.x; // reset the widths of the right and center windows
249 MoveLists(hY);
251 Sizing = 0;
254 // Subclass the edit controls
255 LRESULT CALLBACK ThisEditProc(HWND hh, UINT mm, WPARAM ww, LPARAM ll)
257 int i = 0;
258 if (hh == hE_O) i = 1; // easy way to detect which edit window
259 switch (mm)
261 case WM_MOUSEMOVE:
262 // turn off any sizing operation if the cursor strays off the listviews
263 Sizing = 0;
264 // also turn off any half-completed mouseclicks
265 xClick = -1;
266 break;
267 case WM_SETFOCUS: // force the Input window to always have the caret
268 return 0; // SETFOCUS/KILLFOCUS commands are sent directly to the hE_I defProc
269 case WM_KILLFOCUS:
270 return 0;
271 case WM_SHOWWINDOW: // Note: This doesn't work ... on an unhide, it didn't even GET this message!
272 if (ww == 0) // fall through to SetFocus on Output when Input window is "shown"
273 return 0;
274 case WM_LBUTTONDOWN:
275 SetFocus(hE_O); // this does more than just send a SETFOCUS message ...
276 return 0;
277 case WM_CHAR:
278 case WM_SYSCHAR:
279 // throw away all Enter keys (bell problems)
280 if (ww == VK_RETURN)
281 return 0;
282 // force all typed input to the Input window (wEdit[0] = Input)
283 CallWindowProc((WNDPROC) *wEdit, hE_I, mm, ww, ll);
284 return 0;
285 case WM_KEYDOWN:
286 case WM_SYSKEYDOWN:
287 // simply let parent know about all keys hit in these edit boxes
288 SendMessage(GetParent(hh),mm,ww,ll);
289 // the following keys cause annoying "bells" if sent on to the Original proc
290 // -- so throw them away (return 0)
291 if (ww == VK_RETURN || ww == VK_DOWN || ww == VK_UP)
292 return 0;
294 if (wEdit[i] != NULL)
295 return (CallWindowProc(wEdit[i], hh, mm, ww, ll));
296 else
297 return 0;
300 // Subclass all the button controls together
301 LRESULT CALLBACK BtnProc(HWND hh, UINT mm, WPARAM ww, LPARAM ll)
303 switch (mm)
305 case WM_MOUSEMOVE:
306 // turn off any sizing operation if the cursor strays off the listviews
307 Sizing = 0;
308 // also turn off any half-completed mouseclicks
309 xClick = -1;
310 break;
311 case WM_CHAR:
312 // throw away any Enter keys (potential bell problems?)
313 if (ww == VK_RETURN)
314 return 0;
315 // force any typed input to the Input window
316 CallWindowProc((WNDPROC) *wEdit, hE_I, mm, ww, ll);
317 return 0;
318 case WM_KEYDOWN:
319 case WM_SYSKEYDOWN:
320 // pass to parent any keys
321 SendMessage(GetParent(hh),mm,ww,ll);
322 if (ww == ' ') // space chars cause buttons to activate
323 return 0;
325 return (CallWindowProc(wBtn, hh, mm, ww, ll));
328 // the subclassed tree-view uses the same handler that the listview does
329 // subclass all the listviews at once
330 // Note: the Sizing varaible keeps track of whether the program is in resize or dock mode, and
331 // which windows are involved. It's complicated. If you don't like how I use the variable, tough.
332 LRESULT CALLBACK LVProc(HWND hh, UINT mm, WPARAM ww, LPARAM ll)
334 int i;
335 POINT pt;
336 switch (mm)
338 case WM_CHAR:
339 // throw away all Enter keys (or use them for something)
340 if (ww != VK_RETURN && *wEdit != NULL)
341 // force all typed input to the Input window
342 CallWindowProc(*wEdit, hE_I, mm, ww, ll);
343 return 0;
345 case WM_MOUSEMOVE: // need to play with the cursor during resize/dock operations
346 pt.y = HIWORD(ll);
347 pt.x = LOWORD(ll); // get the listview client's X coord of the mouse
348 if (xClick >= 0) // saw a lbutton mousedown recently? (pre-dock mode)
350 // cancel an impending "click" and go to dock (drag) mode if mouse is moving too much
351 i= (OneCharWide >> 1);
352 if (pt.x > xClick + i || pt.x < xClick - i)
353 xClick = -1;
354 else if (pt.y > yClick + i || pt.y < yClick - i)
355 xClick = -1;
356 // go into dock mode (without canceling the click) on a .5s time delay
357 i = CurTimeStamp + 500;
358 if (xClick < 0 || GetMessageTime() > i) // Start a "dock" operation?
359 Sizing = SizeList; // Sizing tells which ListView is being moved
361 // if "drag" did not turn off, then I will get only one mousemove, with VK_LBUTTON showing UP
362 i = GetKeyState(VK_LBUTTON);
363 if (i >= 0 && Sizing != 0)
364 DockResize (hh, ll);
366 if (Sizing != 0)
368 ClientToScreen(hh,&pt);
369 ScreenToClient(hY,&pt); // convert to parent's coordinates
370 i = GetKeyState(VK_LBUTTON);
371 // verify horizontal limits of the current resize or dock operation
372 if (pt.x > Resize_HiX || pt.x < Resize_LoX)
373 Sizing = 0;
374 else if (i >= 0 && Sizing > 0)
375 DockResize (hh, ll);
376 else if (Sizing > 5)
377 SetCursor(hCursDock);
378 else
379 SetCursor(hCursResize);
381 break;
383 case WM_NCMOUSEMOVE: // more cursor games
384 if (Sizing == 0)
386 if (ww == HTBORDER) // mouse is hovering or dragging over a resize bar or border
388 i = LOWORD(ll); // get the screen X coord of the mouse
389 if (i < BarScrx[0] + 10) // is it the left or right bar?
390 Sizing = -2;
391 else if (i > BarScrx[1] - 10)
392 Sizing = -1;
393 Resize_LoX = BarClix[Sizing + 2] - OneCharWide; // set horizontal limits
394 Resize_HiX = BarClix[Sizing + 2] + OneCharWide;
397 if (Sizing >= 10) // docking operation?
398 SetCursor(hCursDock);
399 else if (Sizing != 0)
401 pt.y = HIWORD(ll);
402 pt.x = LOWORD(ll); // get the screen X coord of the mouse
403 ScreenToClient(hY,&pt); // convert to parent's coordinates
404 // verify horizontal limits of the current resize operation
405 if (pt.x > Resize_HiX || pt.x < Resize_LoX)
406 Sizing = 0;
407 else
408 SetCursor(hCursResize);
410 break;
412 case WM_NCLBUTTONDOWN:
413 if (Sizing < 0) // doing a resize?
414 SetHorzLimits((int) LOWORD(ll)); // NC messages are in Screen coordinates
415 SetFocus(hE_O); // helps to make keystrokes go to Input window
416 break;
418 case WM_NCLBUTTONUP:
419 Sizing = 0; // a mouseup on a border can't be interpreted -- cancel everything
420 xClick = -1;
421 break;
423 case WM_LBUTTONDOWN:
424 if (Sizing < 0) // doing a resize?
426 GetCursorPos(&pt); // Screen coordinates
427 SetHorzLimits((int) pt.x);
429 else // set "pre-dock" mode
431 if (hh == hL[0])
432 SizeList = 10; // remember which list to dock
433 else if (hh == hL[1])
434 SizeList = 11;
435 else
436 SizeList = 12;
437 Resize_LoX = OneCharWide << 2; // set horizontal limits
438 i = ListWidthPix[0] + ListWidthPix[1] + ListWidthPix[2];
439 Resize_HiX = i - (OneCharWide << 2);
440 CurTimeStamp = GetMessageTime();
441 xClick = LOWORD(ll);
442 yClick = HIWORD(ll);
444 SetFocus(hE_O); // helps to make keystrokes go to Input window
445 // prevent default drag operations by returning 0
446 // unfortunately, this also prevents clicks from happening automatically
447 return 0;
449 case WM_LBUTTONUP:
450 // the mouseup COMPLETES a "click" or drag
451 if (Sizing > 0)
452 DockResize (hh, ll);
453 else if (xClick >= 0)
455 pt.x = LOWORD(ll);
456 pt.y = HIWORD(ll);
457 // verify the mouseup was within a tight circle of the mousedown
458 i= (OneCharWide >> 1) +1;
459 if (pt.x < xClick + i && pt.x > xClick - i && pt.y < yClick + i && pt.y > yClick - i)
461 LV_ITEM lvi;
462 lvi.stateMask = LVIS_SELECTED;
463 lvi.state = 0;
465 // emulate a regular click, for Trees or Lists
466 if (hh == hT)
468 TV_HITTESTINFO TreeHT;
469 TreeHT.pt.x = pt.x; // find out which tree button got clicked
470 TreeHT.pt.y = pt.y;
471 HTREEITEM hTreeEnt;
472 hTreeEnt = (HTREEITEM) CallWindowProc(wTreeView,hT,TVM_HITTEST,(WPARAM) 0,(LPARAM) &TreeHT);
473 // then simulate a click on that button
474 if (hTreeEnt != NULL) // make sure the click is actually on an entry
475 CallWindowProc(wTreeView,hT,TVM_EXPAND,(WPARAM) TVE_TOGGLE,(LPARAM) hTreeEnt);
476 xClick = -1;
477 Sizing = 0;
478 return 0; // eat all the Tree mouseups
480 i = 0; // deal with List Focus
481 DumpHasFocus = FALSE;
482 if (hh == hL[1])
483 i = 1;
484 else if (hh != hL[0])
486 DumpHasFocus = TRUE;
487 i = 2;
488 EnableMenuItem (hCmdMenu, CMD_BRKPT, MF_GRAYED);
489 if (DumpMode == 0)
491 EnableMenuItem (hCmdMenu, CMD_WPTWR, MF_ENABLED);
492 EnableMenuItem (hCmdMenu, CMD_WPTRD, MF_ENABLED);
494 else
496 EnableMenuItem (hCmdMenu, CMD_WPTWR, MF_GRAYED);
497 EnableMenuItem (hCmdMenu, CMD_WPTRD, MF_GRAYED);
500 if (DumpHasFocus == FALSE)
502 EnableMenuItem (hCmdMenu, CMD_BRKPT, MF_ENABLED);
503 EnableMenuItem (hCmdMenu, CMD_WPTWR, MF_GRAYED);
504 EnableMenuItem (hCmdMenu, CMD_WPTRD, MF_GRAYED);
506 if (GetFocus() != hh)
508 CallWindowProc(wListView, hh, WM_SETFOCUS, (WPARAM) 0, (LPARAM) 0);
509 if (i != 0)
510 CallWindowProc(wListView, hL[0], WM_KILLFOCUS, (WPARAM) 0, (LPARAM) 0);
511 if (i != 1)
512 CallWindowProc(wListView, hL[1], WM_KILLFOCUS, (WPARAM) 0, (LPARAM) 0);
513 if (i != 2)
514 CallWindowProc(wListView, hL[2], WM_KILLFOCUS, (WPARAM) 0, (LPARAM) 0);
517 lvht.pt.x = LOWORD(ll); // do a hit test to get the iItem to select
518 lvht.pt.y = HIWORD(ll);
519 i = CallWindowProc(wListView, hh, LVM_HITTEST, (WPARAM) 0, (LPARAM) &lvht);
520 // i is a copy of the iItem number -- ignore anything <= 0
521 // deselect anyything that's selected
522 int j = CallWindowProc(wListView, hh, LVM_GETNEXTITEM, (WPARAM) -1, MAKELPARAM(LVNI_SELECTED, 0));
523 while (j >= 0)
525 // cancel the item's "selection"
526 CallWindowProc(wListView, hh, LVM_SETITEMSTATE, (WPARAM)j, (LPARAM)&lvi);
527 // and get the next one
528 j = CallWindowProc(wListView, hh, LVM_GETNEXTITEM, (WPARAM) -1, MAKELPARAM(LVNI_SELECTED, 0));
530 if (i >= 0) // then select the one that got clicked
532 lvi.state = lvi.stateMask; // value = "selected"
533 CallWindowProc(wListView, hh, LVM_SETITEMSTATE, (WPARAM)lvht.iItem, (LPARAM)&lvi);
534 if (hh == hL[2])
536 // if this was a MemDump click -- need to get the "Selected Address"
537 SelectedDataAddress = DumpStart + (i<<4);
538 // Clicked a Subitem? column numbers = byte offsets + 1
539 CallWindowProc(wListView, hh, LVM_SUBITEMHITTEST, 0, (LPARAM)&lvht);
540 if (lvht.iSubItem > 0)
541 SelectedDataAddress += lvht.iSubItem - 1;
546 xClick = -1; // all drags/clicks have been processed, so reset
547 Sizing = 0;
548 return 0; // eat all the mouseups
549 } // end the switch
550 if (hh == hT) // if this is a param_tree message, use the proper windowProc
551 return (CallWindowProc(wTreeView, hh, mm, ww, ll));
552 else
553 return (CallWindowProc(wListView, hh, mm, ww, ll));
557 bx_bool SpListView() // Superclasses a ListView control
559 WNDCLASS wClass;
560 GetClassInfo(GetModuleHandle(0), WC_LISTVIEW, &wClass);
561 wListView = wClass.lpfnWndProc;
562 wClass.hInstance = GetModuleHandle(0);
563 wClass.lpszClassName = "sLV";
564 wClass.lpfnWndProc = LVProc;
565 if (RegisterClass(&wClass) == 0)
566 return FALSE;
567 return TRUE;
570 bx_bool SpBtn() // Superclasses a button control
572 WNDCLASS wClass;
573 GetClassInfo(GetModuleHandle(0), "button", &wClass);
574 wBtn = wClass.lpfnWndProc;
575 wClass.hInstance = GetModuleHandle(0);
576 wClass.lpszClassName = "sBtn";
577 wClass.lpfnWndProc = BtnProc;
578 if (RegisterClass(&wClass) == 0)
579 return FALSE;
580 return TRUE;
583 // Convert a string (except for the 0x in a hex number) to uppercase
584 void upr(char* d)
586 char *p;
587 p = d;
588 while (*p != 0)
590 if (*p == '0' && p[1] == 'x')
591 p += 2;
592 else
594 *p = UCtable[(int) *p]; // use the lookup table created by MakeXlatTables
595 ++p;
600 // create EFLAGS display for Status line
601 void ShowEflags()
603 Bit32u Efl = (Bit32u) rV[EFL_Rnum];
604 int i = 16;
605 char *cp = tmpcb + 6;
607 sprintf(tmpcb,"IOPL=%1u", (Efl & 0x3000) >> 12);
608 while (--i >= 0)
610 *(cp++)= ' ';
611 strcpy (cp, EflBName[i]); // copy the name of the bitflag
612 if ((Efl & EflBitVal[i]) != 0) // if the bit is set, put the name in uppercase
613 upr(cp);
614 cp += EflBNameLen[i];
618 // change the display on the status line if anything has changed
619 void UpdateStatus()
621 if (StatusChange == FALSE) return; // avoid sending unnecessary messages/invalidations
622 StatusChange = FALSE;
624 if (AtBreak != FALSE) // modify status line only during a break
626 ShowEflags(); // prints flags into tmpcb
627 SendMessage(hS_S,SB_SETTEXT,3,(LPARAM)tmpcb); // display eflags
629 if (CpuModeChange != FALSE) // Did CR0 bits or EFER bits change value?
631 CpuModeChange = FALSE;
632 switch (CpuMode) {
633 case BX_MODE_IA32_REAL:
634 if (In32Mode == FALSE)
635 SendMessage(hS_S,SB_SETTEXT,1,(LPARAM)"CPU: Real Mode (16)");
636 else
637 SendMessage(hS_S,SB_SETTEXT,1,(LPARAM)"CPU: Real Mode (32)");
638 break;
639 case BX_MODE_IA32_V8086:
640 SendMessage(hS_S,SB_SETTEXT,1,(LPARAM)"CPU: V8086 Mode");
641 break;
642 case BX_MODE_IA32_PROTECTED:
643 if (In32Mode == FALSE) {
644 if (InPaging != 0)
645 SendMessage(hS_S,SB_SETTEXT,1,(LPARAM)"CPU: PMode (16) (PG)");
646 else
647 SendMessage(hS_S,SB_SETTEXT,1,(LPARAM)"CPU: PMode (16)");
649 else {
650 if (InPaging != 0)
651 SendMessage(hS_S,SB_SETTEXT,1,(LPARAM)"CPU: PMode (32) (PG)");
652 else
653 SendMessage(hS_S,SB_SETTEXT,1,(LPARAM)"CPU: PMode (32)");
655 break;
656 case BX_MODE_LONG_COMPAT:
657 SendMessage(hS_S,SB_SETTEXT,1,(LPARAM)"CPU: Compatibility Mode");
658 break;
659 case BX_MODE_LONG_64:
660 SendMessage(hS_S,SB_SETTEXT,1,(LPARAM)"CPU: Long Mode");
661 break;
666 // set window color (active or gray), depending on AtBreak value
667 if (AtBreak != PrevAtBreak)
669 PrevAtBreak = AtBreak;
670 COLORREF c = RGB(255,255,255);
671 if (AtBreak == FALSE)
673 SendMessage(hS_S,SB_SETTEXT,0,(LPARAM)"Running");
674 c = RGB(210,210,210); // emulation running -> gui inactive
676 else
677 SendMessage(hS_S,SB_SETTEXT,0,(LPARAM)"Break");
679 // this sets the background color OUTSIDE the area of the list, for A, D, R
680 CallWindowProc(wListView, hL[2],LVM_SETBKCOLOR,0,c);
681 CallWindowProc(wListView, hL[1],LVM_SETBKCOLOR,0,c);
682 CallWindowProc(wListView, hL[0],LVM_SETBKCOLOR,0,c);
684 InvalidateRect(hL[2],0,TRUE);
685 InvalidateRect(hL[1],0,TRUE);
686 InvalidateRect(hL[0],0,TRUE);
690 // Read a copy of some emulated linear bochs memory
691 // Note: laddr + len must not cross a 4K boundary -- otherwise, there are no limits
692 bx_bool ReadBxLMem(Bit64u laddr, unsigned len, Bit8u *buf)
694 bx_phy_address paddr;
695 bx_bool retval = TRUE;
697 // on same physical page as the last access?
698 if (laddr < ladrmin || laddr > ladrmax)
700 // No -- create a new translation offset for the new page.
701 if (laddr > (Bit64u) 0xffffffff && In64Mode == FALSE)
702 return FALSE;
703 bx_address la_4K = (bx_address) laddr & (~0xfff);
704 ladrmin = la_4K;
705 ladrmax = la_4K + 0xfff;
706 retval = BX_CPU(CurrentCPU)->dbg_xlate_linear2phy(la_4K, &paddr);
707 if (retval == FALSE)
708 return FALSE;
709 l_p_offset = la_4K - paddr;
711 paddr = (bx_phy_address)(laddr - l_p_offset);
712 if (len != 0)
713 retval = bx_mem.dbg_fetch_mem(BX_CPU(CurrentCPU), paddr, len, buf);
714 return retval;
718 // "singlestep" disassembly lines from the internal debugger are sometimes ignored
719 bx_bool isSSDisasm(char *s)
721 if (ignSSDisasm == FALSE) // ignoring those lines?
722 return FALSE;
724 while (*s == ' ') // need to parse the line to see if it is ASM
725 ++s;
726 if (*s != '(') // first char must be (
727 return FALSE;
728 while (*s != '[' && *s != 0) // then there must be a [
729 ++s;
730 if (*s == 0)
731 return FALSE;
732 while (*s != 0 && (*s != ')' || s[1] != ':' || s[2] != ' '))
733 ++s;
734 if (*s == 0)
735 return FALSE;
736 while (*s != ';' && *s != 0) // last, there must be a ;
737 ++s;
738 if (*s == 0)
739 return FALSE;
740 return TRUE;
743 // dump output from the bochs internal debugger to hE_O output window
744 void ParseUnknown(char *x)
746 char *s = x;
747 int i = 0;
748 int overflow = 0;
750 while (*s !=0 && *s != '\r' && *s != '\n' && DbgAppendPtr < tmpcb)
751 *(DbgAppendPtr++)= *(s++); // append the chars from x into the bigbuf
752 if (DbgAppendPtr >= tmpcb) // overflow error?
754 MessageBox(hY,"Debugger output cannot be parsed -- buffer overflow",0,MB_OK);
755 DbgAppendPtr = bigbuf; // throw away the line
756 return;
759 *DbgAppendPtr = 0;
760 if (*s == 0) // automatically process only complete lines further
762 PO_Tdelay = 2; // wait a half second, then force display of partial lines
763 return;
765 PO_Tdelay = 0; // line completed -- cancel any partial output time delay
767 // restart DbgAppendPtr at the beginning of a new line buffer
768 s= DbgAppendPtr= bigbuf; // s -> raw register text line from debugger
769 if (ignoreNxtT != FALSE)
771 if (strncmp(s,"Next at t",9) == 0)
772 return;
774 if (isSSDisasm(s) != FALSE)
775 return;
777 while ((*s >= ' ' || *s == '\t') && i < 204) // scan out to eol, count chars
779 ++i;
780 ++s;
782 if (i > 203) // max out at 203 chars per line (should never happen)
784 i = 200;
785 overflow = 3;
787 char *p = OutWindow;
788 if ((i+overflow+3) > OutWinCnt) // amt needed vs. space available
790 s = OutWindow; // need to toss lines off beginning of OutWindow
791 int j = OutWinCnt - overflow - 3;
792 while (j < i) // throw away one line at a time
794 // stop on any unprintable char < ' '
795 while ((unsigned char)*s >= ' ' || *s == '\t')
797 ++s;
798 ++j; // increase available space as chars are tossed
800 // in reality, s must be pointing at a CRLF
801 s += 2;
802 j += 2;
804 OutWinCnt = j + overflow + 3;
805 j = OutWinSIZE - OutWinCnt; // chars to copy, without the terminal zero
806 while (j-- > 0) // recopy the OutWindow buffer up
807 *(p++) = *(s++);
809 else
810 p = OutWindow + OutWinSIZE - OutWinCnt;
811 OutWinCnt -= i + overflow + 2;
812 *(p++) = '\r'; // end of buf only had a 0 in it,
813 *(p++) = '\n'; // and needs CRLFs to display properly
814 s = bigbuf;
815 while (i-- > 0) // copy the new output line onto the buffer
816 *(p++) = *(s++);
817 if (overflow != 0)
819 *(p++) = '.'; // just for fun, if the line overflows
820 *(p++) = '.';
821 *(p++) = '.';
823 *p = 0;
824 SetWindowText(hE_O,OutWindow); // replace all text with modified buffer
825 // SendMessage(hE_O,EM_SETSEL,0,-1); // invisibly selects all, sets caret to end
826 CallWindowProc(wEdit[1], hE_O,EM_SETSEL,OutWinSIZE,OutWinSIZE+1); // sets caret to end only
827 CallWindowProc(wEdit[1], hE_O,EM_SCROLLCARET,0,0); // scrolls window to caret
828 // Note: the caret is never actually visible in the Output window
831 // load appropriate register values from simulation into local rV[] array
832 void FillRegs()
834 int i = EFER_Rnum + 1; // EFER is the highest reg # in rV
835 while (--i >= 0)
837 if (RegObject[CurrentCPU][i] != NULL)
838 rV[i] = RegObject[CurrentCPU][i]->get64();
840 #if BX_SUPPORT_X86_64 == 0
841 // copy RIP, RSP from EIP, ESP -- so LAs for both are always easily available
842 rV[RIP_Rnum] = rV[EIP_Rnum];
843 rV[RSP_Rnum] = rV[ESP_Rnum];
844 #else
845 // copy the lower dwords of RAX - RBP to EAX - EBP (with 32bit truncation)
846 i = RIP_Rnum + 1;
847 while (--i >= 0)
848 rV[i + (EAX_Rnum - RAX_Rnum)] = GET32L(rV[i]);
849 #endif
850 if (RegObject[CurrentCPU][GDTR_Lim] != NULL) // get the limits on GDT and IDT
851 GDT_Len = RegObject[CurrentCPU][GDTR_Lim]->get();
852 if (RegObject[CurrentCPU][IDTR_Lim] != NULL)
853 IDT_Len = RegObject[CurrentCPU][IDTR_Lim]->get();
855 // Check CR0 bit 31 -- Paging bit
856 Bit32u NewPg = (Bit32u) rV[CR0_Rnum] & 0x80000000;
857 if (InPaging != NewPg)
859 if (NewPg == FALSE)
860 EnableMenuItem (hViewMenu, CMD_PAGEV, MF_GRAYED);
861 else
862 EnableMenuItem (hViewMenu, CMD_PAGEV, MF_ENABLED);
863 StatusChange = TRUE;
865 InPaging = NewPg;
868 // grab linear breakpoints out of internal debugger's bx_guard structures, and sort them
869 void ParseBkpt()
871 extern bx_guard_t bx_guard;
872 int k;
873 int j = 0;
874 int i = bx_guard.iaddr.num_linear;
875 while (--i >= 0)
877 if (bx_guard.iaddr.lin[i].enabled != FALSE)
879 BrkLAddr[j] = bx_guard.iaddr.lin[i].addr;
880 BrkIdx[j] = bx_guard.iaddr.lin[i].bpoint_id;
881 ++j;
884 BreakCount = i = j;
885 // sort the breakpoint list (linear sort), to make it faster to search
886 while (--i > 0)
888 j = k = i;
889 while (--j >= 0)
891 if (BrkLAddr[j] > BrkLAddr[k]) // find the next biggest
892 k = j;
894 if (k < i)
896 bx_address h = BrkLAddr[i]; // do the swap on BOTH arrays
897 j = BrkIdx[i];
898 BrkLAddr[i] = BrkLAddr[k];
899 BrkIdx[i] = BrkIdx[k];
900 BrkLAddr[k] = h;
901 BrkIdx[k] = j;
906 // this routine is only called if debugger already knows SSE is supported
907 // -- but it might not be "turned on", either
908 int FillSSE(int LineCount)
910 #if BX_SUPPORT_SSE
911 int i;
912 Bit64u val = 0;
913 bx_param_num_c *p;
914 lviG.pszText = tmpce;
915 #ifndef IS_WIN98
916 lviG.iGroupId = 4;
917 #endif
918 if ((rV[CR0_Rnum] & 0xc) != 0) // TS or EM flags in CR0 temporarily disable SSE
920 strcpy (tmpce, "SSE-off");
921 lviG.iItem = LineCount;
922 RitemToRnum[LineCount] = XMM0_Rnum;
923 CallWindowProc(wListView,hL[0],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
924 return ++LineCount;
927 // format: XMM[#] 00000000:00000000 (each 16 hex digits)
928 LV_ITEM lvi = {LVIF_TEXT,0,2,0,0,(LPSTR) tmpcf,80,0,0};
929 strcpy (tmpce, "XMM[0]");
930 for (i = 0; i < BX_XMM_REGISTERS; i++)
932 if (i >= 10)
934 tmpce[4] = '1';
935 tmpce[5] = i - 10 + '0';
936 tmpce[6] = ']';
937 tmpce[7] = 0;
939 else
940 tmpce[4] = i + '0';
941 lviG.iItem = LineCount;
942 RitemToRnum[LineCount] = i + XMM0_Rnum;
943 CallWindowProc(wListView,hL[0],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
944 tmpce[6] = 0;
945 p = RegObject[CurrentCPU][XMM0_hi + i];
946 if (p != NULL)
947 val = p->get64(); // get the value of "xmm(i)_hi" register
948 else
949 val = 0;
950 *tmpcf = '0'; // I'm putting a hex value in the decimal column -- more room there!
951 tmpcf[1] = 'x';
952 sprintf (tmpcf + 2,Fmt64b[UprCase],val);
953 strcpy (tmpcf + 18, " : ");
954 p = RegObject[CurrentCPU][XMM0_Rnum + i];
955 if (p != NULL)
956 val = p->get64(); // "SSE.xmm[i]_lo"
957 else
958 val = 0;
959 sprintf (tmpcf + 21,Fmt64b[UprCase], val);
960 lvi.iItem = LineCount;
961 CallWindowProc(wListView,hL[0],LVM_SETITEMTEXT,(WPARAM) LineCount,(LPARAM) &lvi);
962 ++LineCount;
964 #endif
965 return (LineCount);
968 // this routine is only called if debugger already knows FPU is supported
969 // -- but it might not be active
970 int FillMMX(int LineCount)
972 static double scale_factor = pow(2.0, -63.0);
973 int i;
974 Bit16u exp = 0;
975 Bit64u mmreg = 0;
976 bx_param_num_c *p;
977 unsigned short exponent[8];
979 lviG.pszText = tmpce;
980 #ifndef IS_WIN98
981 lviG.iGroupId = 3;
982 #endif
983 if ((rV[CR0_Rnum] & 0xc) != 0) // TS or EM flags in CR0 temporarily disable MMX/FPU/SSE
985 strcpy (tmpce, "FPU-off");
986 lviG.iItem = LineCount;
987 RitemToRnum[LineCount] = ST0_Rnum;
988 CallWindowProc(wListView,hL[0],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
989 return ++LineCount;
992 // format: MM#|ST# 00000000:00000000 then FPU float value in "decimal" column
993 LV_ITEM lvi = {LVIF_TEXT,0,0,0,0,(LPSTR) tmpcf,80,0,0};
994 strcpy (tmpce, "MM0-ST0");
995 i = 7;
996 for (i = 0; i < 8; i++)
998 tmpce[2] = i + '0';
999 tmpce[6] = i + '0';
1000 lviG.iItem = LineCount;
1001 RitemToRnum[LineCount] = i + ST0_Rnum;
1002 CallWindowProc(wListView,hL[0],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
1003 p = RegObject[CurrentCPU][ST0_Rnum + i];
1004 if (p != NULL)
1005 mmreg = p->get64(); // get the value of "mmx(i)" register
1006 else
1007 mmreg = 0;
1008 sprintf (tmpcf,Fmt32b[UprCase],GET32H(mmreg));
1009 strcpy (tmpcf + 8, " : ");
1010 sprintf (tmpcf + 11,Fmt32b[UprCase], GET32L(mmreg));
1011 lvi.iItem = LineCount;
1012 lvi.iSubItem = 1;
1013 CallWindowProc(wListView,hL[0],LVM_SETITEMTEXT,(WPARAM) LineCount,(LPARAM) &lvi);
1014 p = RegObject[CurrentCPU][ST0_exp + i];
1015 if (p != NULL)
1016 exp = (Bit16u) p->get64(); // get the exponent for this FPU register
1017 else
1018 exp = 0;
1019 exponent[i] = exp; // save each one temporarily
1020 double f = pow(2.0, ((0x7fff & exp) - 0x3fff));
1021 if (exp & 0x8000)
1022 f = -f;
1023 #ifdef _MSC_VER
1024 f *= (double)(signed __int64)(mmreg>>1) * scale_factor * 2;
1025 #else
1026 f *= mmreg*scale_factor;
1027 #endif
1028 sprintf (tmpcf,"%.3e",f);
1029 lvi.iSubItem = 2;
1030 CallWindowProc(wListView,hL[0],LVM_SETITEMTEXT,(WPARAM) LineCount,(LPARAM) &lvi);
1031 ++LineCount;
1033 strcpy (tmpce, "ST0.exp");
1034 for (i = 0; i < 8; i++)
1036 tmpce[2] = i + '0';
1037 lviG.iItem = LineCount;
1038 RitemToRnum[LineCount] = i + ST0_exp;
1039 CallWindowProc(wListView,hL[0],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
1040 sprintf (tmpcf,Fmt16b[UprCase], exponent[i]);
1041 lvi.iItem = LineCount;
1042 lvi.iSubItem = 1;
1043 CallWindowProc(wListView,hL[0],LVM_SETITEMTEXT,(WPARAM) LineCount,(LPARAM) &lvi);
1044 sprintf (tmpcf,"%u", exponent[i]);
1045 lvi.iSubItem = 2;
1046 CallWindowProc(wListView,hL[0],LVM_SETITEMTEXT,(WPARAM) LineCount,(LPARAM) &lvi);
1047 ++LineCount;
1049 return LineCount;
1052 // get values of Debug registers from simulation
1053 int FillDebugRegs(int itemnum)
1055 bx_param_num_c *bxp;
1056 Bit32u val[6];
1057 unsigned int i;
1058 LV_ITEM lvi = {LVIF_TEXT,0,1,0,0,(LPSTR) tmpcf,80,0,0};
1059 strcpy (tmpce,"dr0");
1060 if (UprCase != FALSE)
1062 *tmpce = 'D';
1063 tmpce[1] = 'R';
1065 lviG.pszText = tmpce;
1066 for(i = 0 ; i < 6 ; i++)
1068 bxp = RegObject[CurrentCPU][DR0_Rnum + i];
1069 val[i] = 0;
1070 if (bxp != NULL)
1071 val[i] = bxp->get();
1072 RitemToRnum[itemnum] = i + DR0_Rnum;
1073 lviG.iItem = itemnum;
1074 #ifndef IS_WIN98
1075 lviG.iGroupId = 5;
1076 #endif
1077 CallWindowProc(wListView,hL[0],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
1078 sprintf(tmpcf,Fmt32b[UprCase],val[i]);
1079 lvi.iItem = itemnum;
1080 CallWindowProc(wListView,hL[0],LVM_SETITEMTEXT,(WPARAM) itemnum,(LPARAM) &lvi);
1081 ++tmpce[2]; // change the name, the cheap way
1082 if (i == 3) tmpce[2] += 2; // jump from "DR3" to "DR6"
1083 ++itemnum;
1085 return itemnum;
1088 // Disassemble a linear memory area, in a loop, loading text into ASM window
1089 // completely update the ASM display with new data
1090 void FillAsm(Bit64u LAddr, int MaxLines)
1092 Bit64u ReadAddr = LAddr;
1093 int BufLen = 0;
1094 int i, len;
1095 bx_bool BufEmpty;
1096 bx_bool Go = TRUE;
1097 char *s;
1098 char *p = bigbuf; // just to avoid a compiler warning
1099 LV_ITEM lvi = {LVIF_TEXT,0,0,0,0,(LPSTR) 0,80,0,0};
1101 AsmLineCount = 0; // initialize for disasm window update
1102 CallWindowProc(wListView,hL[1],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
1103 if (MaxLines > MAX_ASM) // just for protection
1104 MaxLines = MAX_ASM;
1106 while (Go != FALSE)
1108 // copydown buffer -- buffer size must be 4K + 16
1109 s= bigbuf;
1110 i= BufLen; // BufLen is guaranteed < 16
1111 while (i-- > 0)
1112 *(s++)= *(p++);
1113 // load buffer, up to the next 4k boundary
1114 len = 4096 - (((int) ReadAddr) & 0xfff); // calculate read amount
1115 Go = ReadBxLMem (ReadAddr, len, (Bit8u *) s);
1116 BufLen += len;
1117 ReadAddr += len;
1118 if (Go == FALSE)
1119 return;
1120 BufEmpty = FALSE;
1121 p= bigbuf; // start at the beginning of the new buffer
1122 while (AsmLineCount < MaxLines && BufEmpty == FALSE)
1124 // disassemble 1 line with a direct call, into tmpcf
1125 len = bx_disassemble.disasm(In32Mode, In64Mode, (bx_address) 0,
1126 (bx_address) LAddr, (Bit8u *) p, tmpcf);
1127 if (len <= BufLen) // disassembly was successful?
1129 AsmLA[AsmLineCount] = LAddr; // save, and
1130 if (In64Mode == FALSE) // "display" linear addy of the opcode
1131 sprintf (tmpce,Fmt32b[UprCase],LAddr);
1132 else
1133 sprintf (tmpce,Fmt64b[UprCase],LAddr);
1135 // create a new list entry
1136 lvi.iSubItem = 0;
1137 lvi.pszText = tmpce;
1138 lvi.iItem = AsmLineCount;
1139 CallWindowProc(wListView,hL[1],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lvi);
1140 BufLen -= len; // used up len bytes from buffer
1141 LAddr += len; // calculate next LAddr
1143 // then build the "bytes" column entry
1144 s = tmpce;
1145 *(s++) = '('; // begin with the bytecount in parens
1146 i = len;
1147 if (len > 9)
1149 *(s++)= '1'; // len < 16, so convert to decimal the easy way
1150 i -= 10;
1152 *(s++) = i + '0';
1153 *(s++) = ')';
1154 *(s++) = ' ';
1155 while (len-- > 0)
1157 i = (unsigned char) *(p++);
1158 *(s++) = AsciiHex[ 2* i ];
1159 *(s++) = AsciiHex[ 1+ 2*i ];
1161 *s = 0; // zero terminate the "bytes" string
1162 lvi.iSubItem = 1;
1163 CallWindowProc(wListView,hL[1],LVM_SETITEMTEXT,(WPARAM) AsmLineCount,(LPARAM) &lvi);
1164 // display the ASM text
1165 if (UprCase != FALSE) // do any requested uppercase conversion on the text
1166 upr(tmpcf);
1167 lvi.iSubItem = 2;
1168 lvi.pszText = tmpcf;
1169 CallWindowProc(wListView,hL[1],LVM_SETITEMTEXT,(WPARAM) AsmLineCount,(LPARAM) &lvi);
1170 ++AsmLineCount;
1172 else
1173 BufEmpty = TRUE;
1175 if (AsmLineCount >= MaxLines) // disassembled enough lines?
1176 Go = FALSE;
1181 // Reload the entire Register window (hL[0]) with data
1182 void LoadRegList()
1184 int i, itemnum; // TODO: This routine needs a big rewrite to make it pretty
1185 bx_bool showEreg = TRUE;
1186 // ShowWindow(hL[0],SW_HIDE); // Hiding the windows causes way too much flicker
1187 FillRegs(); // get new values for rV local register array
1188 CallWindowProc(wListView,hL[0],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0); // destroy list
1189 // set general purpose Register ListView Item "group" = 0
1190 // groupId sets a little text header in the Listview -- but is not Pre-WinXP compatible
1191 #ifndef IS_WIN98
1192 lviG.iGroupId = 0;
1193 #endif
1195 LV_ITEM lvi = {LVIF_TEXT,0,0,0,0,(LPSTR) tmpce,80,0,0};
1196 // Display GP registers -- 64 bit registers first, if they exist
1197 itemnum = 0;
1198 if (In64Mode != FALSE)
1200 showEreg = SeeReg[0]; // get user option setting for EAX, etc.
1201 for (i = RAX_Rnum ; i <= R15_Rnum ; i++)
1203 RitemToRnum[itemnum] = i; // always recreate the register -> itemnum mapping
1204 lviG.iItem = itemnum;
1205 lviG.pszText = RDispName[i];
1206 CallWindowProc(wListView,hL[0],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
1208 lvi.iItem = itemnum;
1209 sprintf(tmpce,"%I64d",rV[i]); // print the decimal column
1210 lvi.iSubItem = 2;
1211 CallWindowProc(wListView,hL[0],LVM_SETITEMTEXT,(WPARAM) itemnum,(LPARAM) &lvi);
1213 sprintf(tmpce,Fmt64b[UprCase],rV[i]); // and hex
1214 lvi.iSubItem = 1;
1215 CallWindowProc(wListView,hL[0],LVM_SETITEMTEXT,(WPARAM) itemnum,(LPARAM) &lvi);
1216 ++itemnum;
1221 // then 32bit GP registers (if appropriate)
1222 if (showEreg != FALSE)
1224 for (i = EAX_Rnum ; i <= EIP_Rnum ; i++)
1226 RitemToRnum[itemnum] = i;
1227 lviG.iItem = itemnum;
1228 lviG.pszText = RDispName[i];
1230 if (In32Mode == FALSE && i == 26) // Check for Real Mode (Pmode is TRUE in Long Mode)
1232 rV[EIP_Rnum] &= 0xffff; // in Real Mode, mask IP to 2 bytes
1233 ++(lviG.pszText); // and shorten name to 2 letters
1235 CallWindowProc(wListView,hL[0],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
1237 lvi.iItem = itemnum;
1238 sprintf(tmpce,"%I64d",rV[i]); // print the decimal column
1239 lvi.iSubItem = 2;
1240 CallWindowProc(wListView,hL[0],LVM_SETITEMTEXT,(WPARAM) itemnum,(LPARAM) &lvi);
1242 sprintf(tmpce,Fmt32b[UprCase],(Bit32u)rV[i]); // and hex
1243 lvi.iSubItem = 1;
1244 CallWindowProc(wListView,hL[0],LVM_SETITEMTEXT,(WPARAM) itemnum,(LPARAM) &lvi);
1245 ++itemnum;
1248 // always insert eflags next
1249 RitemToRnum[itemnum] = EFL_Rnum;
1250 lviG.iItem = itemnum;
1251 lviG.pszText = RDispName[EFL_Rnum];
1252 CallWindowProc(wListView,hL[0],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
1254 sprintf(tmpce,Fmt32b[UprCase],(Bit32u)rV[EFL_Rnum]);
1255 lvi.iItem = itemnum; // SubItem is already 1
1256 CallWindowProc(wListView,hL[0],LVM_SETITEMTEXT,(WPARAM) itemnum,(LPARAM) &lvi);
1257 ++itemnum;
1259 if (rV[EFL_Rnum] != PV[EFL_Rnum])
1260 StatusChange = TRUE; // if eflags changed, force a status update
1262 // display Segment registers (if requested)
1263 if (SeeReg[1])
1265 #ifndef IS_WIN98
1266 lviG.iGroupId = 1;
1267 #endif
1268 for(i = CS_Rnum ; i <= GS_Rnum ; i++) // segment registers
1270 RitemToRnum[itemnum] = i;
1271 lviG.iItem = itemnum;
1272 lviG.pszText = RDispName[i];
1273 CallWindowProc(wListView,hL[0],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
1274 sprintf(tmpce,Fmt16b[UprCase], rV[i] & 0xffff);
1275 lvi.iItem = itemnum; // SubItem is already 1
1276 CallWindowProc(wListView,hL[0],LVM_SETITEMTEXT,(WPARAM) itemnum,(LPARAM) &lvi);
1277 ++itemnum;
1280 // display System regsiters (if requested)
1281 // displaying these once is necessary for column resizing
1282 if (SeeReg[2] || ResizeColmns)
1284 #ifndef IS_WIN98
1285 lviG.iGroupId = 1;
1286 #endif
1287 int j = TRRnum;
1288 if (In32Mode == FALSE) // don't show lgdt or tr in Real mode
1289 j= IDTRnum;
1290 for(i = GDTRnum ; i <= j ; i++)
1292 RitemToRnum[itemnum] = i;
1293 lviG.iItem = itemnum;
1294 lviG.pszText = RDispName[i];
1295 CallWindowProc(wListView,hL[0],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
1297 if (i == GDTRnum || i == IDTRnum)
1299 Bit16u limit = GDT_Len;
1300 if (i == IDTRnum)
1301 limit = IDT_Len;
1302 if (In64Mode == FALSE)
1303 sprintf(tmpce,xDT32Fmt[UprCase],(Bit32u)rV[i],limit);
1304 else
1305 sprintf(tmpce,xDT64Fmt[UprCase],rV[i],limit);
1308 else
1309 sprintf(tmpce,Fmt16b[UprCase], rV[i] & 0xffff); // lgdt, tr
1311 lvi.iItem = itemnum; // SubItem is already 1
1312 CallWindowProc(wListView,hL[0],LVM_SETITEMTEXT,(WPARAM) itemnum,(LPARAM) &lvi);
1313 ++itemnum;
1316 // display Control Registers (if requested)
1317 if (SeeReg[3])
1319 #ifndef IS_WIN98
1320 lviG.iGroupId = 2;
1321 #endif
1322 for(i = CR0_Rnum ; i <= EFER_Rnum ; i++)
1324 RitemToRnum[itemnum] = i;
1325 lviG.iItem = itemnum;
1326 lviG.pszText = RDispName[i];
1327 CallWindowProc(wListView,hL[0],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
1329 sprintf(tmpce,"%08X",(Bit32u)rV[i]);
1330 lvi.iItem = itemnum; // SubItem is already 1
1331 CallWindowProc(wListView,hL[0],LVM_SETITEMTEXT,(WPARAM) itemnum,(LPARAM) &lvi);
1332 ++itemnum;
1336 // set the register background colors for rV
1337 i = EFER_Rnum + 1; // total number of registers stored in rV
1338 while (--i >= 0)
1340 if (rV[i] != PV[i]) // set the "red" flag if value changed
1341 RegColor[i] |= 0x80;
1342 else
1343 RegColor[i] &= 0x7f;
1345 // Load any optional STi, MMX, SSE, DRx, TRx register info into the Register window (hL[0])
1346 #if BX_SUPPORT_FPU
1347 // MMX-FPU registers
1348 if (SeeReg[4] != FALSE)
1349 itemnum = FillMMX(itemnum);
1350 #endif
1352 #if BX_SUPPORT_SSE
1353 // SSE registers
1354 if (SeeReg[5] != FALSE)
1355 itemnum = FillSSE(itemnum);
1356 #endif
1358 // Internal x86 Debug Registers
1359 if (SeeReg[6] != FALSE)
1360 itemnum = FillDebugRegs(itemnum);
1362 // if (SeeReg[7] != FALSE) // Test registers are not supported yet in bochs
1363 // FillTRXRegs(itemnum);
1365 if (ResizeColmns != FALSE) // resize Hex Value column sometimes
1366 CallWindowProc(wListView, hL[0], LVM_SETCOLUMNWIDTH, 1, LVSCW_AUTOSIZE);
1368 ShowWindow(hL[0],SW_SHOW);
1371 // scroll ASM window so that the current line is in the "middle"
1372 void doAsmScroll()
1374 int j;
1375 int CurTopIdx = CallWindowProc(wListView,hL[1],LVM_GETTOPINDEX,(WPARAM) 0,(LPARAM) 0);
1376 int nli = -2;
1377 // Can the current line be displayed at all?
1378 if (CurrentAsmLA < *AsmLA || CurrentAsmLA > AsmLA[AsmLineCount-1])
1379 return;
1380 // convert from LA to a Line Index (nli) with a search
1381 j = CurTopIdx; // try to start at CurTopIdx
1382 if (AsmLA[j] > CurrentAsmLA)
1383 j = 0;
1384 while (nli < 0 && j < AsmLineCount && AsmLA[j] <= CurrentAsmLA)
1386 if (AsmLA[j] == CurrentAsmLA)
1387 nli = j;
1388 ++j;
1390 // not found -> CurrentAsmLA is an illegal opcode address
1391 if (nli < 0)
1392 return;
1393 // is the current line ALREADY in the middle of the window?
1394 if (nli < CurTopIdx || nli >= CurTopIdx + AsmPgSize - bottommargin)
1396 // need to scroll!
1397 int ScrollLines = nli - CurTopIdx - topmargin;
1398 j = AsmLineCount - CurTopIdx - AsmPgSize;
1399 // limit ScrollLines by the theoretical max and min
1400 if (ScrollLines > j)
1401 ScrollLines = j + 1; // just a little extra to make sure
1402 if (ScrollLines < -CurTopIdx)
1403 ScrollLines = -CurTopIdx - 1; // just a little extra to make sure
1404 // convert # of scroll lines to pixels
1405 CallWindowProc(wListView,hL[1],LVM_SCROLL,(WPARAM) 0,(LPARAM) (ScrollLines * ListLineRatio));
1407 InvalidateRect(hL[1],0,TRUE); // "current opcode" in ASM window needs redrawing
1410 // try to find a Linear Address to start a "pretty" autodisassembly
1411 void CanDoLA(Bit64u *h)
1413 int index;
1414 if (TopAsmLA > *h || *h > AsmLA[AsmLineCount-1]) // is it hopeless?
1415 return;
1416 if (bottommargin > AsmLineCount)
1417 index = 0;
1418 else
1419 index = AsmLineCount - bottommargin;
1420 while (++index < AsmLineCount)
1422 if (AsmLA[index] == *h)
1424 *h = AsmLA[index - topmargin];
1425 return;
1430 void InitRegObjects()
1432 bx_list_c *cpu_list;
1433 extern bx_list_c *root_param;
1434 int j = TotCPUs;
1435 // get the param tree interface objects for every single register on all CPUs
1436 while (--j >= 0)
1438 // RegObject[j]s are all initted to NULL when allocated in the BSS area
1439 // but it doesn't hurt anything to do it again, once
1440 int i = TOT_REG_NUM + EXTRA_REGS;
1441 while (--i >= 0)
1442 RegObject[j][i] = (bx_param_num_c *) NULL;
1443 sprintf (tmpce,"bochs.cpu%d",j); // set the "cpu number" for cpu_list
1444 cpu_list = (bx_list_c *) SIM->get_param(tmpce,root_param);
1445 // TODO: in the next version, put all the names in an array, and loop
1446 // -- but that method is not compatible with bochs 2.3.7 or earlier
1447 #if BX_SUPPORT_X86_64 == 0
1448 RegObject[j][EAX_Rnum] = SIM->get_param_num("EAX", cpu_list);
1449 RegObject[j][EBX_Rnum] = SIM->get_param_num("EBX", cpu_list);
1450 RegObject[j][ECX_Rnum] = SIM->get_param_num("ECX", cpu_list);
1451 RegObject[j][EDX_Rnum] = SIM->get_param_num("EDX", cpu_list);
1452 RegObject[j][ESI_Rnum] = SIM->get_param_num("ESI", cpu_list);
1453 RegObject[j][EDI_Rnum] = SIM->get_param_num("EDI", cpu_list);
1454 RegObject[j][EBP_Rnum] = SIM->get_param_num("EBP", cpu_list);
1455 RegObject[j][ESP_Rnum] = SIM->get_param_num("ESP", cpu_list);
1456 RegObject[j][EIP_Rnum] = SIM->get_param_num("EIP", cpu_list);
1457 #else
1458 RegObject[j][RAX_Rnum] = SIM->get_param_num("RAX", cpu_list);
1459 RegObject[j][RBX_Rnum] = SIM->get_param_num("RBX", cpu_list);
1460 RegObject[j][RCX_Rnum] = SIM->get_param_num("RCX", cpu_list);
1461 RegObject[j][RDX_Rnum] = SIM->get_param_num("RDX", cpu_list);
1462 RegObject[j][RSI_Rnum] = SIM->get_param_num("RSI", cpu_list);
1463 RegObject[j][RDI_Rnum] = SIM->get_param_num("RDI", cpu_list);
1464 RegObject[j][RBP_Rnum] = SIM->get_param_num("RBP", cpu_list);
1465 RegObject[j][RSP_Rnum] = SIM->get_param_num("RSP", cpu_list);
1466 RegObject[j][RIP_Rnum] = SIM->get_param_num("RIP", cpu_list);
1467 RegObject[j][R8_Rnum] = SIM->get_param_num("R8", cpu_list);
1468 RegObject[j][R9_Rnum] = SIM->get_param_num("R9", cpu_list);
1469 RegObject[j][R10_Rnum] = SIM->get_param_num("R10", cpu_list);
1470 RegObject[j][R11_Rnum] = SIM->get_param_num("R11", cpu_list);
1471 RegObject[j][R12_Rnum] = SIM->get_param_num("R12", cpu_list);
1472 RegObject[j][R13_Rnum] = SIM->get_param_num("R13", cpu_list);
1473 RegObject[j][R14_Rnum] = SIM->get_param_num("R14", cpu_list);
1474 RegObject[j][R15_Rnum] = SIM->get_param_num("R15", cpu_list);
1475 #endif
1476 RegObject[j][EFL_Rnum]= SIM->get_param_num("EFLAGS", cpu_list);
1477 RegObject[j][CS_Rnum]= SIM->get_param_num("CS.selector", cpu_list);
1478 RegObject[j][DS_Rnum]= SIM->get_param_num("DS.selector", cpu_list);
1479 RegObject[j][ES_Rnum]= SIM->get_param_num("ES.selector", cpu_list);
1480 RegObject[j][SS_Rnum]= SIM->get_param_num("SS.selector", cpu_list);
1481 RegObject[j][FS_Rnum]= SIM->get_param_num("FS.selector", cpu_list);
1482 RegObject[j][GS_Rnum]= SIM->get_param_num("GS.selector", cpu_list);
1483 RegObject[j][GDTRnum]= SIM->get_param_num("GDTR.base", cpu_list);
1484 RegObject[j][GDTR_Lim]= SIM->get_param_num("GDTR.limit", cpu_list);
1485 RegObject[j][IDTRnum]= SIM->get_param_num("IDTR.base", cpu_list);
1486 RegObject[j][IDTR_Lim]= SIM->get_param_num("IDTR.limit", cpu_list);
1487 RegObject[j][LDTRnum]= SIM->get_param_num("LDTR.base", cpu_list);
1488 RegObject[j][TRRnum]= SIM->get_param_num("TR.base", cpu_list);
1489 RegObject[j][CR0_Rnum]= SIM->get_param_num("CR0", cpu_list);
1490 RegObject[j][CR3_Rnum]= SIM->get_param_num("CR3", cpu_list);
1491 #if BX_CPU_LEVEL >= 4
1492 RegObject[j][CR4_Rnum] = SIM->get_param_num("CR4", cpu_list);
1493 #endif
1494 #if BX_SUPPORT_X86_64
1495 RegObject[j][EFER_Rnum]= SIM->get_param_num("MSR.EFER", cpu_list);
1496 #endif
1497 #if BX_SUPPORT_FPU
1498 RegObject[j][ST0_Rnum]= SIM->get_param_num("FPU.st0.fraction", cpu_list);
1499 RegObject[j][ST1_Rnum]= SIM->get_param_num("FPU.st1.fraction", cpu_list);
1500 RegObject[j][ST2_Rnum]= SIM->get_param_num("FPU.st2.fraction", cpu_list);
1501 RegObject[j][ST3_Rnum]= SIM->get_param_num("FPU.st3.fraction", cpu_list);
1502 RegObject[j][ST4_Rnum]= SIM->get_param_num("FPU.st4.fraction", cpu_list);
1503 RegObject[j][ST5_Rnum]= SIM->get_param_num("FPU.st5.fraction", cpu_list);
1504 RegObject[j][ST6_Rnum]= SIM->get_param_num("FPU.st6.fraction", cpu_list);
1505 RegObject[j][ST7_Rnum]= SIM->get_param_num("FPU.st7.fraction", cpu_list);
1506 RegObject[j][ST0_exp]= SIM->get_param_num("FPU.st0.exp", cpu_list);
1507 RegObject[j][ST1_exp]= SIM->get_param_num("FPU.st1.exp", cpu_list);
1508 RegObject[j][ST2_exp]= SIM->get_param_num("FPU.st2.exp", cpu_list);
1509 RegObject[j][ST3_exp]= SIM->get_param_num("FPU.st3.exp", cpu_list);
1510 RegObject[j][ST4_exp]= SIM->get_param_num("FPU.st4.exp", cpu_list);
1511 RegObject[j][ST5_exp]= SIM->get_param_num("FPU.st5.exp", cpu_list);
1512 RegObject[j][ST6_exp]= SIM->get_param_num("FPU.st6.exp", cpu_list);
1513 RegObject[j][ST7_exp]= SIM->get_param_num("FPU.st7.exp", cpu_list);
1514 #endif
1515 #if BX_SUPPORT_SSE
1516 RegObject[j][XMM0_Rnum]= SIM->get_param_num("SSE.xmm00_lo", cpu_list);
1517 RegObject[j][XMM1_Rnum]= SIM->get_param_num("SSE.xmm01_lo", cpu_list);
1518 RegObject[j][XMM2_Rnum]= SIM->get_param_num("SSE.xmm02_lo", cpu_list);
1519 RegObject[j][XMM3_Rnum]= SIM->get_param_num("SSE.xmm03_lo", cpu_list);
1520 RegObject[j][XMM4_Rnum]= SIM->get_param_num("SSE.xmm04_lo", cpu_list);
1521 RegObject[j][XMM5_Rnum]= SIM->get_param_num("SSE.xmm05_lo", cpu_list);
1522 RegObject[j][XMM6_Rnum]= SIM->get_param_num("SSE.xmm06_lo", cpu_list);
1523 RegObject[j][XMM7_Rnum]= SIM->get_param_num("SSE.xmm07_lo", cpu_list);
1524 RegObject[j][XMM0_hi]= SIM->get_param_num("SSE.xmm00_hi", cpu_list);
1525 RegObject[j][XMM1_hi]= SIM->get_param_num("SSE.xmm01_hi", cpu_list);
1526 RegObject[j][XMM2_hi]= SIM->get_param_num("SSE.xmm02_hi", cpu_list);
1527 RegObject[j][XMM3_hi]= SIM->get_param_num("SSE.xmm03_hi", cpu_list);
1528 RegObject[j][XMM4_hi]= SIM->get_param_num("SSE.xmm04_hi", cpu_list);
1529 RegObject[j][XMM5_hi]= SIM->get_param_num("SSE.xmm05_hi", cpu_list);
1530 RegObject[j][XMM6_hi]= SIM->get_param_num("SSE.xmm06_hi", cpu_list);
1531 RegObject[j][XMM7_hi]= SIM->get_param_num("SSE.xmm07_hi", cpu_list);
1532 #if BX_SUPPORT_X86_64
1533 RegObject[j][XMM8_Rnum]= SIM->get_param_num("SSE.xmm08_lo", cpu_list);
1534 RegObject[j][XMM9_Rnum]= SIM->get_param_num("SSE.xmm09_lo", cpu_list);
1535 RegObject[j][XMMA_Rnum]= SIM->get_param_num("SSE.xmm10_lo", cpu_list);
1536 RegObject[j][XMMB_Rnum]= SIM->get_param_num("SSE.xmm11_lo", cpu_list);
1537 RegObject[j][XMMC_Rnum]= SIM->get_param_num("SSE.xmm12_lo", cpu_list);
1538 RegObject[j][XMMD_Rnum]= SIM->get_param_num("SSE.xmm13_lo", cpu_list);
1539 RegObject[j][XMME_Rnum]= SIM->get_param_num("SSE.xmm14_lo", cpu_list);
1540 RegObject[j][XMMF_Rnum]= SIM->get_param_num("SSE.xmm15_lo", cpu_list);
1541 RegObject[j][XMM8_hi]= SIM->get_param_num("SSE.xmm08_hi", cpu_list);
1542 RegObject[j][XMM9_hi]= SIM->get_param_num("SSE.xmm09_hi", cpu_list);
1543 RegObject[j][XMMA_hi]= SIM->get_param_num("SSE.xmm00_hi", cpu_list);
1544 RegObject[j][XMMB_hi]= SIM->get_param_num("SSE.xmm11_hi", cpu_list);
1545 RegObject[j][XMMC_hi]= SIM->get_param_num("SSE.xmm12_hi", cpu_list);
1546 RegObject[j][XMMD_hi]= SIM->get_param_num("SSE.xmm13_hi", cpu_list);
1547 RegObject[j][XMME_hi]= SIM->get_param_num("SSE.xmm14_hi", cpu_list);
1548 RegObject[j][XMMF_hi]= SIM->get_param_num("SSE.xmm15_hi", cpu_list);
1549 #endif // 64bit
1550 #endif // SSE
1551 RegObject[j][DR0_Rnum]= SIM->get_param_num("DR0", cpu_list);
1552 RegObject[j][DR1_Rnum]= SIM->get_param_num("DR1", cpu_list);
1553 RegObject[j][DR2_Rnum]= SIM->get_param_num("DR2", cpu_list);
1554 RegObject[j][DR3_Rnum]= SIM->get_param_num("DR3", cpu_list);
1555 RegObject[j][DR6_Rnum]= SIM->get_param_num("DR6", cpu_list);
1556 RegObject[j][DR7_Rnum]= SIM->get_param_num("DR7", cpu_list);
1557 // is there an #if for whether the test registers are supported?
1558 // RegObject[j][71]= SIM->get_param_num("TR3", cpu_list);
1559 // {"TR3","TR4","TR5","TR6","TR7"};
1564 // set all TRUE flags to checked in the Options menu, gray out unsupported features
1565 void InitMenus()
1567 int i = 8;
1568 doOneTimeInit = FALSE;
1569 EnableMenuItem (hOptMenu, CMD_EREG, MF_GRAYED);
1570 EnableMenuItem (hCmdMenu, CMD_WPTWR, MF_GRAYED);
1571 EnableMenuItem (hCmdMenu, CMD_WPTRD, MF_GRAYED);
1572 // 32bit registers are always displayed until longmode is active
1573 while (--i >= 0)
1575 if (SeeReg[i] != FALSE)
1576 CheckMenuItem (hOptMenu, i + CMD_EREG, MF_CHECKED);
1578 if (ShowButtons != FALSE)
1579 CheckMenuItem (hOptMenu, CMD_SBTN, MF_CHECKED);
1580 if (UprCase != 0)
1581 CheckMenuItem (hOptMenu, CMD_UCASE, MF_CHECKED);
1582 if (isLittleEndian != FALSE)
1583 CheckMenuItem (hOptMenu, CMD_LEND, MF_CHECKED);
1584 if (ignSSDisasm != FALSE)
1585 CheckMenuItem (hOptMenu, CMD_IGNSA, MF_CHECKED);
1586 if (ignoreNxtT != FALSE)
1587 CheckMenuItem (hOptMenu, CMD_IGNNT, MF_CHECKED);
1588 if (SeeRegColors != FALSE)
1589 CheckMenuItem (hOptMenu, CMD_RCLR, MF_CHECKED);
1590 if ((DumpInAsciiMode & 2) != 0)
1591 CheckMenuItem (hOptMenu, CMD_MHEX, MF_CHECKED);
1592 if ((DumpInAsciiMode & 1) != 0)
1593 CheckMenuItem (hOptMenu, CMD_MASCII, MF_CHECKED);
1594 if (ShowIOWindows != FALSE)
1595 CheckMenuItem (hOptMenu, CMD_IOWIN, MF_CHECKED);
1597 HMENU wsMenu = GetSubMenu (hOptMenu, WS_POPUP_IDX);
1598 CheckMenuItem (wsMenu, CMD_WS_1, MF_CHECKED);
1599 EnableMenuItem (hOptMenu, CMD_TREG, MF_GRAYED); // not currently supported by bochs
1600 EnableMenuItem (hViewMenu, CMD_PAGEV, MF_GRAYED);
1601 #if BX_SUPPORT_FPU == 0
1602 EnableMenuItem (hOptMenu, CMD_FPUR, MF_GRAYED);
1603 #endif
1605 #if BX_SUPPORT_SSE == 0
1606 EnableMenuItem (hOptMenu, CMD_XMMR, MF_GRAYED);
1607 #endif
1610 void doUpdate()
1612 void FillStack();
1613 if (doOneTimeInit != FALSE)
1614 InitMenus();
1615 // begin an autoupdate of Register and Asm windows
1616 LoadRegList(); // build and show ListView
1617 ParseBkpt(); // get the linear breakpoint list
1618 if (DViewMode == VIEW_STACK) // in stack view mode, keep the stack updated
1619 FillStack();
1620 CurrentAsmLA = BX_CPU(CurrentCPU)->get_laddr(BX_SEG_REG_CS, (bx_address) rV[RIP_Rnum]);
1621 // ShowWindow(hL[1],SW_HIDE); // Hiding the windows causes way too much flicker
1622 if (CurrentAsmLA < BottomAsmLA || CurrentAsmLA > TopAsmLA)
1624 Bit64u h = CurrentAsmLA;
1625 // generate a startLA (= h) that overlaps by topmargin, if possible
1626 CanDoLA(&h);
1628 FillAsm(h, DefaultAsmLines);
1629 if (ResizeColmns != FALSE)
1631 // recalculate # of list items per page for all list windows
1632 AsmPgSize = CallWindowProc(wListView,hL[1],LVM_GETCOUNTPERPAGE,(WPARAM) 0,(LPARAM) 0);
1633 if (AsmPgSize != 0)
1634 ListLineRatio = ListVerticalPix / AsmPgSize;
1635 CallWindowProc(wListView, hL[1], LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
1638 // Set the scroll position for the new ASM window
1639 BottomAsmLA = *AsmLA;
1640 int j = bottommargin; // try to use this bottom margin on ASM window
1641 if (j > AsmLineCount)
1642 j = AsmLineCount;
1643 TopAsmLA = AsmLA[AsmLineCount - j]; //TopAsmLA is the scroll point
1645 doAsmScroll(); // ASM window may need to scroll
1646 ShowWindow(hL[1],SW_SHOW);
1647 ResizeColmns = FALSE; // done with reformatting, if it was needed
1648 UpdateStatus(); // Mode and Eflags may have changed status
1651 // squish the MemDump columns to 0 width, in preparation for resizing
1652 void ZeroDColumns()
1654 int i = 17; // never change the size of the last column
1655 while (--i >= 0)
1656 CallWindowProc(wListView, hL[2], LVM_SETCOLUMNWIDTH, i, 0);
1659 // Fill the GDT ListView, reading GDT data directly from bochs linear mem
1660 void FillGDT()
1662 Bit64u laddr;
1663 unsigned int i, j;
1664 unsigned int k = (GDT_Len + 1) / 8;
1665 char *info;
1666 Bit8u gdtbuf[8];
1667 LV_ITEM lvi = {LVIF_TEXT,0,0,0,0,(LPSTR) 0,100,0,0};
1668 doDumpRefresh = FALSE;
1670 laddr = rV[GDTRnum] & (~7); // recover the GDT base address (force 8b align)
1671 CallWindowProc(wListView,hL[2],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
1672 ZeroDColumns();
1674 for(i = 0 ; i < k ; i++)
1676 // read 2 dwords from bochs linear mem into "buffer"
1677 lviG.iItem = i;
1678 lviG.pszText = tmpce;
1679 sprintf(tmpce,"%02u (Selector 0x%04X)",i,i << 3);
1680 CallWindowProc(wListView,hL[2],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
1681 lvi.iItem = i;
1682 lvi.pszText = tmpce;
1683 if (ReadBxLMem(laddr, 8, gdtbuf) == FALSE) // abort the current GDT dump on a memory error
1685 sprintf (tmpce,"illegal address");
1686 lvi.iSubItem = 17;
1687 CallWindowProc(wListView,hL[2],LVM_SETITEMTEXT,(WPARAM) i,(LPARAM) &lvi);
1688 break;
1690 laddr += 8;
1692 // enforce proper littleendianness on the gdtbuf bytes
1693 Bit32u limit = gdtbuf[0] | ((Bit32u) gdtbuf[1] << 8);
1694 limit |= ((Bit32u)gdtbuf[6] & 0xf) << 16;
1695 if ((gdtbuf[6] & 0x80) != 0) // 'Granularity' bit = 4K limit multiplier
1696 limit = limit * 4096 + 4095; // and the bottom 12 bits aren't tested
1698 info = GDTsT[0]; // default info string is blank
1699 j = 8; // default GDT type (group) is blank
1700 if ((gdtbuf[5] & 0x10) == 0) // 'S' bit clear = System segment
1702 #ifndef IS_WIN98
1703 lviG.iGroupId = 1;
1704 if (limit == 0 && (gdtbuf[5] & 0x80) == 0) // 'P' (present) bit
1705 lviG.iGroupId = 0;
1706 #endif
1707 // point to the approprate info string for the GDT system segment type
1708 info = GDTsT[(int) (gdtbuf[5] & 0xf)];
1710 else // it's an 'executable' code or data segment
1712 j = (gdtbuf[6] & 0x60) >> 5; // get the 'L' and 'D/B' bits
1713 if (j == 3) // both bits set is illegal
1714 j = 6;
1715 else if ((gdtbuf[5] & 0x8) == 0)
1716 j += 3; // data = 3 to 5, code = 0 to 2
1718 #ifndef IS_WIN98
1719 lviG.iGroupId = j; // use GroupIDs on XP and higher systems
1720 #else
1721 info = GDTt2[j]; // otherwise, put descriptive text in "info" column
1722 #endif
1725 // enforce proper littleendianness on the gdtbuf bytes
1726 Bit32u base = gdtbuf[2] | ((Bit32u) gdtbuf[3] << 8);
1727 base |= (Bit32u) gdtbuf[4] << 16;
1728 base |= (Bit32u) gdtbuf[7] << 24;
1729 if ((gdtbuf[6] & 0x60) == 0x20) // test for longmode segment
1731 base = 0; // the base is always 0 in longmode, with "no" limit
1732 sprintf(tmpcf,"0xFFFFFFFFFFFFFFFF");
1734 else
1735 sprintf(tmpcf,"0x%X",limit);
1737 sprintf(tmpce,"0x%X",base);
1738 lvi.iSubItem = 1;
1739 CallWindowProc(wListView,hL[2],LVM_SETITEMTEXT,(WPARAM) i,(LPARAM) &lvi);
1741 sprintf(tmpce,"%u", (gdtbuf[5] & 0x60) >> 5);
1742 lvi.iSubItem = 3;
1743 CallWindowProc(wListView,hL[2],LVM_SETITEMTEXT,(WPARAM) i,(LPARAM) &lvi);
1745 lvi.iSubItem = 2;
1746 lvi.pszText = tmpcf;
1747 CallWindowProc(wListView,hL[2],LVM_SETITEMTEXT,(WPARAM) i,(LPARAM) &lvi);
1749 if (i == 0)
1750 info = GDTt2[7]; // call "Null" selector "unused"
1751 lvi.iSubItem = 17;
1752 lvi.pszText = info;
1753 CallWindowProc(wListView,hL[2],LVM_SETITEMTEXT,(WPARAM) i,(LPARAM) &lvi);
1755 // 2 of the GDT columns are too narrow with a regular Autosize
1756 LV_COLUMN lvgc = {LVCF_TEXT,0,0,tmpce};
1757 strcpy (tmpce,"Index"); // header for col 0
1758 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 0,(LPARAM) &lvgc);
1759 strcpy (tmpce,"Base"); // header for col 1
1760 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 1,(LPARAM) &lvgc);
1761 strcpy (tmpce,"Size"); // header for col 2
1762 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 2,(LPARAM) &lvgc);
1763 strcpy (tmpce,"DPL"); // header for col 3
1764 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 3,(LPARAM) &lvgc);
1765 strcpy (tmpce,"Info"); // header for col 4 (17)
1766 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 17,(LPARAM) &lvgc);
1767 CallWindowProc(wListView, hL[2], LVM_SETCOLUMNWIDTH, 1, LVSCW_AUTOSIZE_USEHEADER);
1768 CallWindowProc(wListView, hL[2], LVM_SETCOLUMNWIDTH, 3, LVSCW_AUTOSIZE_USEHEADER);
1769 CallWindowProc(wListView, hL[2], LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
1770 CallWindowProc(wListView, hL[2], LVM_SETCOLUMNWIDTH, 2, LVSCW_AUTOSIZE);
1771 ShowWindow(hL[2],SW_SHOW);
1775 // Fills the IDT ListView, reading IDT data directly from bochs linear mem
1776 void FillIDT()
1778 Bit64u laddr;
1779 Bit8u idtbuf[16];
1780 Bit16u sel;
1781 Bit32u ofs;
1782 unsigned entrysize;
1783 unsigned int i;
1784 LV_ITEM lvi = {LVIF_TEXT,0,17,0,0,(LPSTR) tmpce,100,0,0};
1785 unsigned int mode = 0;
1786 if (In32Mode != FALSE)
1787 mode = 1;
1788 if (In64Mode != FALSE)
1789 mode = 2;
1790 doDumpRefresh = FALSE;
1792 entrysize = 4 << mode ; // calculate the bytesize of the entries
1793 unsigned int k = (IDT_Len + 1) / entrysize;
1794 CallWindowProc(wListView,hL[2],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
1795 // force all column widths to 0
1796 ZeroDColumns();
1797 // recover the IDT linear base address (aligned)
1798 laddr = rV[IDTRnum] & (~(entrysize - 1));
1800 for(i = 0 ; i < k ; i++)
1802 // sprintf(info,"0x%02X",i);
1803 *tmpce = AsciiHex[ 2* i ];
1804 tmpce[1] = AsciiHex[ 1+ 2*i ];
1805 tmpce[2] = 0;
1806 lviG.iItem = i;
1807 lviG.pszText = tmpce;
1808 #ifndef IS_WIN98
1809 lviG.iGroupId = 8; // IDT "group" is always blank
1810 #endif
1811 int L = CallWindowProc(wListView,hL[2],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
1812 if (ReadBxLMem(laddr, entrysize, idtbuf) == FALSE) // abort the current IDT dump on a memory error
1814 sprintf (tmpce,"illegal address");
1815 CallWindowProc(wListView,hL[2],LVM_SETITEMTEXT,(WPARAM) L,(LPARAM) &lvi);
1816 break;
1818 laddr += entrysize;
1819 // enforce proper littleendianness on the idtbuf bytes
1820 ofs = idtbuf[0] | ((Bit32u) idtbuf[1] << 8);
1821 sel = idtbuf[2] | ((Bit16u) idtbuf[3] << 8);
1823 switch (mode)
1825 case 0: // Real Mode
1826 sprintf(tmpce,"0x%04X:0x%04X", sel, ofs);
1827 break;
1829 case 1: // Pmode
1830 ofs |= ((Bit32u) idtbuf[6] << 16) | ((Bit32u) idtbuf[7] << 24);
1831 sprintf(tmpce,"0x%04X:0x%08X", sel, ofs);
1832 // TODO: also print some flags from idtbuf[5], maybe, in another column
1833 break;
1835 case 2: // Lmode
1836 Bit64u off64 = (Bit64u)(ofs | ((Bit32u) idtbuf[6] << 16) | ((Bit32u) idtbuf[7] << 24));
1837 off64 |= ((Bit64u) idtbuf[8] << 32) | ((Bit64u) idtbuf[9] << 40);
1838 off64 |= ((Bit64u) idtbuf[10] << 48) | ((Bit64u) idtbuf[11] << 56);
1839 sprintf(tmpce,"0x%04X:0x%016I64X", sel, off64);
1840 // TODO: also print some flags from idtbuf[5], maybe, in another column
1841 break;
1844 lvi.iItem = L;
1845 CallWindowProc(wListView,hL[2],LVM_SETITEMTEXT,(WPARAM) L,(LPARAM) &lvi);
1847 LV_COLUMN lvgc = {LVCF_TEXT,0,0,tmpce};
1848 strcpy (tmpce,"Interrupt"); // header for col 0
1849 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 0,(LPARAM) &lvgc);
1850 strcpy (tmpce,"L.Address"); // header for col 1 (17)
1851 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 17,(LPARAM) &lvgc);
1852 // redo col0 to handle the wide header
1853 CallWindowProc(wListView, hL[2], LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE_USEHEADER);
1854 ShowWindow(hL[2],SW_SHOW);
1857 // insert one entry into the Paging data list -- col0 in tmpce, col1 in tmpcf
1858 void AddPagingLine(int LC)
1860 LV_ITEM lvi = {LVIF_TEXT,LC,17,0,0,(LPSTR) tmpcf,80,0,0};
1861 lviG.iItem = LC;
1862 lviG.pszText = tmpce;
1863 CallWindowProc(wListView,hL[2],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
1864 CallWindowProc(wListView,hL[2],LVM_SETITEMTEXT,(WPARAM) LC,(LPARAM) &lvi);
1867 // lifted from bx_dbg_dump_table in dbg_main of the internal debugger
1868 void FillPAGE()
1870 Bit32u lin, start_lin, curlin; // show only low 32 bit
1871 bx_phy_address phy;
1872 Bit64u start_phy, phy64;
1873 int LineCount = 0;
1874 doDumpRefresh = FALSE;
1875 #ifndef IS_WIN98
1876 lviG.iGroupId = 8; // Paging "group" is always blank
1877 #endif
1879 CallWindowProc(wListView,hL[2],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
1880 curlin = lin = 0; // always start at linear address 0
1881 start_lin = 1; // force a mismatch on the first line
1882 start_phy = 2;
1883 while (LineCount < 1024 && curlin != 0xfffff000)
1885 // get translation lin -> phys, and verify mapping is legal
1886 if (BX_CPU(CurrentCPU)->dbg_xlate_linear2phy(lin, &phy) != FALSE)
1888 phy64 = phy;
1889 if ((lin - start_lin) != (phy64 - start_phy))
1891 if (start_lin != 1)
1893 sprintf (tmpce,"0x%08X - 0x%08X",start_lin, lin - 1);
1894 sprintf (tmpcf,"0x%016I64X - 0x%016I64X",start_phy, start_phy + (lin-1-start_lin));
1895 AddPagingLine (LineCount);
1896 ++LineCount;
1898 start_lin = lin;
1899 start_phy = phy64;
1902 else
1904 if (start_lin != 1)
1906 sprintf (tmpce,"0x%08X - 0x%08X",start_lin, lin - 1);
1907 sprintf (tmpcf,"0x%016I64X - 0x%016I64X",start_phy, start_phy + (lin-1-start_lin));
1908 AddPagingLine (LineCount);
1909 ++LineCount;
1911 start_lin = 1;
1912 start_phy = 2;
1914 curlin = lin;
1915 lin += 0x1000; // then test the next 4K page in the loop
1917 if (start_lin != 1) // need to output one last line?
1919 sprintf (tmpce,"0x%08X - 0x%08X", start_lin, -1);
1920 sprintf (tmpcf,"0x%016I64X - 0x%016I64X",start_phy, start_phy -1 -start_lin);
1921 AddPagingLine (LineCount);
1923 ZeroDColumns();
1924 LV_COLUMN lvgc = {LVCF_TEXT,0,0,tmpce};
1925 strcpy (tmpce,"L.Address"); // header for col 0
1926 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 0,(LPARAM) &lvgc);
1927 strcpy (tmpce,"is mapped to P.Address"); // header for col 1 (17)
1928 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 17,(LPARAM) &lvgc);
1929 CallWindowProc(wListView, hL[2], LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
1930 ShowWindow(hL[2],SW_SHOW);
1934 // build the stack display
1935 void FillStack()
1937 Bit64u StackLA, EndLA;
1938 unsigned int len, i, wordsize, overlap;
1939 int j;
1940 bx_bool LglAddy;
1941 bx_bool HasNeg = FALSE;
1942 bx_bool UpdateDisp;
1943 char *cp, *cpp;
1945 doDumpRefresh = FALSE;
1946 lviG.pszText = tmpcf;
1947 StackLA = (Bit64u) BX_CPU(CurrentCPU)->get_laddr(BX_SEG_REG_SS, (bx_address) rV[RSP_Rnum]);
1949 if (PStackLA == 1) // illegal value requests a full refresh
1950 PStackLA = StackLA ^ 0x4000; // force a non-match below
1952 wordsize = 4; // assume Pmode
1953 if (In32Mode == FALSE)
1954 wordsize = 2;
1955 else if (In64Mode != FALSE)
1956 wordsize = 8;
1957 len = STACK_ENTRIES * wordsize;
1959 // TODO: enforce that tmpce is wordsize aligned
1960 // also -- enforce that StackLA is wordsize aligned
1961 cp = tmpce;
1962 i = (unsigned int) StackLA & 0xfff; // where is stack bottom, in its 4K memory page?
1963 if (i > 0x1000 - len) // does len cross a 4K boundary?
1965 unsigned int ReadSize = 0x1000 - i;
1966 // read up to the 4K boundary, then try to read the last chunk
1967 if (ReadBxLMem (StackLA, ReadSize, (Bit8u *) cp) == FALSE)
1969 // no data to show -- just an error message
1970 sprintf (tmpcf,"illegal address");
1971 CallWindowProc(wListView,hL[2],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
1972 CallWindowProc(wListView,hL[2],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
1973 CallWindowProc(wListView, hL[2], LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
1974 return;
1976 LglAddy = ReadBxLMem (StackLA + ReadSize, len + i - 0x1000, (Bit8u *) cp + ReadSize);
1977 if (LglAddy == FALSE)
1978 len = ReadSize;
1980 else
1981 ReadBxLMem (StackLA, len, (Bit8u *) cp);
1983 UpdateDisp = CpuModeChange; // calculate which stack entries have changed
1984 cp = tmpce;
1985 cpp = PrevStack;
1986 j = overlap = len / wordsize;
1987 while (--j >= 0)
1988 StackEntChg[j] = TRUE; // assume that all lines have changed
1989 if (PStackLA > StackLA) // calculate the overlap between the prev and current stacks
1991 EndLA = PStackLA - StackLA;
1992 if (EndLA < len)
1994 i = (unsigned int) (EndLA / wordsize);
1995 cp += i * wordsize;
1997 else
1998 i = overlap; // force the next loop to exit
2000 else
2002 EndLA = StackLA - PStackLA;
2003 if (EndLA < len)
2005 i = 0;
2006 j = (int) (EndLA / wordsize);
2007 cpp += j * wordsize;
2008 overlap -= j;
2010 else
2011 i = overlap; // force the next loop to exit
2013 while (i < overlap)
2015 j = wordsize; // if the two entries match, cancel the EntryChange flag for that entry
2016 while (j > 0 && *cp == *cpp)
2018 --j;
2019 ++cp;
2020 ++cpp;
2022 if (j == 0)
2023 StackEntChg[i] = FALSE; // got a match on all bytes
2024 else
2026 cp += j; // bump the pointers to the next stack entry
2027 cpp += j;
2029 ++i;
2031 j = len / wordsize;
2032 while (--j >= 0)
2033 UpdateDisp |= StackEntChg[j];
2034 if (UpdateDisp == FALSE) // Don't need to update the list? (no changes?)
2036 if (StkInvOnce == FALSE)
2037 InvalidateRect(hL[2],0,TRUE); // Invalidate ONCE to turn off all the red stuff
2038 StkInvOnce = TRUE;
2039 return;
2041 CallWindowProc(wListView,hL[2],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
2042 StkInvOnce = FALSE;
2043 PStackLA = StackLA;
2044 cp = tmpce;
2045 cpp = PrevStack;
2046 j = len;
2047 while (--j >= 0)
2048 *(cpp++)= *(cp++); // copy the stack to the Prev buffer
2049 j= STACK_ENTRIES * 8 - len;
2050 while (--j >= 0)
2051 *(cpp++)= 0; // zero out the unused tail end of the prev buffer
2052 cp = tmpce; // the following display loop runs on the cp pointer
2054 #ifndef IS_WIN98
2055 lviG.iGroupId = 8; // Stack "group" is always blank
2056 #endif
2057 LV_ITEM lvi = {LVIF_TEXT,0,0,0,0,(LPSTR) tmpcf,0,0,0};
2058 EndLA = StackLA + len - 1;
2059 i = 0;
2060 while (StackLA < EndLA)
2062 lviG.iItem = i;
2063 lvi.iItem = i;
2064 lvi.iSubItem = 1;
2065 if (In64Mode == FALSE)
2067 int tmp;
2068 sprintf (tmpcf,Fmt32b[1],StackLA);
2069 CallWindowProc(wListView,hL[2],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
2070 if (In32Mode == FALSE)
2071 tmp = *((Bit16s *) cp);
2072 else
2073 tmp = *((Bit32s *) cp);
2074 if (tmp < 0)
2075 HasNeg = TRUE;
2076 sprintf (tmpcf,"0x%X",tmp);
2077 CallWindowProc(wListView,hL[2],LVM_SETITEMTEXT,(WPARAM) i,(LPARAM) &lvi);
2078 sprintf (tmpcf,"%d",tmp);
2080 else
2082 Bit64s tmp = *((Bit64s *) cp);
2083 // don't bother testing negative -- 64b values are all the same length
2084 sprintf (tmpcf,Fmt64b[1],StackLA);
2085 CallWindowProc(wListView,hL[2],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
2086 sprintf (tmpcf,Fmt64b[1],tmp);
2087 CallWindowProc(wListView,hL[2],LVM_SETITEMTEXT,(WPARAM) i,(LPARAM) &lvi);
2088 sprintf (tmpcf,"%I64d",tmp);
2090 lvi.iSubItem = 17;
2091 CallWindowProc(wListView,hL[2],LVM_SETITEMTEXT,(WPARAM) i,(LPARAM) &lvi);
2092 StackLA += wordsize;
2093 cp += wordsize;
2094 ++i;
2096 if (StackSized == 0 || (StackSized == 1 && HasNeg != FALSE))
2098 // force all column widths to 0
2099 ZeroDColumns();
2100 LV_COLUMN lvgc = {LVCF_TEXT,0,0,tmpce};
2101 strcpy (tmpce,"L.Address"); // header for col 0
2102 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 0,(LPARAM) &lvgc);
2103 strcpy (tmpce,"Value"); // header for col 1
2104 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 1,(LPARAM) &lvgc);
2105 strcpy (tmpce,"(dec.)"); // header for col 2 (17)
2106 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 17,(LPARAM) &lvgc);
2107 CallWindowProc(wListView, hL[2], LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
2108 CallWindowProc(wListView, hL[2], LVM_SETCOLUMNWIDTH, 1, LVSCW_AUTOSIZE);
2109 StackSized = 1; // may need to resize a second time
2110 if (HasNeg != FALSE)
2111 StackSized = 2;
2113 ShowWindow(hL[2],SW_SHOW);
2117 // recurse displaying each leaf/branch of param_tree -- with values for each leaf
2118 void MakeBL(HTREEITEM h_P, bx_param_c *p)
2120 HTREEITEM h_new;
2121 bx_list_c *as_list = NULL;
2122 int i = 0;
2123 strcpy (tmpce, p->get_name());
2124 int j = strlen (tmpce);
2125 tvis.item.cChildren = 0;
2126 switch (p->get_type())
2128 case BXT_PARAM_NUM:
2129 if (((bx_param_num_c*)p)->get_base() == BASE_DEC)
2130 sprintf (tmpce + j,": %I64d",((bx_param_num_c*)p)->get64());
2131 else
2132 sprintf (tmpce + j,": 0x%0I64X",((bx_param_num_c*)p)->get64());
2133 break;
2134 case BXT_LIST:
2135 as_list = (bx_list_c *)p;
2136 tvis.item.cChildren = 1;
2137 i = as_list->get_size();
2138 break;
2139 case BXT_PARAM_BOOL:
2140 sprintf (tmpce + j,": %s",((bx_param_bool_c*)p)->get()?"true":"false");
2141 break;
2142 case BXT_PARAM_ENUM:
2143 sprintf (tmpce + j,": %s",((bx_param_enum_c*)p)->get_selected());
2144 break;
2145 case BXT_PARAM_STRING:
2146 if (((bx_param_string_c*)p)->get_options()->get() & bx_param_string_c::RAW_BYTES)
2148 char *cp = tmpce + j;
2149 unsigned char *rp = (unsigned char *)((bx_param_string_c*)p)->getptr();
2150 char sc = ((bx_param_string_c*)p)->get_separator();
2151 int k = ((bx_param_string_c*)p)->get_maxsize();
2152 *(cp++) = ':';
2153 *(cp++) = ' ';
2154 while (k-- > 0)
2156 *(cp++) = AsciiHex[2* *rp];
2157 *(cp++) = AsciiHex[2* *rp + 1];
2158 *(cp++) = sc;
2160 *--cp = 0; // overwrite the last separator char
2162 else
2163 sprintf (tmpce + j,": %s",((bx_param_string_c*)p)->getptr());
2164 break;
2165 case BXT_PARAM_DATA:
2166 sprintf (tmpce + j,": binary data, size=%d",((bx_shadow_data_c*)p)->get_size());
2168 tvis.hParent = h_P; // create leaves/recurse branches
2169 h_new = (HTREEITEM) CallWindowProc(wTreeView,hT,TVM_INSERTITEM,(WPARAM) 0,(LPARAM) &tvis);
2170 if (i > 0)
2172 while (--i >= 0)
2173 MakeBL(h_new, as_list->get(i));
2174 // sort this level of the tree alphabetically
2175 // CallWindowProc(wTreeView,hT,TVM_SORTCHILDREN,(WPARAM) 0,(LPARAM) h_new);
2180 void FillPTree()
2182 HTREEITEM h_PTroot;
2183 int i;
2184 extern bx_list_c *root_param;
2185 // Note: don't multithread this display -- the user expects it to complete
2186 doDumpRefresh = FALSE;
2187 ShowWindow(hL[2],SW_HIDE);
2188 TreeView_DeleteAllItems(hT);
2189 strcpy (tmpce, "bochs parameter tree");
2190 tvis.hParent = NULL; // create the root node
2191 tvis.item.mask = TVIF_TEXT | TVIF_CHILDREN | TVIF_STATE;
2192 tvis.hInsertAfter = (HTREEITEM)TVI_FIRST;
2193 tvis.item.pszText = tmpce;
2194 tvis.item.cchTextMax = 250;
2195 tvis.item.cChildren = 1;
2196 tvis.item.state = TVIS_EXPANDED; // it must be expanded to show the first layer
2197 tvis.item.stateMask = TVIS_EXPANDED;
2198 h_PTroot = TreeView_InsertItem(hT,&tvis);
2199 tvis.item.mask = TVIF_TEXT | TVIF_CHILDREN; // don't expand any other layers
2200 i = root_param->get_size();
2201 while (--i >= 0)
2202 MakeBL(h_PTroot, root_param->get(i));
2203 // sort this level of the tree alphabetically
2204 // CallWindowProc(wTreeView,hT,TVM_SORTCHILDREN,(WPARAM) 0,(LPARAM) h_PTroot);
2205 ShowWindow(hT,SW_SHOW);
2209 // performs endian byteswapping the hard way, for a Data dump
2210 void FillDataX(char* t,char C,bx_bool doHex)
2212 char *d = tmpce + 100; // the beginning of tmpce is being used by ShowData/SD_Thread
2213 if (isLittleEndian == FALSE || doHex == FALSE)
2214 d = t + strlen(t); // bigendian can always be appended directly
2215 *d = C;
2216 d[1] = 0;
2217 if (isprint(C) == 0)
2218 *d = '.';
2220 if (doHex != FALSE)
2222 *d = AsciiHex[ 2* (unsigned char)C ];
2223 d[1] = AsciiHex[ 1+ 2* (unsigned char)C ];
2224 d[2] = 0;
2225 if (isLittleEndian != FALSE) // little endian => reverse hex digits
2227 strcat(d,t);
2228 strcpy(t,d); // so append the new bytes to the FRONT of t
2233 // do the ShowData display work asynchronously, as a thread
2234 void ShowData()
2236 unsigned int i;
2237 char *x;
2238 LV_ITEM lvi = {LVIF_TEXT,0,0,0,0,(LPSTR) 0,80,0,0};
2240 doDumpRefresh = FALSE;
2241 // ShowWindow(hL[2],SW_HIDE); // Hiding the windows causes way too much flash
2242 CallWindowProc(wListView,hL[2],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
2244 lviG.pszText = tmpce;
2245 #ifndef IS_WIN98
2246 lviG.iGroupId = 8; // MemDump "group" is always blank
2247 #endif
2248 x = DataDump; // data dumps are ALWAYS 4K
2249 for(i = 0 ; i < 4096 ; i += 16)
2251 if (In64Mode == FALSE)
2252 sprintf(tmpce,"0x%08X",(Bit32u) (DumpStart + i));
2253 else
2254 sprintf(tmpce,"0x%016I64X",DumpStart + i);
2255 lviG.iItem = i>>4;
2256 int L = CallWindowProc(wListView,hL[2],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lviG);
2257 lvi.iItem = L;
2259 *tmpce = 0;
2260 *tmpcf = 0;
2261 for(unsigned int y = 0 ; y < 16 ; y++)
2263 if ((DumpInAsciiMode & 1) != 0)
2264 FillDataX(tmpcf,x[y],FALSE);
2266 if ((DumpInAsciiMode & 2) != 0)
2268 FillDataX(tmpce,x[y],TRUE);
2269 if (((y + 1) & (DumpAlign - 1)) == 0)
2271 lvi.pszText = tmpce;
2272 lvi.iSubItem = y+2-DumpAlign;
2273 CallWindowProc(wListView,hL[2],LVM_SETITEMTEXT,(WPARAM) L,(LPARAM) &lvi);
2274 *tmpce = 0; // FillDataX APPENDS, so you need to clear the buffer
2278 lvi.pszText = tmpcf;
2279 lvi.iSubItem = 17;
2280 if ((DumpInAsciiMode & 1) != 0)
2281 CallWindowProc(wListView,hL[2],LVM_SETITEMTEXT,(WPARAM) L,(LPARAM) &lvi);
2282 x+= 16; // bump to the next row of data
2285 CallWindowProc(wListView, hL[2], LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
2286 if (PrevDAD != DumpAlign)
2288 for(i = 1 ; i < 17 ; i++)
2290 // if dumping ONLY in ascii, 0 out ALL the other columns
2291 if (((i - 1) & (DumpAlign - 1)) == 0 && (DumpInAsciiMode & 2) != 0)
2292 CallWindowProc(wListView, hL[2], LVM_SETCOLUMNWIDTH, i, LVSCW_AUTOSIZE);
2293 else // force the width of unused columns to 0
2294 CallWindowProc(wListView, hL[2], LVM_SETCOLUMNWIDTH, i, 0);
2297 PrevDAD = DumpAlign;
2298 ShowWindow(hL[2],SW_SHOW);
2302 // build Register "display" names from lower case names
2303 // (must build the pointer list while building the names)
2304 void MakeRDnames()
2306 char *p, *c;
2308 p = RDispName[0]; // first storage location
2309 for (int i=0; i < 41; i++)
2311 RDispName[i] = p; // create the Name pointer
2312 c = RegLCName[i]; // Register name in lower case
2314 if (UprCase != 0)
2316 while (*c != 0)
2317 *(p++) = UCtable[(int) *(c++)]; // use lookup tbl for uppercase
2319 else
2321 while (*c != 0)
2322 *(p++) = *(c++);
2324 *(p++) = 0;
2328 // generic initialization routine -- called once, only at startup
2329 void DoAllInit()
2331 char *p;
2332 int i;
2334 i = TotCPUs;
2335 while (--i >= 0)
2336 BX_CPU(i)->mode_break = FALSE;
2337 // divide up the pre-allocated char buffer into smaller pieces
2338 p = bigbuf + outbufSIZE; // point at the end of preallocated mem
2339 p -= 200; // 200 bytes is enough for all the register names
2340 RDispName[0] = p;
2341 p -= 4096;
2342 DataDump = p; // storage for 4K memory dumps
2343 p -= OutWinCnt; // 10K for Output Window buffer
2344 OutWindow = p;
2345 i = 64;
2346 while (--i >= 0)
2348 p -= 80; // command history buffers are 80b each
2349 CmdHistory[i] = p; // set up 64 of them (5120b)
2350 *p = 0; // and clear each one
2352 p -= STACK_ENTRIES * 8; // usually a 400 byte buffer for the stack values
2353 PrevStack = p;
2354 p -= 512;
2355 tmpcf = p;
2356 p -= 512;
2357 tmpce = p;
2358 p -= 512;
2359 tmpcd = p;
2360 p -= 512;
2361 AsciiHex = p; // storage for the binary->ascii table
2362 p -= 512; // 2 "hex" bytes per byte value
2363 tmpcb = p;
2365 i = TOT_REG_NUM; // fake up a color table -- there are just enough, currently
2366 int j = 7; // color 7 = orange
2367 while (i > 0)
2369 // change color when the loop goes below the base register number
2370 // if (i == TRXR) --j; // 5 TRX registers -- currently don't exist
2371 if (i == DR0_Rnum) --j; // 6 Debug
2372 else if (i == XMM0_Rnum) --j; // 8 or 16 XMM
2373 else if (i == ST0_Rnum) --j; // 8 MMX/FPU
2374 else if (i == CR0_Rnum) --j; // EFER and CR
2375 else if (i == GDTRnum) --j; // Sys Registers
2376 else if (i == CS_Rnum) --j; // Segments
2377 else if (i == EAX_Rnum) --j; // GP Registers (32b)
2378 // below EAX is 64bit GP Registers and EFLAGS
2379 RegColor[--i] = j;
2382 MakeXlatTables(); // create UpperCase and AsciiHex translation tables
2383 MakeRDnames(); // create Rnames from lower-case register names
2384 InitRegObjects(); // get/store all the bx_param_num_c objects for the registers
2387 // Autosize "fixed size" ListView columns, every time the font changes.
2388 // This also runs once during the init sequence.
2389 void doAutoSize()
2391 ResizeColmns = TRUE; // force the "variable size" columns to resize, too
2392 // resize the "fixed size" columns (once only, perhaps)
2393 if (doOneTimeInit == TRUE)
2394 CallWindowProc(wListView, hL[1], LVM_SETCOLUMNWIDTH, 1, LVSCW_AUTOSIZE_USEHEADER); // "bytes" column
2395 CallWindowProc(wListView, hL[0], LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE_USEHEADER); // RegName column
2397 for (int i = 0; i < 17; i++)
2398 CallWindowProc(wListView, hL[2], LVM_SETCOLUMNWIDTH, i, LVSCW_AUTOSIZE_USEHEADER);
2401 // exit GDT/IDT/Paging/Stack/Tree -- back to the MemDump window
2402 void ShowMemData()
2404 LV_COLUMN lvgc = {LVCF_TEXT,0,0,tmpcb};
2405 ShowWindow(hT,SW_HIDE);
2406 ShowWindow(hL[2],SW_SHOW);
2407 DViewMode = VIEW_MEMDUMP; // returning to MemDump mode
2408 CallWindowProc(wTreeView,hT,TVM_DELETEITEM,(WPARAM) 0,(LPARAM) TVI_ROOT);
2409 // need to fix the MemDump column "names"
2410 strcpy (tmpcb,"0"); // rebuild header for col 1
2411 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 1,(LPARAM) &lvgc);
2412 // headers for cols 1 to 5, are just numbers 0 to 4
2413 *tmpcb = '1';
2414 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 2,(LPARAM) &lvgc);
2415 *tmpcb = '2';
2416 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 3,(LPARAM) &lvgc);
2417 strcpy (tmpcb,"Ascii"); // rebuild header for col 17
2418 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 17,(LPARAM) &lvgc);
2419 if (DumpInitted == FALSE)
2421 // GDT/IDT/PAGING data may be in the window
2422 CallWindowProc(wListView,hL[2],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
2423 strcpy (tmpcb,"Address"); // "generic" header for col 0
2424 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 0,(LPARAM) &lvgc);
2425 int i = 17; // never change the size of the last column
2426 while (--i >= 0) // can't repopulate -- just resize
2427 CallWindowProc(wListView, hL[2], LVM_SETCOLUMNWIDTH, i, LVSCW_AUTOSIZE_USEHEADER);
2429 else
2431 strcpy (tmpcb,DC0txt[DumpMode]); // "real" header for col 0
2432 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 0,(LPARAM) &lvgc);
2433 PrevDAD = 0; // force a column resize
2434 ShowData(); // repopulates & resizes all columns
2439 // refill whichever "data window" (hL[2]) is active -- or param_tree
2440 void RefreshDataWin()
2442 switch (DViewMode)
2444 case VIEW_MEMDUMP:
2445 if (DumpInitted != FALSE)
2446 ShowData();
2447 else
2448 ShowWindow(hL[2],SW_SHOW);
2449 break;
2450 case VIEW_GDT:
2451 FillGDT();
2452 break;
2453 case VIEW_IDT:
2454 FillIDT();
2455 break;
2456 case VIEW_PAGING:
2457 FillPAGE();
2458 break;
2459 case VIEW_STACK:
2460 PStackLA = 1; // flag to force a full stack refresh
2461 FillStack();
2462 break;
2463 case VIEW_PTREE:
2464 FillPTree();
2468 // performs tasks whenever the simulation "breaks"
2469 void OnBreak()
2471 int i = EFER_Rnum + 1;
2472 // check if Ptime has changed
2473 NewPtime = bx_pc_system.time_ticks();
2474 if (PrevPtime == NewPtime) // if not, nothing really changed
2476 UpdateStatus(); // Updates if there really was a status change, at least
2477 return;
2479 // display the new ptime on the status bar
2480 sprintf (tmpcb,"t= %I64d",NewPtime);
2481 SendMessage(hS_S,SB_SETTEXT,2,(LPARAM) tmpcb);
2482 PrevPtime = NewPtime;
2484 // remember register values from before the last run
2485 while (--i >= 0)
2486 PV[i] = rV[i];
2487 ladrmin = ladrmax; // invalidate any old linear->phys mapping
2489 // then detect current CPU mode the *right* way -- look for changes
2490 // TODO: create param Objects for CS.d_b and cpu_mode for each CPU
2491 CpuMode = BX_CPU(CurrentCPU)->get_cpu_mode();
2492 if (CpuMode == BX_MODE_LONG_64)
2494 if (In64Mode == FALSE) // Entering LongMode?
2496 CpuModeChange = TRUE;
2497 In64Mode = TRUE;
2498 In32Mode = TRUE; // In32Mode must be TRUE in LongMode
2499 ResizeColmns = TRUE; // if so, some formatting has changed
2500 StackSized = 0;
2503 else
2505 bx_bool d_b = BX_CPU(CurrentCPU)->sregs[BX_SEG_REG_CS].cache.u.segment.d_b;
2506 if (In32Mode != d_b || In64Mode != FALSE)
2508 CpuModeChange = TRUE;
2509 In64Mode = FALSE;
2510 In32Mode = d_b;
2513 if (CpuModeChange != FALSE)
2515 if (In64Mode == FALSE)
2516 EnableMenuItem (hOptMenu, CMD_EREG, MF_GRAYED);
2517 else
2518 EnableMenuItem (hOptMenu, CMD_EREG, MF_ENABLED);
2519 BottomAsmLA = ~0; // force an ASM autoload
2520 StatusChange = TRUE;
2522 doUpdate(); // do a full "autoupdate"
2523 if (doDumpRefresh != FALSE)
2524 RefreshDataWin();
2527 int HexFromAsk(char* ask,char* b) // this routine converts a user-typed hex string into binary bytes
2528 { // it ignores any bigendian issues -- binary is converted front to end as chars
2529 int y = 0;
2530 int i = 0;
2531 for(;;)
2533 unsigned int C = 0;
2534 if (strlen(ask + i) < 2)
2535 break;
2536 if (!sscanf(ask + i,"%02X",&C))
2537 break;
2538 b[y++] = C;
2539 i += 2;
2541 return y;
2544 bx_bool FindHex(unsigned char* b1,int bs,unsigned char* b2,int by)
2546 // search bs bytes of b1
2547 for(int i = 0 ; i < bs ; i++) // TODO: this loop could be a little more efficient.
2548 { // -- it just scans an input byte string against DataDump memory
2549 bx_bool Match = TRUE;
2550 for(int y = 0 ; y < by ; y++)
2552 if (b1[i + y] != b2[y])
2554 Match = FALSE;
2555 break;
2558 if (Match != FALSE)
2559 return TRUE;
2561 return FALSE;
2564 // load new memory for a MemDump
2565 // newDS = illegal (1) is a flag to ask the user for a DumpStart address
2566 bx_bool InitDataDump(int dType, Bit64u newDS)
2568 bx_bool retval = TRUE;
2569 bx_bool MsgOnErr = FALSE;
2570 char *s = tmpcb;
2571 if (((int) newDS & 0xf) != 0) // legal addys must be on 16byte boundary
2573 if (In64Mode == FALSE)
2574 sprintf(tmpcb,"0x%X",(Bit32u) DumpStart);
2575 else
2576 sprintf(tmpcb,"0x%I64X",DumpStart);
2577 if (AskText(hY,"4K Memory Dump","4K Memory Dump -- Enter Address (use 0x for hex):",tmpcb,0) == FALSE)
2578 return FALSE;
2580 while (*s == ' ') // allow user to enter whitespace
2581 ++s;
2582 if (*s == '0' && (s[1] =='X' || s[1] == 'x')) // and either hex or decimal
2583 sscanf (s+2,"%I64X",&newDS);
2584 else
2585 sscanf (s,"%I64d",&newDS);
2586 newDS &= ~15; // force Mem Dump to be 16b aligned
2587 MsgOnErr = TRUE;
2590 // load 4k DataDump array from bochs emulated linear (dType=0) or physical memory
2591 if (dType != 0)
2593 // cannot read linear mem across a 4K boundary -- so break the read in two
2594 // -- calculate location of 4K boundary (h):
2595 unsigned int len = (int) newDS & 0xfff;
2596 unsigned int i = 4096 - len;
2597 Bit64u h = newDS + i;
2598 retval = ReadBxLMem (newDS,i,(Bit8u *)DataDump);
2599 if (retval != FALSE && len != 0)
2600 retval = ReadBxLMem (h,len,(Bit8u *)DataDump + i);
2602 else
2603 retval = (bx_bool) bx_mem.dbg_fetch_mem( BX_CPU(CurrentCPU),
2604 (bx_phy_address)newDS, 4096, (Bit8u *)DataDump);
2605 if (retval == FALSE)
2607 // assume that the DataDump array is still valid -- fetch_mem should error without damage
2608 if (MsgOnErr != FALSE)
2609 MessageBox (hY,"Address range was not legal memory","Memory Error", MB_ICONERROR);
2610 return retval;
2612 EnableMenuItem (hCmdMenu, CMD_WPTWR, MF_GRAYED);
2613 EnableMenuItem (hCmdMenu, CMD_WPTRD, MF_GRAYED);
2614 DumpInitted = TRUE; // OK to refresh the Dump window in the future (it has data)
2615 DumpStart = newDS;
2616 DumpMode = dType; // finalize dump mode, since it worked
2617 // update column 0 to say whether its physmem or linear
2618 LV_COLUMN lvgc = {LVCF_TEXT,0,0,DC0txt[DumpMode]};
2619 CallWindowProc(wListView,hL[2],LVM_SETCOLUMN,(WPARAM) 0,(LPARAM) &lvgc);
2620 ShowMemData(); // Display DataDump using preset parameters
2621 return TRUE;
2624 void SetSizeIOS(int WinSizeX, int WinSizeY)
2626 int i, j;
2627 TEXTMETRIC tm;
2628 // calculate the height/width of typical "glyphs" in the font
2629 HDC hdc = GetDC (hS_S);
2630 GetTextMetrics (hdc, &tm);
2631 ReleaseDC (hS_S, hdc);
2632 OneCharWide = tm.tmAveCharWidth;
2633 j= tm.tmAveCharWidth * 72; // status bar contains about 72 char positions (without eflags)
2634 if (j > WinSizeX/2) // leave half the status bar for the eflags
2635 j = WinSizeX/2;
2636 i = j*5 / 12; // predefined proportions of Status "subwindows" = 2:5:5
2637 int modepos = j/6;
2638 int ptimepos = modepos + i;
2639 int eflpos = ptimepos + i;
2640 int p[4] = {modepos,ptimepos,eflpos,-1};
2642 // then set the dimensions of the I, O, and S child windows
2643 j = tm.tmHeight + tm.tmExternalLeading; // input window is the height of a char
2644 i = j >> 1;
2645 int sY = j + i; // status window and buttons are 50% taller
2646 LstTop = 0;
2647 if (ShowButtons != FALSE)
2649 // position the 5 command buttons
2650 LstTop = sY;
2651 i = WinSizeX / 5;
2652 SetWindowPos(hBTN[1],0,0,0,i,LstTop,SWP_SHOWWINDOW);
2653 SetWindowPos(hBTN[2],0,i,0,i,LstTop,SWP_SHOWWINDOW);
2654 SetWindowPos(hBTN[3],0,i*2,0,i,LstTop,SWP_SHOWWINDOW);
2655 SetWindowPos(hBTN[4],0,i*3,0,i,LstTop,SWP_SHOWWINDOW);
2656 SetWindowPos(hBTN[0],0,i*4,0,WinSizeX - 4*i,LstTop,SWP_SHOWWINDOW);
2658 else
2660 ShowWindow(hBTN[0],SW_HIDE);
2661 ShowWindow(hBTN[1],SW_HIDE);
2662 ShowWindow(hBTN[2],SW_HIDE);
2663 ShowWindow(hBTN[3],SW_HIDE);
2664 ShowWindow(hBTN[4],SW_HIDE);
2666 if (TotCPUs > 1)
2668 // MultiCPU simulation -- need CPU button row, too.
2669 int HorPos = 0;
2670 unsigned int CPUn = 0;
2671 i = WinSizeX / TotCPUs;
2672 while (CPUn < TotCPUs - 1)
2674 SetWindowPos(hCPUt[CPUn],0,HorPos,LstTop,i,sY,SWP_SHOWWINDOW);
2675 ++CPUn;
2676 HorPos += i;
2678 // use up any extra pixels on the last button
2679 SetWindowPos(hCPUt[CPUn],0,HorPos,LstTop,WinSizeX-HorPos,sY,SWP_SHOWWINDOW);
2680 LstTop += sY;
2682 // The status win may not use all of its space: overlap lists or Input by STATUS_WIN_OVERLAP pixels
2683 i = WinSizeY - sY - j;
2684 if (ShowIOWindows == FALSE)
2686 // need to keep caret functions in PAIRS
2687 CallWindowProc(*wEdit, hE_I,WM_KILLFOCUS,(WPARAM) 0,0); // destroy Input caret
2688 ShowWindow(hE_I,SW_HIDE);
2689 ShowWindow(hE_O,SW_HIDE);
2690 ListVerticalPix = WinSizeY - sY - LstTop + STATUS_WIN_OVERLAP;
2692 else
2694 CallWindowProc(*wEdit, hE_I,WM_SETFOCUS,(WPARAM) 0,0); // create Input caret
2695 ListVerticalPix = (WinSizeY * 3) >> 2; // 3/4 height
2696 SetWindowPos(hE_I,0,2,i + STATUS_WIN_OVERLAP,WinSizeX,j,SWP_SHOWWINDOW);
2697 SetWindowPos(hE_O,0,0,ListVerticalPix + LstTop,WinSizeX,
2698 i - ListVerticalPix - LstTop + (STATUS_WIN_OVERLAP/2),SWP_SHOWWINDOW);
2700 SetWindowPos(hS_S,0,0,WinSizeY - sY,WinSizeX,sY,SWP_SHOWWINDOW);
2701 SendMessage(hS_S,SB_SETPARTS,4,(LPARAM)p);
2702 SetFocus(hE_O); // focus on Output window works best
2705 // hh is the handle to the main parent window -- hY may not work yet
2706 void MoveLists(HWND hh)
2708 int i, j, k;
2709 unsigned int StrtCol[3] = {0,0,0};
2710 // use DockOrder to figure out the start columns of each list
2711 // starting column of 2nd list = width of first list
2712 i = ListWidthPix[(DockOrder >> 8) -1];
2713 j = ((DockOrder>>4)& 3) -1; // index of 2nd list
2714 StrtCol[j] = i;
2715 BarClix[0] = i;
2716 k = i + ListWidthPix[j]; // width of first + second
2717 StrtCol[(DockOrder & 3) -1] = k;
2718 BarClix[1] = k;
2719 // the center listview must be the only one with a border
2720 if (CurCenterList != j)
2722 // remove the border on the previous center list, and put it on the new one
2723 SetWindowLong ( hL[CurCenterList], GWL_STYLE, LVStyle[CurCenterList]);
2724 SetWindowLong ( hL[j], GWL_STYLE, LVStyle[j] | WS_BORDER );
2725 CurCenterList = j;
2726 // the tree window should have the same border as the data window --
2727 // but unfortunately, SetWindowLong does not work properly on the treeview!
2728 // if (j == 2)
2729 // k=SetWindowLong ( hT, GWL_STYLE, TVS_DISABLEDRAGDROP | TVS_HASLINES | TVS_HASBUTTONS | WS_CHILD | WS_BORDER );
2730 // else
2731 // k=SetWindowLong ( hT, GWL_STYLE, TVS_DISABLEDRAGDROP | TVS_HASLINES | TVS_HASBUTTONS | WS_CHILD );
2734 // On at least some versions of Win, you cannot mess with the positions
2735 // of subclassed ListView controls that still HAVE DATA IN THEM.
2736 // Therefore, delete all ListView data --
2737 // then refresh the 3 main ListView windows afterward
2739 CallWindowProc(wListView,hL[2],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
2740 CallWindowProc(wListView,hL[1],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
2741 CallWindowProc(wListView,hL[0],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
2743 SetWindowPos(hL[0],0,StrtCol[0],LstTop,ListWidthPix[0],ListVerticalPix,SWP_HIDEWINDOW);
2744 SetWindowPos(hL[1],0,StrtCol[1],LstTop,ListWidthPix[1],ListVerticalPix,SWP_HIDEWINDOW);
2745 SetWindowPos(hL[2],0,StrtCol[2],LstTop,ListWidthPix[2],ListVerticalPix,SWP_HIDEWINDOW);
2746 // tree window = same size/position as dump window
2747 SetWindowPos(hT,0,StrtCol[2],LstTop,ListWidthPix[2],ListVerticalPix,SWP_HIDEWINDOW);
2749 // calculate the SCREEN coordinates of the two "divider bars"
2750 POINT pt;
2751 pt.y = 0;
2752 pt.x = BarClix[0];
2753 ClientToScreen(hh,&pt);
2754 BarScrx[0] = (unsigned short) pt.x;
2755 pt.y = 0;
2756 pt.x = BarClix[1];
2757 ClientToScreen(hh,&pt);
2758 BarScrx[1] = (unsigned short) pt.x;
2760 // size the last column of each list = total width of that list
2761 CallWindowProc(wListView, hL[0], LVM_SETCOLUMNWIDTH, 2, ListWidthPix[0]);
2762 CallWindowProc(wListView, hL[1], LVM_SETCOLUMNWIDTH, 2, ListWidthPix[1]);
2763 CallWindowProc(wListView, hL[2], LVM_SETCOLUMNWIDTH, 17, ListWidthPix[2]);
2764 doAutoSize(); // autosize all other ListView columns for the new width
2765 BottomAsmLA = ~0; // force an ASM autoload next time, to resize it
2766 PrevDAD = 0; // force Data list autosize on next refresh
2767 doDumpRefresh = TRUE; // force a data window refresh on a break
2768 if (AtBreak != FALSE) // can't refresh the windows until a break!
2770 doUpdate(); // refresh the ASM and Register windows
2771 RefreshDataWin(); // and whichever data window is up
2773 else
2774 BottomAsmLA = ~0; // force an ASM autoload, to repaint
2777 // redraw/recalculate everything if the old window sizes are invalid
2778 void doShowAll(HWND hh)
2780 RECT rc;
2781 GetClientRect(hh,&rc);
2782 SetSizeIOS((int)rc.right,(int)rc.bottom); // window sizes are font-dependent
2783 // must clear listviews before MoveLists()
2784 CallWindowProc(wListView,hL[2],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
2785 CallWindowProc(wListView,hL[1],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
2786 CallWindowProc(wListView,hL[0],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
2787 MoveLists(hh);
2788 doAutoSize();
2791 // User is changing which registers are displaying in the Register list
2792 void ToggleSeeReg(int LW)
2794 int i = LW - CMD_EREG;
2795 if (i < 0 || i > 7)
2796 return;
2797 if (i == 4 || i == 5)
2798 ResizeColmns = TRUE; // may need to resize the register value column
2800 SeeReg[i] ^= TRUE;
2801 if (SeeReg[i] == FALSE)
2802 CheckMenuItem (hOptMenu, LW, MF_UNCHECKED);
2803 else
2804 CheckMenuItem (hOptMenu, LW, MF_CHECKED);
2805 if (AtBreak != FALSE)
2806 LoadRegList(); // do a register window update
2810 void doNewWSize(int i)
2812 // DumpAlign is the "wordsize" in bytes -- need to "calculate" the power of 2
2813 int j = 0;
2814 if (DumpAlign == 2) j = 1;
2815 else if (DumpAlign == 4) j = 2;
2816 else if (DumpAlign == 8) j = 3;
2817 else if (DumpAlign == 16) j = 4;
2818 if (j != i)
2820 // the wordsize popup is the 11th entry in the Opt menu -- COUNTING SEPARATORS
2821 HMENU wsMenu = GetSubMenu (hOptMenu, WS_POPUP_IDX);
2822 CheckMenuItem (wsMenu, j, MF_UNCHECKED | MF_BYPOSITION);
2823 CheckMenuItem (wsMenu, i, MF_CHECKED | MF_BYPOSITION);
2824 DumpAlign = 1<<i;
2825 if (DViewMode == VIEW_MEMDUMP && DumpInitted != FALSE)
2826 ShowData();
2830 void ToggleGDT()
2832 EnableMenuItem (hCmdMenu, CMD_WPTWR, MF_GRAYED);
2833 EnableMenuItem (hCmdMenu, CMD_WPTRD, MF_GRAYED);
2834 if (DViewMode == VIEW_GDT || (GDT_Len & 7) != 7 || (unsigned) GDT_Len >= 0x10000)
2836 if (DViewMode != VIEW_GDT)
2837 MessageBox(hY,"GDT limit is illegal",0,MB_OK);
2838 ShowMemData();
2840 else
2842 ShowWindow(hT,SW_HIDE);
2843 CallWindowProc(wTreeView,hT,TVM_DELETEITEM,(WPARAM) 0,(LPARAM) TVI_ROOT);
2844 // force all column widths to 0, then autosize later
2845 FillGDT();
2846 DViewMode = VIEW_GDT; // displaying a GDT
2850 void ToggleIDT()
2852 EnableMenuItem (hCmdMenu, CMD_WPTWR, MF_GRAYED);
2853 EnableMenuItem (hCmdMenu, CMD_WPTRD, MF_GRAYED);
2854 if (DViewMode == VIEW_IDT || (IDT_Len & 3) != 3 || (unsigned) IDT_Len >= 0x10000)
2856 if (DViewMode != VIEW_IDT)
2857 MessageBox(hY,"IDT limit is illegal",0,MB_OK);
2858 ShowMemData();
2860 else
2862 ShowWindow(hT,SW_HIDE);
2863 CallWindowProc(wTreeView,hT,TVM_DELETEITEM,(WPARAM) 0,(LPARAM) TVI_ROOT);
2864 FillIDT();
2865 DViewMode = VIEW_IDT; // displaying an IDT
2869 void TogglePAGE()
2871 EnableMenuItem (hCmdMenu, CMD_WPTWR, MF_GRAYED);
2872 EnableMenuItem (hCmdMenu, CMD_WPTRD, MF_GRAYED);
2873 if (DViewMode == VIEW_PAGING)
2874 ShowMemData();
2875 else
2877 ShowWindow(hT,SW_HIDE);
2878 CallWindowProc(wTreeView,hT,TVM_DELETEITEM,(WPARAM) 0,(LPARAM) TVI_ROOT);
2879 FillPAGE();
2880 DViewMode = VIEW_PAGING; // currently displaying Paging info
2884 void ToggleStack()
2886 EnableMenuItem (hCmdMenu, CMD_WPTWR, MF_GRAYED);
2887 EnableMenuItem (hCmdMenu, CMD_WPTRD, MF_GRAYED);
2888 if (DViewMode == VIEW_STACK)
2889 ShowMemData();
2890 else
2892 ShowWindow(hT,SW_HIDE);
2893 CallWindowProc(wTreeView,hT,TVM_DELETEITEM,(WPARAM) 0,(LPARAM) TVI_ROOT);
2894 StackSized = 0; // need to autosize the stack display columns
2895 PStackLA = 1; // flag to force a full refresh
2896 FillStack();
2897 DViewMode = VIEW_STACK; // currently displaying stack
2901 void TogglePTree()
2903 EnableMenuItem (hCmdMenu, CMD_WPTWR, MF_GRAYED);
2904 EnableMenuItem (hCmdMenu, CMD_WPTRD, MF_GRAYED);
2905 if (DViewMode == VIEW_PTREE)
2906 ShowMemData();
2907 else
2909 DViewMode = VIEW_PTREE; // currently displaying param_tree
2910 CallWindowProc(wListView,hL[2],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
2911 FillPTree(); // get all info from param_tree into tree-view window
2916 void doFind()
2918 unsigned int i, L;
2919 *tmpcb = 0;
2920 // prepare to read ASM column 2, then set Selected state of each line on/off
2921 LV_ITEM lvi = {LVIF_STATE,0,2,0,LVIS_SELECTED,(LPSTR) tmpcb,100,0,0};
2922 if (DumpHasFocus == FALSE)
2924 if (AskText(hY,"Find text in mnemonic lines","ASM Search text:",tmpcb,0) == FALSE)
2925 return;
2926 if (strchr(tmpcb,'*') == 0 && strchr(tmpcb,'?') == 0)
2927 sprintf(tmpcd,"*%s*",tmpcb);
2928 else
2929 strcpy(tmpcd,tmpcb);
2931 if (UprCase != FALSE) // convert search string to uppercase if ASM is that way
2932 upr(tmpcd);
2933 L = CallWindowProc(wListView,hL[1],LVM_GETITEMCOUNT,(WPARAM) 0,(LPARAM) 0);
2934 for(i = 0 ; i < L ; i++)
2936 lvi.mask = LVIF_TEXT;
2937 lvi.iItem = i;
2938 // get column 2 text from ASM window
2939 CallWindowProc(wListView,hL[1],LVM_GETITEMTEXT,(WPARAM) i,(LPARAM) &lvi);
2940 lvi.mask = LVIF_STATE;
2941 lvi.state = 0; // assume unselected
2942 // if it's a match, set the state to Selected
2943 if (IsMatching(tmpcb,tmpcd,TRUE))
2944 lvi.state = LVIS_SELECTED;
2945 CallWindowProc(wListView,hL[1],LVM_SETITEMSTATE,(WPARAM) i,(LPARAM) &lvi);
2948 else
2950 if (AskText(hY,"Memory Dump Search",
2951 "Sequential hex bytes (e.g 00FEFA - no spaces), or ascii string (max. 16b):",tmpcb,0) == FALSE)
2952 return;
2954 int by = HexFromAsk(tmpcb,tmpcd); // by = len of binary search string
2956 // Find in all rows of 16 bytes -- must do rows, so they can be selected
2957 for(i = 0,L = 0 ; i < 4096 ; i += 16, L++)
2959 lvi.iItem = L;
2960 lvi.state = 0; // assume unselected
2961 // if it's a match, change state to Selected
2962 if (by != 0 && FindHex((unsigned char *)DataDump + i,16,(unsigned char *)tmpcd,by))
2963 lvi.state = LVIS_SELECTED;
2964 CallWindowProc(wListView,hL[2],LVM_SETITEMSTATE,(WPARAM) L,(LPARAM) &lvi);
2967 // Try ascii for additional matches and selected lines
2968 lvi.state = LVIS_SELECTED;
2969 strcpy(tmpcd,tmpcb);
2970 by = strlen(tmpcd);
2971 for(i = 0,L = 0 ; i < 4096 ; i += 16, L++)
2973 lvi.iItem = L;
2974 if (by != 0 && FindHex((unsigned char *)DataDump + i,16,(unsigned char *)tmpcd,by))
2975 CallWindowProc(wListView,hL[2],LVM_SETITEMSTATE,(WPARAM) L,(LPARAM) &lvi);
2980 void doStepN()
2982 Bit32u i;
2983 char *s = tmpcb;
2984 sprintf (tmpcb,"%d",PrevStepNSize);
2985 if (AskText(hY,"Singlestep N times","Number of steps (use 0x for hex):",tmpcb,0) == FALSE)
2986 return;
2987 while (*s == ' ') // allow user to enter whitespace
2988 ++s;
2989 if (*s == '0' && (s[1] =='X' || s[1] == 'x')) // and either hex or decimal
2990 sscanf (s+2,"%x",&i);
2991 else
2992 sscanf (s,"%d",&i);
2993 if (i == 0)
2994 return;
2995 PrevStepNSize = i;
2996 AtBreak = FALSE;
2997 StatusChange = TRUE;
2998 bx_dbg_stepN_command(i);
2999 AtBreak = TRUE;
3000 StatusChange = TRUE;
3001 OnBreak();
3004 void ShowFW()
3006 FWflag = TRUE;
3007 MessageBox(hY,"With more than 1000 lines in the ASM window, be careful not to minimize the app.\r\nIt will be very slow to reopen.",
3008 "Friendly warning:",MB_ICONINFORMATION);
3011 // User wants a custom disassembly
3012 void doDisAsm()
3014 char *s = tmpcb;
3015 int NumLines = DefaultAsmLines;
3016 Bit64u h;
3017 sprintf (tmpcb,"0x%I64X",CurrentAsmLA);
3018 if (AskText(hY,"Disassemble",
3019 "Disassemble -- Enter Linear Start Address (use 0x for hex):",tmpcb,0) == FALSE)
3020 return;
3021 while (*s == ' ') // allow user to enter whitespace
3022 ++s;
3023 if (*s == '0' && (s[1] =='X' || s[1] == 'x')) // and either hex or decimal
3024 sscanf (s+2,"%I64x",&h);
3025 else
3026 sscanf (s,"%I64d",&h);
3027 sprintf (tmpcb,"%d",NumLines);
3028 if (AskText(hY,"Disassemble","Number of lines: (Max. 2048)",tmpcb,0) == FALSE)
3029 return;
3030 sscanf (tmpcb,"%d",&NumLines);
3031 if (NumLines <= 0 || NumLines > 2048)
3032 return;
3033 if (NumLines > 1000 && FWflag == FALSE)
3034 ShowFW();
3035 FillAsm(h, NumLines);
3036 // Set the scroll limits for the new ASM window
3037 BottomAsmLA = *AsmLA;
3038 int j = bottommargin; // try to use this bottom margin on ASM window
3039 if (j > AsmLineCount)
3040 j = AsmLineCount;
3041 TopAsmLA = AsmLA[AsmLineCount - j]; //TopAsmLA is the scroll point
3045 // Toggle all "selected" items as linear breakpoint on the ASM window
3046 void SetBreak()
3048 int L = CallWindowProc(wListView, hL[1], LVM_GETNEXTITEM,(WPARAM) -1,MAKELPARAM(LVNI_SELECTED, 0));
3049 while (L >= 0)
3051 int iExist = -1;
3052 int i=0;
3053 while (i < BreakCount && iExist < 0)
3055 if (BrkLAddr[i] == AsmLA[L])
3056 iExist = i;
3057 ++i;
3059 if (iExist >= 0)
3061 // existing, remove
3062 bx_dbg_del_lbreak(BrkIdx[iExist]);
3063 i = iExist; // also compress it out of the local list
3064 while (++i < BreakCount)
3066 BrkLAddr[i-1] = BrkLAddr[i];
3067 BrkIdx[i-1] = BrkIdx[i];
3069 --BreakCount;
3071 else
3073 bx_address nbrk = (bx_address) AsmLA[L];
3074 // Set a "regular" bochs linear breakpoint to that address
3075 int BpId = bx_dbg_lbreakpoint_command(bkRegular, nbrk);
3076 if (BpId >= 0)
3078 // insertion sort the new Brkpt into the local list
3079 i = BreakCount - 1;
3080 while (i >= 0 && BrkLAddr[i] > nbrk)
3082 BrkLAddr[i+1] = BrkLAddr[i];
3083 BrkIdx[i+1] = BrkIdx[i];
3084 --i;
3086 BrkLAddr[i+1] = nbrk;
3087 BrkIdx[i+1] = BpId;
3088 ++BreakCount;
3091 // start the next search at item L
3092 L = CallWindowProc(wListView, hL[1], LVM_GETNEXTITEM,(WPARAM) L,MAKELPARAM(LVNI_SELECTED, 0));
3096 void SetWatchpoint(unsigned * num_watchpoints, bx_phy_address * watchpoint)
3098 int iExist1 = -1;
3099 int i = (int) *num_watchpoints;
3100 // the list is unsorted -- test all of them
3101 while (--i >= 0)
3103 if (watchpoint[i] == SelectedDataAddress)
3105 iExist1 = i;
3106 i = 0;
3109 if (iExist1 >= 0)
3111 // existing watchpoint, remove by copying the list down
3112 while (++iExist1 < (int) *num_watchpoints)
3113 watchpoint[iExist1 - 1] = watchpoint[iExist1];
3114 -- *num_watchpoints;
3116 else
3118 // Set a watchpoint to last clicked address -- the list is not sorted
3119 if (*num_watchpoints >= 16)
3120 MessageBox (hY,"Too many of that type of watchpoint. Max. 16",
3121 "Table Overflow", MB_ICONERROR) ;
3122 else
3123 watchpoint[(*num_watchpoints)++] = (bx_phy_address) SelectedDataAddress;
3127 // Main Window Proc for our Dialog
3128 LRESULT CALLBACK B_WP(HWND hh,UINT mm,WPARAM ww,LPARAM ll)
3130 unsigned int i;
3131 extern unsigned num_write_watchpoints;
3132 extern unsigned num_read_watchpoints;
3133 extern bx_phy_address write_watchpoint[];
3134 extern bx_phy_address read_watchpoint[];
3136 switch(mm)
3138 case WM_CREATE:
3140 HFONT hF = (HFONT)GetStockObject(OEM_FIXED_FONT);
3141 HFONT hF2 = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
3143 // Register Window
3144 char* txt0[] = {"Reg Name","Hex Value","Decimal"};
3145 LV_COLUMN lvc = {LVCF_SUBITEM | LVCF_TEXT,LVCFMT_LEFT,0,txt0[0]};
3146 hL[0] = CreateWindowEx(0,"sLV","",LVStyle[0],0,0,1,1,hh,(HMENU)1001,GetModuleHandle(0),0);
3147 // Note; WM_CREATE only happens once, so don't bother eliminating these SendMessage macros
3148 ListView_InsertColumn(hL[0],0,&lvc);
3149 lvc.pszText = txt0[1];
3150 ListView_InsertColumn(hL[0],1,&lvc);
3151 lvc.pszText = txt0[2];
3152 ListView_InsertColumn(hL[0],2,&lvc);
3154 // Enable the groupID's for the register window
3155 #ifndef IS_WIN98
3156 // GroupID's are only supported on XP or higher -- verify Win Version
3157 // the group stuff may COMPILE correctly, but still may fail at runtime
3158 Bit8u MajWinVer, MinWinVer;
3159 Bit32u PackedVer = GetVersion();
3160 bx_bool Group_OK = TRUE;
3161 MajWinVer = (Bit8u)(PackedVer & 0xff); // Major version # is in the LOW byte
3162 MinWinVer = (Bit8u)((PackedVer>>8) & 0xff);
3163 if (MajWinVer > 5 || (MajWinVer == 5 && MinWinVer >= 1) // is it XP or higher?
3165 wchar_t* txt[] = {L"General Purpose",L"Segment",L"Control",L"MMX",L"SSE",L"Debug",L"Test",L"Other"};
3166 ListView_EnableGroupView(hL[0],TRUE);
3167 for(i = 0 ; i < 8 ; i++)
3169 LVGROUP group1 = {0};
3170 group1.cbSize = sizeof(LVGROUP);
3171 group1.mask = LVGF_HEADER | LVGF_GROUPID;
3172 group1.pszHeader = txt[i];
3173 group1.iGroupId = i;
3174 ListView_InsertGroup(hL[0], -1, &group1);
3177 else
3178 Group_OK = FALSE;
3179 #endif
3180 SendMessage(hL[0], LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER,
3181 LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER);
3184 // Asm Window
3185 hL[1] = CreateWindowEx(0,"sLV","",LVStyle[1] | WS_BORDER,0,0,1,1,hh,(HMENU)1000,GetModuleHandle(0),0);
3186 CurCenterList = 1; // ASM window starts with the border
3187 char* txt3[] = {"L.Address","Bytes","Mnemonic"};
3189 lvc.pszText = txt3[0];
3190 ListView_InsertColumn(hL[1],0,&lvc);
3191 lvc.pszText = txt3[1];
3192 ListView_InsertColumn(hL[1],1,&lvc);
3193 lvc.pszText = txt3[2];
3194 ListView_InsertColumn(hL[1],2,&lvc);
3195 SendMessage(hL[1], LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER,
3196 LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER);
3199 // Input / Output
3200 hE_I = CreateWindowEx(0,"edit","",WS_CHILD | WS_VISIBLE,0,0,1,1,hh,(HMENU)1004,GetModuleHandle(0),0);
3201 // without AUTOHSCROLL, output window text is always supposed to wordwrap
3202 hE_O = CreateWindowEx(0,"edit","",WS_VSCROLL | WS_BORDER | WS_CHILD | WS_VISIBLE | ES_MULTILINE,0,0,1,1,hh,(HMENU)1003,GetModuleHandle(0),0);
3203 SendMessage(hE_I,WM_SETFONT,(WPARAM)hF2,MAKELPARAM(TRUE,0));
3204 SendMessage(hE_O,WM_SETFONT,(WPARAM)hF,MAKELPARAM(TRUE,0));
3205 // subclass both the edit windows together
3206 *wEdit = (WNDPROC) SetWindowLong (hE_I,GWL_WNDPROC,(long) ThisEditProc);
3207 wEdit[1] = (WNDPROC) SetWindowLong (hE_O,GWL_WNDPROC,(long) ThisEditProc);
3209 // Status
3210 hS_S = CreateWindowEx(0,STATUSCLASSNAME,"",WS_CHILD | WS_VISIBLE,0,0,1,1,hh,(HMENU)1006,GetModuleHandle(0),0);
3211 SendMessage(hS_S,WM_SETFONT,(WPARAM)hF2,MAKELPARAM(TRUE,0));
3212 int p[4] = {100,250,400,-1};
3213 SendMessage(hS_S,SB_SETPARTS,4,(LPARAM)p);
3215 // Dump Window
3216 hL[2] = CreateWindowEx(0,"sLV","",LVStyle[2],0,0,1,1,hh,(HMENU)1002,GetModuleHandle(0),0);
3217 //SendMessage(hL[2],WM_SETFONT,(WPARAM)hF2,MAKELPARAM(TRUE,0));
3218 strcpy (bigbuf, "Address");
3219 lvc.pszText = bigbuf;
3220 ListView_InsertColumn(hL[2],0,&lvc);
3221 bigbuf[1] = 0; // use bigbuf to create 1 byte "strings"
3222 for(i = 1 ; i < 17 ; i++)
3224 if (i < 11)
3225 *bigbuf = i - 1 + '0';
3226 else
3227 *bigbuf = i - 11 + 'A';
3228 ListView_InsertColumn(hL[2],i,&lvc);
3230 strcpy (bigbuf, "Ascii");
3231 ListView_InsertColumn(hL[2],17,&lvc);
3232 SendMessage(hL[2], LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER,
3233 LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER);
3235 #ifndef IS_WIN98
3236 if (Group_OK)
3238 wchar_t* txt5[] = {L"16-bit code",L"64-bit code",L"32-bit code",L"16-bit data",L"64-bit data",L"32-bit data",L"Illegal"};
3239 ListView_EnableGroupView(hL[2],TRUE);
3240 LVGROUP group1 = {0};
3241 group1.cbSize = sizeof(LVGROUP);
3242 group1.mask = LVGF_HEADER | LVGF_GROUPID;
3243 for(int i = 0 ; i < 9 ; i++)
3245 group1.pszHeader = txt5[i];
3246 group1.iGroupId = i;
3247 ListView_InsertGroup(hL[2], -1, &group1);
3250 #endif
3251 hT = CreateWindowEx(0,WC_TREEVIEW,"",TVS_DISABLEDRAGDROP | TVS_HASLINES | TVS_HASBUTTONS | WS_CHILD | WS_BORDER,
3252 0,0,1,1,hh,(HMENU)1010,GetModuleHandle(0),0);
3253 //SendMessage(hT,WM_SETFONT,(WPARAM)hF2,MAKELPARAM(TRUE,0));
3254 // Use the same messagehandler for the tree window as for ListViews
3255 wTreeView = (WNDPROC) SetWindowLong (hT,GWL_WNDPROC,(long) LVProc);
3257 /* TotCPUs = SIM->get_param_num(BXPN_CPU_NPROCESSORS)->get() *
3258 SIM->get_param_num(BXPN_CPU_NCORES)->get() *
3259 SIM->get_param_num(BXPN_CPU_NTHREADS)->get();
3260 if (TotCPUs == 0 || TotCPUs > BX_MAX_SMP_THREADS_SUPPORTED)
3261 TotCPUs = 1; // this case will never happen
3263 TotCPUs = BX_SMP_PROCESSORS;
3265 // create button rows
3266 CurrentCPU = 0;
3267 int j = TotCPUs;
3268 Bit32u WStyle = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON;
3269 if (j > 1)
3271 while (--j > 0)
3273 sprintf (bigbuf, "cpu%d",j); // number all the CPU buttons
3274 hCPUt[j] = CreateWindowEx(0,"sBtn",bigbuf,WStyle,0,0,1,1,hh,(HMENU)(1030+j),GetModuleHandle(0),0);
3276 strcpy (bigbuf, "CPU0"); // Handle CPU0 specially -- it is "selected"
3277 hCPUt[0] = CreateWindowEx(0,"sBtn",bigbuf,WStyle,0,0,1,1,hh,(HMENU)MULTICPU_BTN_BASE,GetModuleHandle(0),0);
3279 j = 5;
3280 while (--j >= 0)
3281 hBTN[j] = CreateWindowEx(0,"sBtn",BTxt[j],WStyle,0,0,1,1,hh,(HMENU)(BTN_BASE+j),GetModuleHandle(0),0);
3283 hCursResize = LoadCursor (NULL,IDC_SIZEWE);
3284 hCursDock = LoadCursor (NULL,IDC_CROSS);
3285 SetTimer(hh,2,500,NULL); // get timer ticks every half a second (update VGAW)
3286 DoAllInit(); // any custom GUI initialization goes in here
3287 SetFocus(hE_O); // focus on Output window works best
3288 break;
3291 case WM_SIZE:
3293 RECT rc;
3294 int i, j, k;
3296 // Mapping mode is MM_TEXT (Def), so Yvalues increase DOWN, all values are in pixels.
3297 GetClientRect(hh,&rc);
3298 // don't resize child windows on a minimize, or if client window is too small
3299 // TODO: save the prev size values -- no resize if they are the same
3300 // -- also can skip some resizing steps if horizontal size does not change
3301 if (rc.bottom > 100 && rc.right > 150)
3303 // set up the Input/Output/Status windows
3304 SetSizeIOS((int)rc.right,(int)rc.bottom);
3306 // need to recalculate List widths, with the same proportions as before
3307 i = ListWidthPix[0] + ListWidthPix[1] + ListWidthPix[2];
3308 if (i == 0)
3309 i = 1;
3310 j = (ListWidthPix[2] * rc.right) / i;
3311 k = (ListWidthPix[1] * rc.right) / i;
3312 ListWidthPix[0] = rc.right - k - j; // Register list
3313 ListWidthPix[1] = k; // Asm
3314 ListWidthPix[2] = j; // MemDump
3315 MoveLists(hh);
3317 break;
3320 case WM_SYSKEYDOWN: // ww == key + ALT
3322 if (ww == '1')
3323 doNewWSize(0);
3324 else if (ww == '2')
3325 doNewWSize(1);
3326 else if (ww == '4')
3327 doNewWSize(2);
3328 else if (ww == '8')
3329 doNewWSize(3);
3330 else if (ww == '6')
3331 doNewWSize(4);
3332 else if (ww == VK_F2)
3333 TogglePAGE();
3334 #if BX_SUPPORT_FPU
3335 else if (ww == VK_F3) ToggleSeeReg(139); // MMX/FPU toggle
3336 #endif
3337 else if (ww == VK_F7) // Alt+F7 memdump hex toggle
3339 i = DumpInAsciiMode;
3340 i ^= 2;
3341 if (i != 0)
3343 DumpInAsciiMode = i;
3344 if ((DumpInAsciiMode & 2) != 0)
3345 CheckMenuItem (hOptMenu, 122, MF_CHECKED);
3346 else
3347 CheckMenuItem (hOptMenu, 122, MF_UNCHECKED);
3348 PrevDAD = 0; // force columns to resize
3349 ShowData();
3352 break;
3355 case WM_KEYDOWN:
3357 int Control = GetKeyState(VK_CONTROL); // key is down if val is negative
3358 int Shift = GetKeyState(VK_SHIFT);
3360 switch (ww)
3362 case VK_ESCAPE:
3363 CommandHistoryIdx = 0;
3364 SetWindowText(hE_I,"");
3365 ShowMemData(); // force a "normal" MemDump window
3366 break;
3368 case VK_UP:
3369 // History from nextmost previous command
3370 CommandHistoryIdx = (CommandHistoryIdx - 1) & 63; // wrap -1 to 63 (circular)
3371 SetWindowText(hE_I,CmdHistory[(CmdHInsert + CommandHistoryIdx) & 63]);
3372 CallWindowProc(*wEdit, hE_I, EM_SETSEL,(WPARAM) -1,(LPARAM) -1);
3373 CallWindowProc(*wEdit, hE_I, EM_SCROLLCARET,(WPARAM) 0,(LPARAM) 0);
3374 break;
3376 case VK_DOWN:
3377 // Next History command
3378 CommandHistoryIdx = (CommandHistoryIdx + 1) & 63; // wrap -1 to 63 (circular)
3379 SetWindowText(hE_I,CmdHistory[(CmdHInsert + CommandHistoryIdx) & 63]);
3380 CallWindowProc(*wEdit, hE_I, EM_SETSEL,(WPARAM) -1,(LPARAM) -1);
3381 CallWindowProc(*wEdit, hE_I, EM_SCROLLCARET,(WPARAM) 0,(LPARAM) 0);
3382 break;
3384 case VK_PRIOR:
3385 // Page up on the MemDump window by 2K
3386 if (DumpInitted != FALSE)
3387 InitDataDump(DumpMode, DumpStart - 2048);
3388 break;
3390 case VK_NEXT:
3391 // Page down on the MemDump window by 2K
3392 if (DumpInitted != FALSE)
3393 InitDataDump(DumpMode, DumpStart + 2048);
3394 break;
3396 case VK_F2:
3397 if (Control < 0)
3398 ToggleGDT();
3399 else if (Shift < 0)
3400 ToggleIDT();
3401 else
3402 ToggleStack();
3403 break;
3405 case VK_F3: // ^F3 = param tree, F3 = toggle syntax
3406 if (Control < 0)
3407 TogglePTree();
3408 else
3410 Bit64u h = CurrentAsmLA;
3411 bx_disassemble.toggle_syntax_mode();
3412 // do the standard ASM window fill sequence
3413 CanDoLA(&h);
3414 FillAsm(h, DefaultAsmLines);
3416 break;
3418 case VK_F4:
3419 if (Shift < 0) // Debug register toggle
3420 ToggleSeeReg(CMD_DREG);
3421 else if (Control >= 0) // Refresh
3423 BottomAsmLA = ~0; // force an ASM autoload
3424 doDumpRefresh = TRUE; // force a data window refresh on a break
3425 if (AtBreak != FALSE) // can't refresh the windows until a break!
3427 doUpdate(); // refresh the ASM and Register windows
3428 RefreshDataWin(); // and whichever data window is up
3431 #if BX_SUPPORT_SSE
3432 else ToggleSeeReg(CMD_XMMR); // SSE toggle
3433 #endif
3434 break;
3436 case VK_F5:
3437 // can't continue until everything is ready
3438 if (AtBreak != FALSE && debug_cmd_ready == FALSE && dbgOn)
3440 // The VGAW *MUST* be refreshed periodically -- it's best to use the timer.
3441 // Which means that the sim cannot be directly run from this msglp thread.
3442 *debug_cmd = 'c'; // send a fake "continue" command to the internal debugger
3443 debug_cmd[1] = 0;
3444 debug_cmd_ready = TRUE;
3445 AtBreak = FALSE;
3446 StatusChange = TRUE;
3448 break;
3450 case VK_F7:
3451 if (Control < 0)
3452 InitDataDump(0,(Bit64u) 1); // ^F7 = PhysDump
3453 else if (Shift < 0) // ShiftF7 = ascii toggle
3455 i = DumpInAsciiMode;
3456 i ^= 1;
3457 if (i != 0)
3459 DumpInAsciiMode = i;
3460 if ((DumpInAsciiMode & 1) != 0)
3461 CheckMenuItem (hOptMenu, CMD_MASCII, MF_CHECKED);
3462 else
3463 CheckMenuItem (hOptMenu, CMD_MASCII, MF_UNCHECKED);
3464 PrevDAD = 0; // force columns to resize
3465 ShowData();
3468 else
3469 InitDataDump(1,(Bit64u) 1); // F7 = LinDump
3470 break;
3472 case VK_F6:
3473 if (Control < 0) // ^F6 = Read Watchpt
3475 if (DumpHasFocus != FALSE)
3476 SetWatchpoint(&num_read_watchpoints,read_watchpoint);
3478 else if (Shift < 0) // ShiftF6 = Modechange brk toggle
3480 // toggle mode_break on cpu0, use that value to reset all CPUs
3481 bx_bool nmb = BX_CPU(0)->mode_break ^ TRUE;
3482 int j = TotCPUs;
3483 while (--j >= 0)
3484 BX_CPU(j)->mode_break = nmb;
3485 if (nmb != FALSE)
3486 CheckMenuItem (hOptMenu, CMD_MODEB, MF_CHECKED);
3487 else
3488 CheckMenuItem (hOptMenu, CMD_MODEB, MF_UNCHECKED);
3490 else
3492 if (DumpHasFocus == FALSE) // F6 Brkpt / Write Watchpt
3493 SetBreak();
3494 else
3495 SetWatchpoint(&num_write_watchpoints,write_watchpoint);
3497 break;
3499 case VK_F11:
3500 if (AtBreak != FALSE && debug_cmd_ready == FALSE && dbgOn)
3502 bx_dbg_stepN_command(1); // singlestep
3503 StatusChange = TRUE;
3505 break;
3507 case VK_F9:
3508 // can't run sim until everything is ready
3509 if (AtBreak != FALSE && debug_cmd_ready == FALSE && dbgOn)
3510 doStepN(); // ask user for a step #
3511 break;
3513 case 'C': // ^c = break
3514 if (Control < 0)
3516 SIM->debug_break();
3518 break;
3520 case 'D':
3521 if (Control < 0)
3522 doDisAsm();
3523 break;
3525 case 'F':
3526 if (Control < 0)
3527 doFind();
3528 break;
3530 case VK_RIGHT: // send a few virtual movement keys back into the Input window
3531 case VK_LEFT:
3532 case VK_END:
3533 case VK_HOME:
3534 CallWindowProc (*wEdit, hE_I, mm, ww, ll);
3535 break;
3537 case VK_RETURN:
3538 // can't do a command until everything is ready
3539 if (AtBreak != FALSE && debug_cmd_ready == FALSE && dbgOn)
3541 *tmpcb = 0;
3542 GetWindowText(hE_I,tmpcb,200);
3543 if (*tmpcb == 0) // Hitting <CR> on a blank line means SINGLESTEP
3545 bx_dbg_stepN_command(1); // singlestep
3547 else
3549 // deal with the command history:
3550 if (strlen(tmpcb) > 79)
3551 MessageBox (hY,"Running command, but history has an 80 char Max.",
3552 "Command history overflow", MB_OK);
3553 else
3555 strcpy (CmdHistory[CmdHInsert], tmpcb);
3556 CmdHInsert = (CmdHInsert + 1) & 63; // circular buffer, 0 to 63
3558 strcpy (debug_cmd,tmpcb); // send the command into the bochs internal debugger
3559 debug_cmd_ready = TRUE;
3560 AtBreak = FALSE;
3561 SetWindowText(hE_I,""); // clear the "input" window for the next command
3562 CommandHistoryIdx = 0; // and reset the history queue to the new end
3564 StatusChange = TRUE;
3566 } // end the switch
3567 return 0;
3569 case WM_COMMAND:
3571 int LW = LOWORD(ww);
3573 if (LW >= BTN_BASE && LW <= BTN_BASE +4) // convert button IDs to command IDs
3574 LW = BtnLkup [LW - BTN_BASE];
3575 else if (LW >= MULTICPU_BTN_BASE && LW < MULTICPU_BTN_BASE + BX_MAX_SMP_THREADS_SUPPORTED)
3577 unsigned int newCPU = LW - MULTICPU_BTN_BASE;
3578 if (CurrentCPU != newCPU)
3580 // change text on CurrentCPU button to lowercase
3581 strcpy (tmpcb, "cpu0");
3582 tmpcb[3] = CurrentCPU + '0';
3583 SendMessage (hCPUt[CurrentCPU],WM_SETTEXT,(WPARAM) 0 ,(LPARAM) tmpcb);
3584 // change text on newCPU button to UPPERCASE
3585 strcpy (tmpcb, "CPU0");
3586 tmpcb[3] = newCPU + '0';
3587 SendMessage (hCPUt[newCPU],WM_SETTEXT,(WPARAM) 0 ,(LPARAM) tmpcb);
3588 CurrentCPU = newCPU;
3589 BottomAsmLA = ~0; // force an ASM autoload, to repaint
3590 PrevPtime = 0; // force a full update
3591 if (AtBreak != FALSE) // if at a break, pretend it just happened
3592 OnBreak(); // refresh the ASM and Register windows
3594 return 0;
3596 if (LW >= CMD_BREAK && LW < CMD_MODEB) // Does not include "Step"s or Options
3598 if (AtBreak == FALSE)
3600 SIM->debug_break(); // On a menu click always break (with some exceptions)
3604 switch(LW)
3607 case CMD_CONT: // run/go/continue
3608 if (AtBreak != FALSE && debug_cmd_ready == FALSE && dbgOn)
3610 // The VGAW *MUST* be refreshed periodically -- it's best to use the timer.
3611 // Which means that the sim cannot be directly run from this msglp thread.
3612 *debug_cmd = 'c'; // send a fake "continue" command to the internal debugger
3613 debug_cmd[1] = 0;
3614 debug_cmd_ready = TRUE;
3615 AtBreak = FALSE;
3616 StatusChange = TRUE;
3618 break;
3620 case CMD_STEP1: // step 1
3621 if (AtBreak != FALSE && debug_cmd_ready == FALSE && dbgOn)
3623 bx_dbg_stepN_command(1); // singlestep
3624 StatusChange = TRUE;
3626 break;
3628 case CMD_STEPN: // step N
3629 // can't run sim until everything is ready
3630 if (AtBreak != FALSE && debug_cmd_ready == FALSE && dbgOn)
3631 doStepN();
3632 break;
3634 case CMD_BREAK: // break/stop the sim
3635 // SIM->debug_break() only "break"s the internal debugger
3636 SIM->debug_break();
3637 break;
3639 case CMD_BRKPT: // set or delete a breakpoint at the selected address
3640 SetBreak();
3641 break;
3643 case CMD_WPTWR: // set or delete a data write watchpoint
3644 SetWatchpoint(&num_write_watchpoints,write_watchpoint);
3645 break;
3647 case CMD_WPTRD: // set or delete a data read watchpoint
3648 SetWatchpoint(&num_read_watchpoints,read_watchpoint);
3649 break;
3651 case CMD_FIND: // find -- Control-F
3652 doFind();
3653 break;
3655 case CMD_RFRSH: // force an update/refresh
3656 BottomAsmLA = ~0; // force an ASM autoload
3657 doDumpRefresh = TRUE; // force a data window refresh on a break
3658 if (AtBreak != FALSE) // can't refresh the windows until a break!
3660 doUpdate(); // refresh the ASM and Register windows
3661 RefreshDataWin(); // and whichever data window is up
3663 break;
3665 case CMD_PHYDMP: // "physical mem" data dump
3666 InitDataDump(0,(Bit64u) 1);
3667 break;
3669 case CMD_LINDMP: // "linear memory" data dump
3670 InitDataDump(1,(Bit64u) 1);
3671 break;
3673 case CMD_STACK: // toggle display of Stack
3674 ToggleStack();
3675 break;
3677 case CMD_GDTV: // toggle display of GDT
3678 ToggleGDT();
3679 break;
3681 case CMD_IDTV: // toggle display of IDT
3682 ToggleIDT();
3683 break;
3685 case CMD_PAGEV: // display paging info
3686 TogglePAGE();
3687 break;
3689 case CMD_CMEM: // view current MemDump -- acts like "cancel"
3690 CommandHistoryIdx = 0;
3691 SetWindowText(hE_I,"");
3692 ShowMemData(); // force a "normal" MemDump window
3693 break;
3695 case CMD_PTREE:
3696 TogglePTree();
3697 break;
3699 case CMD_DISASM: // disassemble starting at a particular address
3700 doDisAsm();
3701 break;
3703 case CMD_MODEB: // toggle the simulation's Mode-Change-Break flag
3705 // toggle mode_break on cpu0, use that value to reset all CPUs
3706 bx_bool nmb = BX_CPU(0)->mode_break ^ TRUE;
3707 int j = TotCPUs;
3708 while (--j >= 0)
3709 BX_CPU(j)->mode_break = nmb;
3710 if (nmb != FALSE)
3711 CheckMenuItem (hOptMenu, CMD_MODEB, MF_CHECKED);
3712 else
3713 CheckMenuItem (hOptMenu, CMD_MODEB, MF_UNCHECKED);
3714 break;
3717 case CMD_DADEF: // set default # of disassembly lines in a list
3718 sprintf (tmpcb,"%d",DefaultAsmLines);
3719 if (AskText(hh,"Disassembly default linecount","Max. 2048:",tmpcb,0) == FALSE)
3720 return 0;
3721 sscanf (tmpcb,"%d",&i);
3722 if (i > 0 && i <= 2048)
3723 DefaultAsmLines = i;
3724 if (i > 1000 && FWflag == FALSE) // friendly warning
3725 ShowFW();
3726 break;
3728 case CMD_ATTI: // Toggle ASM Syntax
3730 bx_disassemble.toggle_syntax_mode();
3731 // do the standard ASM window fill sequence
3732 Bit64u h = CurrentAsmLA;
3733 CanDoLA(&h);
3734 FillAsm(h, DefaultAsmLines);
3735 break;
3738 case CMD_IOWIN: // toggle display of internal debugger Input and Output windows
3739 ShowIOWindows ^= TRUE;
3740 if (ShowIOWindows != 0)
3741 CheckMenuItem (hOptMenu, CMD_IOWIN, MF_CHECKED);
3742 else
3743 CheckMenuItem (hOptMenu, CMD_IOWIN, MF_UNCHECKED);
3744 doShowAll(hh);
3745 break;
3747 case CMD_SBTN: // Toggle showing top pushbutton-row
3748 ShowButtons ^= TRUE;
3749 if (ShowButtons != 0)
3750 CheckMenuItem (hOptMenu, CMD_SBTN, MF_CHECKED);
3751 else
3752 CheckMenuItem (hOptMenu, CMD_SBTN, MF_UNCHECKED);
3753 doShowAll(hh);
3754 break;
3756 case CMD_UCASE: // Toggle showing everything in uppercase
3758 UprCase ^= 1;
3759 if (UprCase != 0)
3760 CheckMenuItem (hOptMenu, CMD_UCASE, MF_CHECKED);
3761 else
3762 CheckMenuItem (hOptMenu, CMD_UCASE, MF_UNCHECKED);
3763 MakeRDnames();
3764 // the ASM window will be updated when it gets updated
3765 LoadRegList();
3766 // do the standard ASM window fill sequence
3767 Bit64u h = CurrentAsmLA;
3768 CanDoLA(&h);
3769 FillAsm(h, DefaultAsmLines);
3770 break;
3773 case CMD_MHEX: // Toggle showing hex in Dump window
3774 i = DumpInAsciiMode;
3775 i ^= 2;
3776 if (i != 0)
3778 DumpInAsciiMode = i;
3779 if ((DumpInAsciiMode & 2) != 0)
3780 CheckMenuItem (hOptMenu, CMD_MHEX, MF_CHECKED);
3781 else
3782 CheckMenuItem (hOptMenu, CMD_MHEX, MF_UNCHECKED);
3783 PrevDAD = 0; // force columns to resize
3784 if (DViewMode == VIEW_MEMDUMP && DumpInitted != FALSE)
3785 ShowData();
3787 break;
3789 case CMD_MASCII: // Toggle showing ASCII in Dump window
3790 i = DumpInAsciiMode;
3791 i ^= 1;
3792 if (i != 0)
3794 DumpInAsciiMode = i;
3795 if ((DumpInAsciiMode & 1) != 0)
3796 CheckMenuItem (hOptMenu, CMD_MASCII, MF_CHECKED);
3797 else
3798 CheckMenuItem (hOptMenu, CMD_MASCII, MF_UNCHECKED);
3799 PrevDAD = 0; // force columns to resize
3800 if (DViewMode == VIEW_MEMDUMP && DumpInitted != FALSE)
3801 ShowData();
3803 break;
3805 case CMD_LEND: // Toggle Endianness for the MemDumps
3806 isLittleEndian ^= TRUE;
3807 if (isLittleEndian != FALSE)
3808 CheckMenuItem (hOptMenu, CMD_LEND, MF_CHECKED);
3809 else
3810 CheckMenuItem (hOptMenu, CMD_LEND, MF_UNCHECKED);
3811 if (DViewMode == VIEW_MEMDUMP && DumpInitted != FALSE)
3812 ShowData();
3813 break;
3815 case CMD_WS_1: // set memory dump "wordsize"
3816 // "Align" = "wordsize" -- from 1 to 16
3817 doNewWSize(0);
3818 break;
3820 case CMD_WS_2:
3821 doNewWSize(1);
3822 break;
3824 case CMD_WS_4:
3825 doNewWSize(2);
3826 break;
3828 case CMD_WS_8:
3829 doNewWSize(3);
3830 break;
3832 case CMD_WS16:
3833 doNewWSize(4);
3834 break;
3836 case CMD_IGNSA: // Toggle ID disassembly output ignoring
3837 ignSSDisasm ^= TRUE;
3838 if (ignSSDisasm != FALSE)
3839 CheckMenuItem (hOptMenu, CMD_IGNSA, MF_CHECKED);
3840 else
3841 CheckMenuItem (hOptMenu, CMD_IGNSA, MF_UNCHECKED);
3842 break;
3844 case CMD_IGNNT: // Toggle NextT ignoring
3845 ignoreNxtT ^= TRUE;
3846 if (ignoreNxtT != FALSE)
3847 CheckMenuItem (hOptMenu, CMD_IGNNT, MF_CHECKED);
3848 else
3849 CheckMenuItem (hOptMenu, CMD_IGNNT, MF_UNCHECKED);
3850 break;
3852 case CMD_RCLR: // Toggle Register Coloring
3853 SeeRegColors ^= TRUE;
3854 if (SeeRegColors != FALSE)
3855 CheckMenuItem (hOptMenu, CMD_RCLR, MF_CHECKED);
3856 else
3857 CheckMenuItem (hOptMenu, CMD_RCLR, MF_UNCHECKED);
3858 LoadRegList();
3859 break;
3862 case CMD_EREG: // Show Registers of various types
3863 case CMD_SREG:
3864 case CMD_SYSR:
3865 case CMD_CREG:
3866 case CMD_FPUR:
3867 case CMD_XMMR:
3868 case CMD_DREG:
3869 case CMD_TREG:
3870 ToggleSeeReg(LW);
3871 break;
3873 case CMD_ABOUT: // "About" box
3874 MessageBox(hh,"Bochs Enhanced Debugger, Version 1.0\r\nCopyright (C) Chourdakis Michael.\r\nModified by Bruce Ewing",
3875 "About",MB_OK | MB_ICONINFORMATION);
3876 break;
3878 case CMD_FONT: // font
3879 HFONT hF = (HFONT) CallWindowProc(*wEdit,hE_I,WM_GETFONT,0,0);
3880 LOGFONT lf;
3881 GetObject(hF,sizeof(lf),&lf);
3882 CHOOSEFONT cF = {0};
3883 cF.lStructSize = sizeof(cF);
3884 cF.hwndOwner = hh;
3885 cF.lpLogFont = &lf;
3886 cF.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT;
3887 if (ChooseFont(&cF) == FALSE)
3888 return 0;
3890 ShowWindow(hL[0],SW_HIDE);
3891 ShowWindow(hL[1],SW_HIDE);
3892 ShowWindow(hL[2],SW_HIDE);
3893 ShowWindow(hS_S,SW_HIDE);
3894 ShowWindow(hE_I,SW_HIDE);
3895 if (CustomFont != NULL)
3896 DeleteObject (CustomFont);
3897 CustomFont = CreateFontIndirect(&lf);
3898 DeleteObject(hF);
3899 CallWindowProc(wListView,hL[0],WM_SETFONT,(WPARAM)CustomFont,MAKELPARAM(TRUE,0));
3900 CallWindowProc(wListView,hL[1],WM_SETFONT,(WPARAM)CustomFont,MAKELPARAM(TRUE,0));
3901 CallWindowProc(wListView,hL[2],WM_SETFONT,(WPARAM)CustomFont,MAKELPARAM(TRUE,0));
3902 CallWindowProc(*wEdit,hE_I,WM_SETFONT,(WPARAM)CustomFont,MAKELPARAM(TRUE,0));
3903 SendMessage(hS_S,WM_SETFONT,(WPARAM)CustomFont,MAKELPARAM(TRUE,0));
3904 doShowAll(hh);
3906 return 0;
3908 case WM_NOTIFY:
3910 // key down
3911 NMHDR* n = (NMHDR*)ll;
3912 if (n->code == LVN_KEYDOWN)
3914 NMLVKEYDOWN* key = (NMLVKEYDOWN*)ll; // pass any keystrokes from listview up to parent
3915 SendMessage(hh,WM_KEYDOWN,key->wVKey,0);
3917 if (n->code == NM_CUSTOMDRAW && n->hwndFrom == hL[1]) // custom drawing of ASM window
3919 // highlight the breakpoints, and current opcode, if any
3920 NMLVCUSTOMDRAW *d = (NMLVCUSTOMDRAW *) ll;
3921 if (d->nmcd.dwDrawStage == CDDS_PREPAINT)
3922 return CDRF_NOTIFYITEMDRAW;
3924 if (d->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) // select the "active" ASM line
3926 d->clrTextBk = RGB(255,255,255); // background is white
3927 if (!AtBreak)
3928 d->clrTextBk = RGB(210,210,210); // unless sim is "running"
3930 unsigned char r=0, g=0, b=0; // normal text color is black
3932 bx_address h = (bx_address) AsmLA[d->nmcd.dwItemSpec];
3933 if (h == CurrentAsmLA)
3934 g = 100; // current opcode is colored dark green
3935 int j= BreakCount;
3936 while (--j >= 0) // loop over all breakpoints
3938 // brk list is sorted -- if the value goes too low, end the loop
3939 // And I know for a fact that some complers are soooo stupid that they
3940 // will repeat the following test twice, unless you force them not to.
3941 register bx_address i = BrkLAddr[j] - h;
3942 // if (BrkLAddr[j] < h)
3943 if (i < 0)
3944 j = 0; // force the loop to end if it goes too far
3945 // else if (BrkLAddr[j] == h)
3946 else if (i == 0)
3948 g = j= 0;
3949 if (h == CurrentAsmLA)
3950 b = 200; // breakpoint @ current opcode = blue
3951 else
3952 r = 150; // active breakpoint is red
3955 d->clrText = RGB(r,g,b);
3957 break;
3959 if (n->code == NM_CUSTOMDRAW && n->hwndFrom == hL[2]) // custom drawing of data window
3961 NMLVCUSTOMDRAW *d = (NMLVCUSTOMDRAW *) ll;
3962 if (d->nmcd.dwDrawStage == CDDS_PREPAINT)
3963 return CDRF_NOTIFYITEMDRAW;
3965 d->clrTextBk = RGB(255,255,255); // background is white
3966 if (!AtBreak)
3967 d->clrTextBk = RGB(210,210,210); // unless sim is "running"
3969 else if (DViewMode == VIEW_STACK && d->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
3971 // highlight changed lines in stack
3972 int j = d->nmcd.dwItemSpec;
3973 if (j < 0 || j >= STACK_ENTRIES) // make sure the line # is legal
3975 else if (StackEntChg[j] != FALSE)
3976 d->clrText = RGB(255,0,0); // changed entry = red
3979 if (DumpAlign != 1 || DumpMode != 0 || DViewMode != VIEW_MEMDUMP)
3980 break;
3982 // highlight any physical watchpoints in physical DumpMode
3983 if (d->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
3985 SetWindowLong(hh, DWL_MSGRESULT, CDRF_NOTIFYSUBITEMDRAW);
3986 return CDRF_NOTIFYSUBITEMDRAW;
3989 if (d->nmcd.dwDrawStage == (CDDS_SUBITEM | CDDS_ITEMPREPAINT))
3991 d->clrText = RGB(0,0,0); // assume black text
3992 if (d->iSubItem != 0)
3994 // For each subitem, calculate its equivalent physmem address
3995 bx_phy_address h = (bx_phy_address) DumpStart +
3996 16*(d->nmcd.dwItemSpec) + d->iSubItem -1;
3997 int j = num_write_watchpoints;
3998 int i = num_read_watchpoints;
3999 while (j > 0)
4001 if (write_watchpoint[--j] == h)
4003 d->clrTextBk = RGB(0,0,0); // black background
4004 d->clrText = RGB(255,0,150); // write watchpoint
4005 j = -1; // on a match j<0 -- else j == 0
4008 while (--i >= 0)
4010 if (read_watchpoint[i] == h)
4012 if (j < 0) // BOTH read and write
4013 d->clrText = RGB(0,170,255);
4014 else
4016 d->clrTextBk = RGB(0,0,0); // black background
4017 d->clrText = RGB(130,255,0); // read watchpoint
4019 i = 0; // end the loop on a match
4024 break;
4026 if (n->code == NM_CUSTOMDRAW && n->hwndFrom == hL[0]) // custom drawing of register window
4028 // highlight changed registers
4029 NMLVCUSTOMDRAW *d = (NMLVCUSTOMDRAW *) ll;
4030 if (d->nmcd.dwDrawStage == CDDS_PREPAINT)
4031 return CDRF_NOTIFYITEMDRAW;
4033 if (d->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
4035 int i = d->nmcd.dwItemSpec;
4036 Bit8u ClrFlgs = RegColor[ RitemToRnum[i] ];
4037 d->clrText = RGB(0,0,0);
4038 d->clrTextBk = RGB(255,255,255);
4040 // RitemToRnum converts a ListView row number to the corresponding Register number.
4041 // RegColor has the 0x80 bit set if the register is supposed to be red.
4042 // Background color index is in the low nibble of ClrFlgs/RegColor.
4043 if (SeeRegColors != FALSE)
4044 d->clrTextBk = ColorList[ClrFlgs &7];
4045 if ((ClrFlgs & 0x80) != 0) // should this register be red?
4046 d->clrText = RGB(255,0,0);
4047 if (!AtBreak)
4048 d->clrTextBk = RGB(210,210,210); // gray out the background if "running"
4051 break;
4053 if (n->code == NM_DBLCLK)
4055 if (AtBreak == FALSE)
4056 break;
4058 if (n->hwndFrom == hL[0])
4060 // Change a register
4061 int L = CallWindowProc(wListView, hL[0], LVM_GETNEXTITEM,(WPARAM) -1,MAKELPARAM(LVNI_SELECTED, 0));
4062 if (L == -1 || L >= TOT_REG_NUM)
4063 break; // should be impossible
4065 int i = RitemToRnum[L];
4066 if (i > EFER_Rnum) // only able to do up to EFER for now
4067 break;
4068 char *d1;
4069 d1 = RDispName[i];
4070 sprintf (tmpcb,"0x%I64X", rV[i]);
4071 if (AskText(hh,"Change Register Value",d1,tmpcb,0))
4073 Bit64s val;
4074 char *s = tmpcb;
4075 while (*s == ' ') // allow user to enter whitespace
4076 ++s;
4077 if (*s == '0' && (s[1] =='X' || s[1] == 'x')) // and either hex or decimal
4078 sscanf (s+2,"%I64X",&val);
4079 else
4080 sscanf(tmpcb,"%I64d",&val);
4081 RegObject[CurrentCPU][i]->set(val); // the set function should be a bool, not a void
4082 // bx_bool worked = RegObject[CurrentCPU][i]->set(val);
4083 // if (worked == FALSE)
4084 // MessageBox (hh,"Bochs does not allow you to set that register","Selection Error", MB_ICONERROR) ;
4085 // else
4086 LoadRegList(); // update the register window
4089 if (n->hwndFrom == hL[1]) // doubleclick a breakpoint on ASM window
4090 SetBreak();
4092 if (n->hwndFrom == hL[2] && DViewMode == VIEW_MEMDUMP) // Change values in memory locations
4094 int L = CallWindowProc(wListView, hL[2], LVM_GETNEXTITEM,(WPARAM) -1,MAKELPARAM(LVNI_SELECTED, 0));
4095 i = 0; // flag if setting watchpoints
4096 if (GetKeyState(VK_SHIFT) < 0)
4098 i = 1;
4099 SetWatchpoint(&num_write_watchpoints,write_watchpoint);
4101 if (GetKeyState(VK_CONTROL) < 0)
4103 i = 1;
4104 SetWatchpoint(&num_read_watchpoints,read_watchpoint);
4106 if (L == -1 || i != 0) // L should never be -1, Exit after a watchpoint.
4107 break;
4109 // get base address of "line" of data -- each line (L) is 16 bytes
4110 Bit64u h = DumpStart + (L<<4);
4112 if (DumpMode == 0)
4113 sprintf(tmpcb,"Physical Address: 0x%I64X",h);
4114 else
4115 sprintf(tmpcb,"Linear Address: 0x%I64X",h);
4117 unsigned char *u = (unsigned char *)(DataDump + (L<<4)); // important that it be unsigned!
4118 sprintf(tmpcd,"%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
4119 *u,u[1],u[2],u[3],u[4],u[5],u[6],u[7],u[8],u[9],u[10],u[11],u[12],u[13],u[14],u[15]);
4121 if (AskText(hh,"Change Memory Values",tmpcb,tmpcd,0))
4123 Bit8u newval;
4124 int err=0;
4125 char *x = tmpcd;
4126 upr(x); // force input string to uppercase
4128 if (DumpMode != 0) // is h is a LINEAR address? Convert to physical!
4130 // use the ReadBx function to calculate the lin->phys offset
4131 if (ReadBxLMem (h,0,(Bit8u *)tmpcb) == FALSE) // "read" 0 bytes
4132 err = 2;
4133 else
4134 h -= l_p_offset; // convert h to a physmem address
4137 while (*x != 0 && err == 0)
4139 char *s = x;
4140 // verify that the next 2 chars are hex digits
4141 if ((*x < '0' || *x > '9') && (*x < 'A' || *x > 'F'))
4142 err = 1;
4143 else
4145 ++x;
4146 if ((*x < '0' || *x > '9') && (*x < 'A' || *x > 'F'))
4147 err = 1;
4148 else
4150 ++x;
4151 if (*x != ' ' && *x != 0) // followed by a space or 0
4152 err = 1;
4155 if (err == 0)
4157 // convert the hex to a byte, and try to store the byte in bochs physmem
4158 sscanf (s,"%2X",&newval);
4159 if ( bx_mem.dbg_set_mem( (bx_phy_address) h, 1, &newval) == FALSE )
4160 err = 2;
4161 ++h; // bump to the next mem address
4162 while (*x == ' ') // scan past whitespace
4163 ++x;
4167 if (err != 0)
4169 if (err == 1)
4170 MessageBox (hh,"Improper char hex format","Input Format Error", MB_ICONERROR);
4171 else
4172 MessageBox (hh,"Illegal memory address error?","Memory Error", MB_ICONERROR);
4174 ShowData(); // refresh the data dump, even if there were errors
4178 break;
4180 case WM_TIMER:
4182 if (PO_Tdelay > 0) // output window is delaying display of a partial line?
4184 if (--PO_Tdelay == 0) // on a timeout, add a lf to complete the line
4185 ParseUnknown ("\n");
4187 UpdateStatus();
4188 DEV_vga_refresh();
4189 break;
4191 case WM_NCMOUSEMOVE:
4193 // turn off any sizing operation if the cursor strays off the listviews
4194 Sizing = 0;
4195 // also turn off any half-completed mouseclicks
4196 xClick = -1;
4197 break;
4199 case WM_CLOSE:
4201 bx_user_quit = 1;
4202 SIM->debug_break();
4203 KillTimer(hh,2);
4204 if (CustomFont != NULL)
4205 DeleteObject (CustomFont);
4206 DestroyWindow(hDebugDialog);
4207 hDebugDialog = NULL;
4208 UnregisterClass("sLV",GetModuleHandle(0));
4209 break;
4211 case WM_USER:
4213 // ww == 0x1234, ll = 0 - bochs started running a command
4214 // 11 = 1 - bochs stopped on some type of break
4215 // ll = 2 - bochs is ready to run a command
4216 // ww == 0x5678 - output text from debugger in available in lparam
4218 if (ww == 0x1234 && ll == 2)
4219 dbgOn = TRUE; // bochs internal debugger is able to accept commands now
4221 if (ww != 0x1234 || ll != 0)
4223 // Sim is at a "break".
4224 if (AtBreak == FALSE)
4226 AtBreak = TRUE;
4227 StatusChange = TRUE;
4229 if (doDumpRefresh != FALSE)
4230 RefreshDataWin();
4231 OnBreak();
4234 if (ww == 0x5678) // bochs internal debugger produced some text?
4236 if (strstr((char*)ll,"HALTED"))
4237 break;
4239 ParseUnknown((char*)ll); // Process all debugger text output
4241 return 0;
4244 return DefWindowProc(hh,mm,ww,ll);
4247 ATOM BRegister()
4249 InitCommonControls();
4250 SpListView();
4251 SpBtn();
4252 WNDCLASSEX wC = {0};
4253 wC.cbSize = sizeof(wC);
4254 wC.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
4255 hCursArrow = LoadCursor(NULL,IDC_ARROW);
4256 wC.hCursor = hCursArrow;
4257 wC.hInstance = GetModuleHandle(0);
4258 wC.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS | CS_DBLCLKS;
4259 wC.lpfnWndProc = B_WP;
4260 wC.cbWndExtra = sizeof(void*);
4261 wC.lpszClassName = "bochs_dbg_x";
4262 wC.hIcon = LoadIcon(GetModuleHandle(0),"ICON_D");
4263 wC.hIconSm = LoadIcon(GetModuleHandle(0),"ICON_D");
4264 ATOM P1 = RegisterClassEx(&wC);
4265 return P1;
4268 void RefreshDebugDialog()
4272 void InitDebugDialog(HWND mainwnd)
4274 BRegister();
4275 HMENU hTopMenu = LoadMenu(GetModuleHandle(0),"MENU_1");
4276 hOptMenu = GetSubMenu (hTopMenu, 2);
4277 hViewMenu = GetSubMenu (hTopMenu, 1);
4278 hCmdMenu = GetSubMenu (hTopMenu, 0);
4279 hY = CreateWindowEx(0,"bochs_dbg_x","Bochs Enhanced Debugger (Type 2)",
4280 WS_OVERLAPPEDWINDOW | WS_VISIBLE,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
4281 0,hTopMenu,GetModuleHandle(0),0);
4282 if (hY == NULL)
4283 DebugBreak();
4285 hDebugDialog = hY;
4286 return;
4289 #endif