From 6740d478b2f9c2aad5fbf36e9a4e4a3530018646 Mon Sep 17 00:00:00 2001 From: luigi__ Date: Sun, 13 Sep 2009 00:17:59 +0000 Subject: [PATCH] Windows port: brand new I/O reg viewer. - Allows to view all the registers, the registers of a certain category, or one register in detail. - Table system facilitating implementation of new registers - Implements the registers that were implemented in the old I/O reg viewer, so there's no loss - You can open as many I/O reg viewers as you want --- desmume/src/windows/CWindow.cpp | 18 + desmume/src/windows/CWindow.h | 3 + desmume/src/windows/IORegView.cpp | 701 ++++++++++++++++++++++++------ desmume/src/windows/IORegView.h | 32 +- desmume/src/windows/main.cpp | 17 +- 5 files changed, 635 insertions(+), 136 deletions(-) diff --git a/desmume/src/windows/CWindow.cpp b/desmume/src/windows/CWindow.cpp index 3a2b671d9..e6581e5bd 100644 --- a/desmume/src/windows/CWindow.cpp +++ b/desmume/src/windows/CWindow.cpp @@ -41,6 +41,24 @@ DWORD GetFontQuality() return ANTIALIASED_QUALITY; } +int DrawText(HDC hDC, char* text, int X, int Y, int Width, int Height, UINT format) +{ + RECT rc; + SetRect(&rc, X, Y, X+Width, Y+Height); + return DrawText(hDC, text, -1, &rc, format); +} + +void GetFontSize(HWND hWnd, HFONT hFont, LPSIZE size) +{ + HDC dc = GetDC(hWnd); + HFONT oldfont = (HFONT)SelectObject(dc, hFont); + + GetTextExtentPoint32(dc, " ", 1, size); + + SelectObject(dc, oldfont); + ReleaseDC(hWnd, dc); +} + //----------------------------------------------------------------------------- // Window class handling //----------------------------------------------------------------------------- diff --git a/desmume/src/windows/CWindow.h b/desmume/src/windows/CWindow.h index 09445c4fc..96640a260 100644 --- a/desmume/src/windows/CWindow.h +++ b/desmume/src/windows/CWindow.h @@ -38,6 +38,9 @@ extern CRITICAL_SECTION win_execute_sync; // antialiasing is enabled or not. DWORD GetFontQuality(); +int DrawText(HDC hDC, char* text, int X, int Y, int Width, int Height, UINT format); +void GetFontSize(HWND hWnd, HFONT hFont, LPSIZE size); + //----------------------------------------------------------------------------- // Window class handling //----------------------------------------------------------------------------- diff --git a/desmume/src/windows/IORegView.cpp b/desmume/src/windows/IORegView.cpp index 526440912..758bfacf0 100644 --- a/desmume/src/windows/IORegView.cpp +++ b/desmume/src/windows/IORegView.cpp @@ -19,154 +19,611 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "ioregview.h" +#include "CWindow.h" +#include "IORegView.h" #include #include "debug.h" #include "resource.h" #include "../MMU.h" #include "../armcpu.h" -typedef struct +/*--------------------------------------------------------------------------*/ + +enum EIORegType { - u32 autoup_secs; - bool autoup; -} ioregview_struct; + ListEnd = 0, + AllRegs, + CatBegin, + MMIOReg, + CP15Reg +}; -ioregview_struct *IORegView; - -LRESULT Ioreg_OnPaint(HWND hwnd, WPARAM wParam, LPARAM lParam) +typedef struct _IORegBitfield { - HDC hdc; - PAINTSTRUCT ps; - TCHAR text[80]; - - hdc = BeginPaint(hwnd, &ps); - - // ARM9 registers - sprintf(text, "0x%08X", (int)((u32 *)MMU.ARM9_DTCM)[0x3FFC>>2]); - SetWindowText(GetDlgItem(hwnd, IDC_INTHAND9), text); + char name[32]; + int shift; + int nbits; +} IORegBitfield; - sprintf(text, "0x%08X", (int)MMU.reg_IE[ARMCPU_ARM9]); - SetWindowText(GetDlgItem(hwnd, IDC_IE9), text); +typedef struct _IOReg +{ + EIORegType type; + char name[32]; + u32 address; + int size; // for AllRegs: total number of regs; for CatBegin: number of regs in category + int numBitfields; + IORegBitfield bitfields[32]; +} IOReg; - sprintf(text, "0x%08X", (int)MMU.reg_IF[ARMCPU_ARM9]); - SetWindowText(GetDlgItem(hwnd, IDC_IF9), text); +IOReg IORegs9[] = { + {AllRegs, "All registers", 0, 9, 0, {{0}}}, - sprintf(text, "%s", ((int)(MMU.reg_IME[ARMCPU_ARM9]) & 0x01)?"enabled":"disabled"); - SetWindowText(GetDlgItem(hwnd, IDC_IME9), text); + {CatBegin, "General video registers", 0, 1, 0, {{0}}}, + {MMIOReg, "DISPSTAT", 0x04000004, 2, 8, {{"VBlank",0,1},{"HBlank",1,1},{"VCount match",2,1},{"Enable VBlank IRQ",3,1}, + {"Enable HBlank IRQ",4,1},{"Enable VCount match IRQ",5,1},{"VCount MSb",7,1},{"VCount LSb's",8,8}}}, - sprintf(text, "0x%08X", ((u16 *)MMU.ARM9_REG)[0x0000>>1]); - SetWindowText(GetDlgItem(hwnd, IDC_DISPCNTA9), text); + {CatBegin, "Video engine A registers", 0, 1, 0, {{0}}}, + {MMIOReg, "DISPCNT_A", 0x04000000, 4, 23, {{"BG mode",0,3},{"BG0 -> 3D",3,1},{"Tile OBJ mapping",4,1},{"Bitmap OBJ 2D size",5,1}, + {"Bitmap OBJ mapping",6,1},{"Forced blank",7,1},{"Display BG0",8,1},{"Display BG1",9,1}, + {"Display BG2",10,1},{"Display BG3",11,1},{"Display OBJ",12,1},{"Display window 0",13,1}, + {"Display window 1",14,1},{"Display OBJ window",15,1},{"Display mode",16,2},{"VRAM block",18,2}, + {"Tile OBJ 1D boundary",20,2},{"Bitmap OBJ 1D boundary",22,1},{"Process OBJs during HBlank",23,1},{"Character base",24,3}, + {"Screen base",27,3},{"Enable BG ext. palettes",30,1},{"Enable OBJ ext. palettes",31,1}}}, - sprintf(text, "0x%08X", ((u16 *)MMU.ARM9_REG)[0x0004>>1]); - SetWindowText(GetDlgItem(hwnd, IDC_DISPSTATA9), text); + {CatBegin, "Video engine B registers", 0, 1, 0, {{0}}}, + {MMIOReg, "DISPCNT_B", 0x04001000, 4, 18, {{"BG mode",0,3},{"Tile OBJ mapping",4,1},{"Bitmap OBJ 2D size",5,1},{"Bitmap OBJ mapping",6,1}, + {"Forced blank",7,1},{"Display BG0",8,1},{"Display BG1",9,1},{"Display BG2",10,1}, + {"Display BG3",11,1},{"Display OBJ",12,1},{"Display window 0",13,1},{"Display window 1",14,1}, + {"Display OBJ window",15,1},{"Display mode",16,2},{"Tile OBJ 1D boundary",20,2},{"Process OBJs during HBlank",23,1}, + {"Enable BG ext. palettes",30,1},{"Enable OBJ ext. palettes",31,1}}}, + + {CatBegin, "3D video engine registers", 0, 1, 0, {{0}}}, + {MMIOReg, "GXSTAT", 0x04000600, 4, 12, {{"Box/Pos/Vec-test busy",0,1},{"Box-test result",1,1},{"Pos&Vec mtx stack level",8,5},{"Proj mtx stack level",13,1}, + {"Mtx stack busy",14,1},{"Mtx stack over/under-flow",15,1},{"GX FIFO level",16,9},{"GX FIFO full",24,1}, + {"GX FIFO less than half full",25,1},{"GX FIFO empty",26,1},{"GX busy",27,1},{"GX FIFO IRQ condition",30,2}}}, - sprintf(text, "0x%08X", ((u16 *)MMU.ARM9_REG)[0x1000>>1]); - SetWindowText(GetDlgItem(hwnd, IDC_DISPCNTB9), text); + {CatBegin, "IPC registers", 0, 2, 0, {{0}}}, + {MMIOReg, "IPCSYNC", 0x04000180, 2, 3, {{"Data input from remote",0,4},{"Data output to remote",8,4},{"Enable IRQ from remote",14,1}}}, + {MMIOReg, "IPCFIFOCNT", 0x04000184, 2, 8, {{"Send FIFO empty",0,1},{"Send FIFO full",1,1},{"Enable send FIFO empty IRQ",2,1},{"Recv FIFO empty",8,1}, + {"Recv FIFO full",9,1},{"Enable recv FIFO not empty IRQ",10,1},{"Recv empty/Send full",14,1},{"Enable send/recv FIFO",15,1}}}, - sprintf(text, "0x%08X", ((u16 *)MMU.ARM9_REG)[0x1004>>1]); - SetWindowText(GetDlgItem(hwnd, IDC_DISPSTATB9), text); + {CatBegin, "IRQ control registers", 0, 3, 0, {{0}}}, + {MMIOReg, "IME", 0x04000208, 2, 1, {{"Enable IRQs",0,1}}}, + {MMIOReg, "IE", 0x04000210, 4, 21, {{"VBlank",0,1},{"HBlank",1,1},{"VCount match",2,1},{"Timer 0",3,1}, + {"Timer 1",4,1},{"Timer 2",5,1},{"Timer 3",6,1},{"DMA 0",8,1}, + {"DMA 1",9,1},{"DMA 2",10,1},{"DMA 3",11,1},{"Keypad",12,1}, + {"Game Pak",13,1},{"IPC sync",16,1},{"IPC send FIFO empty",17,1},{"IPC recv FIFO not empty",18,1}, + {"Gamecard transfer",19,1},{"Gamecard IREQ_MC",20,1},{"GX FIFO",21,1}}}, + {MMIOReg, "IF", 0x04000214, 4, 21, {{"VBlank",0,1},{"HBlank",1,1},{"VCount match",2,1},{"Timer 0",3,1}, + {"Timer 1",4,1},{"Timer 2",5,1},{"Timer 3",6,1},{"DMA 0",8,1}, + {"DMA 1",9,1},{"DMA 2",10,1},{"DMA 3",11,1},{"Keypad",12,1}, + {"Game Pak",13,1},{"IPC sync",16,1},{"IPC send FIFO empty",17,1},{"IPC recv FIFO not empty",18,1}, + {"Gamecard transfer",19,1},{"Gamecard IREQ_MC",20,1},{"GX FIFO",21,1}}}, - sprintf(text, "0x%08X", (int)((u32 *)MMU.ARM9_REG)[0x180>>2]); - SetWindowText(GetDlgItem(hwnd, IDC_IPCSYNC9), text); + {ListEnd, 0, 0, 0, 0, {{0}}} +}; - sprintf(text, "0x%08X", (int)((u32 *)MMU.ARM9_REG)[0x184>>2]); - SetWindowText(GetDlgItem(hwnd, IDC_IPCFIFO9), text); +IOReg IORegs7[] = { + {AllRegs, "All registers", 0, 5, 0, {{0}}}, - sprintf(text, "0x%08X", (int)((u32 *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x600>>2]); - SetWindowText(GetDlgItem(hwnd, IDC_GXSTAT9), text); + {CatBegin, "IPC registers", 0, 2, 0, {{0}}}, + {MMIOReg, "IPCSYNC", 0x04000180, 2, 3, {{"Data input from remote",0,4},{"Data output to remote",8,4},{"Enable IRQ from remote",14,1}}}, + {MMIOReg, "IPCFIFOCNT", 0x04000184, 2, 8, {{"Send FIFO empty",0,1},{"Send FIFO full",1,1},{"Enable send FIFO empty IRQ",2,1},{"Recv FIFO empty",8,1}, + {"Recv FIFO full",9,1},{"Enable recv FIFO not empty IRQ",10,1},{"Recv empty/Send full",14,1},{"Enable send/recv FIFO",15,1}}}, - // ARM7 registers - sprintf(text, "0x%08X", (int)MMU.reg_IE[ARMCPU_ARM7]); - SetWindowText(GetDlgItem(hwnd, IDC_IE7), text); + {CatBegin, "IRQ control registers", 0, 3, 0, {{0}}}, + {MMIOReg, "IME", 0x04000208, 2, 1, {{"Enable IRQs",0,1}}}, + {MMIOReg, "IE", 0x04000210, 4, 22, {{"VBlank",0,1},{"HBlank",1,1},{"VCount match",2,1},{"Timer 0",3,1}, + {"Timer 1",4,1},{"Timer 2",5,1},{"Timer 3",6,1},{"RTC",7,1}, + {"DMA 0",8,1},{"DMA 1",9,1},{"DMA 2",10,1},{"DMA 3",11,1}, + {"Keypad",12,1},{"Game Pak",13,1},{"IPC sync",16,1},{"IPC send FIFO empty",17,1}, + {"IPC recv FIFO not empty",18,1},{"Gamecard transfer",19,1},{"Gamecard IREQ_MC",20,1},{"Lid opened",22,1}, + {"SPI bus",23,1},{"Wifi",24,1}}}, + {MMIOReg, "IF", 0x04000214, 4, 22, {{"VBlank",0,1},{"HBlank",1,1},{"VCount match",2,1},{"Timer 0",3,1}, + {"Timer 1",4,1},{"Timer 2",5,1},{"Timer 3",6,1},{"RTC",7,1}, + {"DMA 0",8,1},{"DMA 1",9,1},{"DMA 2",10,1},{"DMA 3",11,1}, + {"Keypad",12,1},{"Game Pak",13,1},{"IPC sync",16,1},{"IPC send FIFO empty",17,1}, + {"IPC recv FIFO not empty",18,1},{"Gamecard transfer",19,1},{"Gamecard IREQ_MC",20,1},{"Lid opened",22,1}, + {"SPI bus",23,1},{"Wifi",24,1}}}, - sprintf(text, "0x%08X", (int)MMU.reg_IF[ARMCPU_ARM7]); - SetWindowText(GetDlgItem(hwnd, IDC_IF7), text); + {ListEnd, 0, 0, 0, 0, {{0}}} +}; - sprintf(text, "%s", ((int)(MMU.reg_IME[ARMCPU_ARM7]) & 0x01)?"enabled":"disabled"); - SetWindowText(GetDlgItem(hwnd, IDC_IME7), text); +IOReg* IORegs[2] = {IORegs9, IORegs7}; - sprintf(text, "0x%08X", (int)((u32 *)MMU.ARM7_REG)[0x180>>2]); - SetWindowText(GetDlgItem(hwnd, IDC_IPCSYNC7), text); +static const int kXMargin = 5; +static const int kYMargin = 1; - sprintf(text, "0x%08X", (int)((u32 *)MMU.ARM7_REG)[0x184>>2]); - SetWindowText(GetDlgItem(hwnd, IDC_IPCFIFO7), text); - EndPaint(hwnd, &ps); +/*--------------------------------------------------------------------------*/ - return 0; +CIORegView::CIORegView() + : CToolWindow("DeSmuME_IORegView", IORegView_Proc, "I/O registers", 400, 400) + , CPU(ARMCPU_ARM9) + , Reg(0) + , yoff(0) +{ } -BOOL CALLBACK IoregView_Proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +CIORegView::~CIORegView() { - switch (message) - { - case WM_INITDIALOG : - IORegView = new ioregview_struct; - memset(IORegView, 0, sizeof(ioregview_struct)); - IORegView->autoup_secs = 1; - SendMessage(GetDlgItem(hwnd, IDC_AUTO_UPDATE_SPIN), - UDM_SETRANGE, 0, MAKELONG(99, 1)); - SendMessage(GetDlgItem(hwnd, IDC_AUTO_UPDATE_SPIN), - UDM_SETPOS32, 0, IORegView->autoup_secs); - return 1; - case WM_CLOSE : - if(IORegView->autoup) - { - KillTimer(hwnd, IDT_VIEW_IOREG); - IORegView->autoup = false; - } - - if (IORegView!=NULL) - { - delete IORegView; - IORegView = NULL; - } - PostQuitMessage(0); - return 1; - case WM_PAINT: - Ioreg_OnPaint(hwnd, wParam, lParam); - return 1; - case WM_TIMER: - SendMessage(hwnd, WM_COMMAND, IDC_REFRESH, 0); - return 1; - case WM_COMMAND : - if(IORegView == NULL) return 0; - switch (LOWORD (wParam)) - { - case IDC_FERMER : - SendMessage(hwnd, WM_CLOSE, 0, 0); - return 1; - case IDC_AUTO_UPDATE : - if(IORegView->autoup) - { - EnableWindow(GetDlgItem(hwnd, IDC_AUTO_UPDATE_SECS), false); - EnableWindow(GetDlgItem(hwnd, IDC_AUTO_UPDATE_SPIN), false); - KillTimer(hwnd, IDT_VIEW_IOREG); - IORegView->autoup = FALSE; - return 1; - } - EnableWindow(GetDlgItem(hwnd, IDC_AUTO_UPDATE_SECS), true); - EnableWindow(GetDlgItem(hwnd, IDC_AUTO_UPDATE_SPIN), true); - IORegView->autoup = TRUE; - SetTimer(hwnd, IDT_VIEW_IOREG, IORegView->autoup_secs*20, (TIMERPROC) NULL); - return 1; - case IDC_AUTO_UPDATE_SECS: - { - int t = GetDlgItemInt(hwnd, IDC_AUTO_UPDATE_SECS, FALSE, TRUE); - if (t != IORegView->autoup_secs) - { - IORegView->autoup_secs = t; - if (IORegView->autoup) - SetTimer(hwnd, IDT_VIEW_IOREG, - IORegView->autoup_secs*20, (TIMERPROC) NULL); - } - } - return 1; - case IDC_REFRESH: - InvalidateRect(hwnd, NULL, FALSE); - return 1; - } - return 0; - } - return FALSE; + DestroyWindow(hWnd); + UnregWndClass("DeSmuME_IORegView"); } + +/*--------------------------------------------------------------------------*/ + +void CIORegView::ChangeCPU(int cpu) +{ + CPU = cpu; + + SendMessage(hRegCombo, CB_RESETCONTENT, 0, 0); + for (int i = 0; ; i++) + { + IOReg reg = IORegs[CPU][i]; + char str[128]; + + if (reg.type == ListEnd) + break; + else + switch (reg.type) + { + case AllRegs: + sprintf(str, "* %s", reg.name); + break; + case CatBegin: + sprintf(str, "** %s", reg.name); + break; + case MMIOReg: + sprintf(str, "*** 0x%08X - %s", reg.address, reg.name); + break; + } + + SendMessage(hRegCombo, CB_ADDSTRING, 0, (LPARAM)str); + } + ChangeReg(0); +} + +void CIORegView::ChangeReg(int reg) +{ + Reg = reg; + IOReg _reg = IORegs[CPU][Reg]; + + if ((_reg.type == AllRegs) || (_reg.type == CatBegin)) + numlines = 2 + _reg.size; + else + numlines = 3 + _reg.numBitfields; + + if (maxlines < numlines) + { + BOOL oldenable = IsWindowEnabled(hScrollbar); + if (!oldenable) + { + RECT rc; GetClientRect(hWnd, &rc); + + EnableWindow(hScrollbar, TRUE); + SendMessage(hScrollbar, SBM_SETRANGE, 0, (numlines * lineheight) - (rc.bottom - rebarHeight)); + SendMessage(hScrollbar, SBM_SETPOS, 0, 0); + } + } + else + EnableWindow(hScrollbar, FALSE); + + SendMessage(hRegCombo, CB_SETCURSEL, Reg, 0); +} + +/*--------------------------------------------------------------------------*/ + +void IORegView_Paint(CIORegView* wnd, HWND hWnd, WPARAM wParam, LPARAM lParam) +{ + HDC hDC; + PAINTSTRUCT ps; + HDC hMemDC; + HBITMAP hMemBitmap; + RECT rc; + HPEN pen; + int x, y, w, h; + int nameColWidth; + int curx, cury; + SIZE fontsize; + IOReg reg; + char txt[80]; + + GetClientRect(hWnd, &rc); + x = 0; + y = wnd->rebarHeight; + w = rc.right - wnd->vsbWidth; + h = rc.bottom - wnd->rebarHeight; + curx = kXMargin; cury = wnd->yoff + kYMargin; + + hDC = BeginPaint(hWnd, &ps); + + hMemDC = CreateCompatibleDC(hDC); + hMemBitmap = CreateCompatibleBitmap(hDC, w, h); + SelectObject(hMemDC, hMemBitmap); + + pen = CreatePen(PS_SOLID, 1, RGB(210, 230, 255)); + SelectObject(hMemDC, pen); + + SelectObject(hMemDC, wnd->hFont); + GetTextExtentPoint32(hMemDC, " ", 1, &fontsize); + + FillRect(hMemDC, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH)); + + reg = IORegs[wnd->CPU][wnd->Reg]; + if ((reg.type == AllRegs) || (reg.type == CatBegin)) + { + nameColWidth = w - (kXMargin + (fontsize.cx*8) + kXMargin + 1 + kXMargin + kXMargin + 1 + kXMargin + (fontsize.cx*8) + kXMargin); + + DrawText(hMemDC, reg.name, curx, cury, w, fontsize.cy, DT_LEFT | DT_END_ELLIPSIS); + cury += fontsize.cy + kYMargin; + MoveToEx(hMemDC, 0, cury, NULL); + LineTo(hMemDC, w, cury); + cury ++; + + curx = kXMargin; + DrawText(hMemDC, "Address", curx, cury+kYMargin, fontsize.cx*8, fontsize.cy, DT_LEFT); + curx += (fontsize.cx*8) + kXMargin; + MoveToEx(hMemDC, curx, cury, NULL); + LineTo(hMemDC, curx, h); + curx += 1 + kXMargin; + DrawText(hMemDC, "Name", curx, cury+kYMargin, nameColWidth, fontsize.cy, DT_LEFT | DT_END_ELLIPSIS); + curx += nameColWidth + kXMargin; + MoveToEx(hMemDC, curx, cury, NULL); + LineTo(hMemDC, curx, h); + curx += 1 + kXMargin; + DrawText(hMemDC, "Value", curx, cury+kYMargin, fontsize.cx*8, fontsize.cy, DT_RIGHT); + + cury += kYMargin + fontsize.cy + kYMargin; + MoveToEx(hMemDC, 0, cury, NULL); + LineTo(hMemDC, w, cury); + cury += 1 + kYMargin; + + for (int i = wnd->Reg+1; ; i++) + { + IOReg curReg = IORegs[wnd->CPU][i]; + curx = kXMargin; + + if (curReg.type == CatBegin) + { + if (reg.type == AllRegs) continue; + else break; + } + else if (curReg.type == ListEnd) + break; + else if (curReg.type == MMIOReg) + { + u32 val; + + sprintf(txt, "%08X", curReg.address); + DrawText(hMemDC, txt, curx, cury, fontsize.cx*8, fontsize.cy, DT_LEFT); + curx += (fontsize.cx*8) + kXMargin + 1 + kXMargin; + + DrawText(hMemDC, curReg.name, curx, cury, nameColWidth, fontsize.cy, DT_LEFT | DT_END_ELLIPSIS); + curx += nameColWidth + kXMargin + 1 + kXMargin; + + switch (curReg.size) + { + case 1: + val = (u32)MMU_read8(wnd->CPU, curReg.address); + sprintf(txt, "%02X", val); + break; + case 2: + val = (u32)MMU_read16(wnd->CPU, curReg.address); + sprintf(txt, "%04X", val); + break; + case 4: + val = MMU_read32(wnd->CPU, curReg.address); + sprintf(txt, "%08X", val); + break; + } + DrawText(hMemDC, txt, curx, cury, fontsize.cx*8, fontsize.cy, DT_RIGHT); + } + + cury += fontsize.cy + kYMargin; + if (cury >= h) break; + MoveToEx(hMemDC, 0, cury, NULL); + LineTo(hMemDC, w, cury); + cury += 1 + kYMargin; + } + } + else + { + u32 val; + nameColWidth = w - (kXMargin + (fontsize.cx*8) + kXMargin + 1 + kXMargin + kXMargin + 1 + kXMargin + (fontsize.cx*8) + kXMargin); + + sprintf(txt, "%08X - %s", reg.address, reg.name); + DrawText(hMemDC, txt, curx, cury, w, fontsize.cy, DT_LEFT | DT_END_ELLIPSIS); + cury += fontsize.cy + kYMargin; + MoveToEx(hMemDC, 0, cury, NULL); + LineTo(hMemDC, w, cury); + cury += 1 + kYMargin; + + switch (reg.size) + { + case 1: + val = (u32)MMU_read8(wnd->CPU, reg.address); + sprintf(txt, "Value: %02X", val); + break; + case 2: + val = (u32)MMU_read16(wnd->CPU, reg.address); + sprintf(txt, "Value: %04X", val); + break; + case 4: + val = MMU_read32(wnd->CPU, reg.address); + sprintf(txt, "Value: %08X", val); + break; + } + DrawText(hMemDC, txt, curx, cury, w, fontsize.cy, DT_LEFT); + cury += fontsize.cy + kYMargin; + MoveToEx(hMemDC, 0, cury, NULL); + LineTo(hMemDC, w, cury); + cury ++; + + curx = kXMargin; + DrawText(hMemDC, "Bits", curx, cury+kYMargin, fontsize.cx*8, fontsize.cy, DT_LEFT); + curx += (fontsize.cx*8) + kXMargin; + MoveToEx(hMemDC, curx, cury, NULL); + LineTo(hMemDC, curx, h); + curx += 1 + kXMargin; + DrawText(hMemDC, "Description", curx, cury+kYMargin, nameColWidth, fontsize.cy, DT_LEFT | DT_END_ELLIPSIS); + curx += nameColWidth + kXMargin; + MoveToEx(hMemDC, curx, cury, NULL); + LineTo(hMemDC, curx, h); + curx += 1 + kXMargin; + DrawText(hMemDC, "Value", curx, cury+kYMargin, fontsize.cx*8, fontsize.cy, DT_RIGHT); + + cury += kYMargin + fontsize.cy + kYMargin; + MoveToEx(hMemDC, 0, cury, NULL); + LineTo(hMemDC, w, cury); + cury += 1 + kYMargin; + + for (int i = 0; i < reg.numBitfields; i++) + { + IORegBitfield bitfield = reg.bitfields[i]; + curx = kXMargin; + + if (bitfield.nbits > 1) + sprintf(txt, "Bit%i-%i", bitfield.shift, bitfield.shift + bitfield.nbits - 1); + else + sprintf(txt, "Bit%i", bitfield.shift); + DrawText(hMemDC, txt, curx, cury, fontsize.cx*8, fontsize.cy, DT_LEFT); + curx += (fontsize.cx*8) + kXMargin + 1 + kXMargin; + + DrawText(hMemDC, bitfield.name, curx, cury, nameColWidth, fontsize.cy, DT_LEFT | DT_END_ELLIPSIS); + curx += nameColWidth + kXMargin + 1 + kXMargin; + + char bfpattern[8]; + sprintf(bfpattern, "%%0%iX", ((bitfield.nbits+3)&~3) >> 2); + sprintf(txt, bfpattern, (val >> bitfield.shift) & ((1<= h) break; + MoveToEx(hMemDC, 0, cury, NULL); + LineTo(hMemDC, w, cury); + cury += 1 + kYMargin; + } + } + + BitBlt(hDC, x, y, w, h, hMemDC, 0, 0, SRCCOPY); + + DeleteDC(hMemDC); + DeleteObject(hMemBitmap); + + DeleteObject(pen); + + EndPaint(hWnd, &ps); +} + +LRESULT CALLBACK IORegView_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + CIORegView* wnd = (CIORegView*)GetWindowLongPtr(hWnd, DWLP_USER); + if ((wnd == NULL) && (uMsg != WM_CREATE)) + return DefWindowProc(hWnd, uMsg, wParam, lParam); + + switch (uMsg) + { + case WM_CREATE: + { + RECT rc; + SIZE fontsize; + + // Retrieve the CIORegView instance passed upon window creation + // and match it to the window + wnd = (CIORegView*)((CREATESTRUCT*)lParam)->lpCreateParams; + SetWindowLongPtr(hWnd, DWLP_USER, (LONG)wnd); + + // Create the fixed-pitch font + wnd->hFont = CreateFont(16, 0, 0, 0, FW_MEDIUM, FALSE, FALSE, FALSE, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, GetFontQuality(), FIXED_PITCH, "Courier New"); + + // Create the vertical scrollbar + // The sizing and positioning of the scrollbar is done in WM_SIZE messages + wnd->vsbWidth = GetSystemMetrics(SM_CXVSCROLL); + wnd->hScrollbar = CreateWindow("Scrollbar", "", + WS_CHILD | WS_VISIBLE | WS_DISABLED | SBS_VERT, + 0, 0, 0, 0, hWnd, NULL, hAppInst, NULL); + + // Create the rebar that will hold all the controls + wnd->hRebar = CreateWindowEx(WS_EX_TOOLWINDOW, REBARCLASSNAME, NULL, + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NODIVIDER | RBS_VARHEIGHT | RBS_BANDBORDERS, + 0, 0, 0, 0, hWnd, NULL, hAppInst, NULL); + + // Create the CPU combobox and fill it + wnd->hCPUCombo = CreateWindow("ComboBox", "", + WS_CHILD | WS_VISIBLE | WS_VSCROLL | CBS_DROPDOWNLIST, + 0, 0, 0, 50, wnd->hRebar, (HMENU)IDC_CPU, hAppInst, NULL); + + SendMessage(wnd->hCPUCombo, WM_SETFONT, (WPARAM)wnd->hFont, TRUE); + SendMessage(wnd->hCPUCombo, CB_ADDSTRING, 0, (LPARAM)"ARM9"); + SendMessage(wnd->hCPUCombo, CB_ADDSTRING, 0, (LPARAM)"ARM7"); + SendMessage(wnd->hCPUCombo, CB_SETCURSEL, 0, 0); + + // Create the reg combobox and fill it + wnd->hRegCombo = CreateWindow("ComboBox", "", + WS_CHILD | WS_VISIBLE | WS_VSCROLL | CBS_DROPDOWNLIST, + 0, 0, 0, 400, wnd->hRebar, (HMENU)IDC_IOREG, hAppInst, NULL); + + SendMessage(wnd->hRegCombo, WM_SETFONT, (WPARAM)wnd->hFont, TRUE); + SendMessage(wnd->hRegCombo, CB_SETDROPPEDWIDTH, 300, 0); + wnd->ChangeCPU(ARMCPU_ARM9); + SendMessage(wnd->hRegCombo, CB_SETCURSEL, 0, 0); + + // Add all those nice controls to the rebar + REBARBANDINFO rbBand = { 80 }; + + rbBand.fMask = RBBIM_STYLE | RBBIM_TEXT | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE; + rbBand.fStyle = RBBS_CHILDEDGE | RBBS_NOGRIPPER; + + GetWindowRect(wnd->hCPUCombo, &rc); + rbBand.lpText = "CPU: "; + rbBand.hwndChild = wnd->hCPUCombo; + rbBand.cxMinChild = 0; + rbBand.cyMinChild = rc.bottom - rc.top; + SendMessage(wnd->hRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand); + + GetWindowRect(wnd->hRegCombo, &rc); + rbBand.lpText = "Registers: "; + rbBand.hwndChild = wnd->hRegCombo; + rbBand.cxMinChild = 0; + rbBand.cyMinChild = rc.bottom - rc.top; + rbBand.cx = 0; + SendMessage(wnd->hRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand); + + GetWindowRect(wnd->hRebar, &rc); + wnd->rebarHeight = rc.bottom - rc.top; + + GetFontSize(hWnd, wnd->hFont, &fontsize); + wnd->lineheight = kYMargin + fontsize.cy + kYMargin + 1; + } + return 0; + + case WM_CLOSE: + CloseToolWindow(wnd); + return 0; + + case WM_SIZE: + { + RECT rc; + int wndHeight, lineHeight; + + // Resize and reposition the controls + SetWindowPos(wnd->hRebar, NULL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, SWP_NOZORDER | SWP_NOMOVE); + + GetClientRect(hWnd, &rc); + SetWindowPos(wnd->hScrollbar, NULL, rc.right-wnd->vsbWidth, wnd->rebarHeight, wnd->vsbWidth, rc.bottom-wnd->rebarHeight, SWP_NOZORDER); + + // Keep the first rebar band width to a reasonable value + SendMessage(wnd->hRebar, RB_SETBANDWIDTH, 0, 60); + + GetClientRect(hWnd, &rc); + wndHeight = rc.bottom - wnd->rebarHeight; + wnd->maxlines = wndHeight / wnd->lineheight; + + if (wnd->maxlines < wnd->numlines) + { + BOOL oldenable = IsWindowEnabled(wnd->hScrollbar); + if (!oldenable) + { + EnableWindow(wnd->hScrollbar, TRUE); + SendMessage(wnd->hScrollbar, SBM_SETPOS, 0, 0); + } + SendMessage(wnd->hScrollbar, SBM_SETRANGE, 0, (wnd->numlines * wnd->lineheight) - wndHeight); + } + else + EnableWindow(wnd->hScrollbar, FALSE); + + wnd->Refresh(); + } + return 0; + + case WM_PAINT: + IORegView_Paint(wnd, hWnd, wParam, lParam); + return 0; + + case WM_VSCROLL: + { + int pos = SendMessage(wnd->hScrollbar, SBM_GETPOS, 0, 0); + int minpos, maxpos; + + SendMessage(wnd->hScrollbar, SBM_GETRANGE, (WPARAM)&minpos, (LPARAM)&maxpos); + + switch(LOWORD(wParam)) + { + case SB_LINEUP: + pos = max(minpos, pos - 1); + break; + case SB_LINEDOWN: + pos = min(maxpos, pos + 1); + break; + case SB_PAGEUP: + pos = max(minpos, pos - wnd->lineheight); + break; + case SB_PAGEDOWN: + pos = min(maxpos, pos + wnd->lineheight); + break; + case SB_THUMBTRACK: + case SB_THUMBPOSITION: + { + SCROLLINFO si; + + ZeroMemory(&si, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_TRACKPOS; + + SendMessage(wnd->hScrollbar, SBM_GETSCROLLINFO, 0, (LPARAM)&si); + pos = si.nTrackPos; + } + break; + } + + SendMessage(wnd->hScrollbar, SBM_SETPOS, pos, TRUE); + wnd->yoff = -pos; + wnd->Refresh(); + } + return 0; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_CPU: + switch (HIWORD(wParam)) + { + case CBN_SELCHANGE: + case CBN_CLOSEUP: + { + int cpu = SendMessage(wnd->hCPUCombo, CB_GETCURSEL, 0, 0); + if (cpu != wnd->CPU) + { + wnd->ChangeCPU(cpu); + wnd->Refresh(); + } + } + break; + } + break; + + case IDC_IOREG: + switch (HIWORD(wParam)) + { + case CBN_SELCHANGE: + case CBN_CLOSEUP: + { + int reg = SendMessage(wnd->hRegCombo, CB_GETCURSEL, 0, 0); + if (reg != wnd->Reg) + { + wnd->ChangeReg(reg); + wnd->Refresh(); + } + } + break; + } + break; + } + return 0; + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +/*--------------------------------------------------------------------------*/ diff --git a/desmume/src/windows/IORegView.h b/desmume/src/windows/IORegView.h index f5431ea78..62d4cab68 100644 --- a/desmume/src/windows/IORegView.h +++ b/desmume/src/windows/IORegView.h @@ -21,8 +21,38 @@ #ifndef IO_REG_H #define IO_REG_H + #include "../common.h" -extern BOOL CALLBACK IoregView_Proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK IORegView_Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +class CIORegView : public CToolWindow +{ +public: + CIORegView(); + ~CIORegView(); + + void ChangeCPU(int cpu); + void ChangeReg(int reg); + + int CPU; + int Reg; + + HFONT hFont; + + int rebarHeight; + int vsbWidth; + + HWND hScrollbar; + HWND hRebar; + HWND hCPUCombo; + HWND hRegCombo; + + int lineheight; + int numlines; + int maxlines; + + int yoff; +}; #endif diff --git a/desmume/src/windows/main.cpp b/desmume/src/windows/main.cpp index 02127d246..403423157 100644 --- a/desmume/src/windows/main.cpp +++ b/desmume/src/windows/main.cpp @@ -228,9 +228,6 @@ extern char Recent_Scripts[MAX_RECENT_SCRIPTS][1024]; //=========================== view tools TOOLSCLASS *ViewDisasm_ARM7 = NULL; TOOLSCLASS *ViewDisasm_ARM9 = NULL; -//TOOLSCLASS *ViewMem_ARM7 = NULL; -//TOOLSCLASS *ViewMem_ARM9 = NULL; -TOOLSCLASS *ViewRegisters = NULL; TOOLSCLASS *ViewPalette = NULL; TOOLSCLASS *ViewTiles = NULL; TOOLSCLASS *ViewMaps = NULL; @@ -2029,9 +2026,6 @@ int _main() ViewDisasm_ARM7 = new TOOLSCLASS(hAppInst, IDD_DESASSEMBLEUR_VIEWER7, (DLGPROC) ViewDisasm_ARM7Proc); ViewDisasm_ARM9 = new TOOLSCLASS(hAppInst, IDD_DESASSEMBLEUR_VIEWER9, (DLGPROC) ViewDisasm_ARM9Proc); - //ViewMem_ARM7 = new TOOLSCLASS(hAppInst, IDD_MEM_VIEWER7, (DLGPROC) ViewMem_ARM7Proc); - //ViewMem_ARM9 = new TOOLSCLASS(hAppInst, IDD_MEM_VIEWER9, (DLGPROC) ViewMem_ARM9Proc); - ViewRegisters = new TOOLSCLASS(hAppInst, IDD_IO_REG, (DLGPROC) IoregView_Proc); ViewPalette = new TOOLSCLASS(hAppInst, IDD_PAL, (DLGPROC) ViewPalProc); ViewTiles = new TOOLSCLASS(hAppInst, IDD_TILE, (DLGPROC) ViewTilesProc); ViewMaps = new TOOLSCLASS(hAppInst, IDD_MAP, (DLGPROC) ViewMapsProc); @@ -2266,9 +2260,6 @@ int _main() if (ViewMaps!=NULL) delete ViewMaps; if (ViewTiles!=NULL) delete ViewTiles; if (ViewPalette!=NULL) delete ViewPalette; - if (ViewRegisters!=NULL) delete ViewRegisters; -// if (ViewMem_ARM9!=NULL) delete ViewMem_ARM9; -// if (ViewMem_ARM7!=NULL) delete ViewMem_ARM7; if (ViewDisasm_ARM9!=NULL) delete ViewDisasm_ARM9; if (ViewDisasm_ARM7!=NULL) delete ViewDisasm_ARM7; @@ -3860,11 +3851,11 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM } return 0; case IDM_IOREG: - ViewRegisters->open(); - //if (!RegWndClass("DeSmuME_IORegView", IORegView_Proc, CS_DBLCLKS, sizeof(CIORegView*))) - // return 0; + //ViewRegisters->open(); + if (!RegWndClass("DeSmuME_IORegView", IORegView_Proc, CS_DBLCLKS, LoadIcon(hAppInst, "ICONDESMUME"), sizeof(CIORegView*))) + return 0; - //OpenToolWindow(new CIORegView()); + OpenToolWindow(new CIORegView()); return 0; case IDM_MEMORY: //if(!MemView_IsOpened(ARMCPU_ARM9)) MemView_DlgOpen(HWND_DESKTOP, "ARM9 memory", ARMCPU_ARM9);