9fb7be9e3d
Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
3997 lines
109 KiB
C
3997 lines
109 KiB
C
/*
|
|
* debugger.c
|
|
*
|
|
* This file is part of Emu48
|
|
*
|
|
* Copyright (C) 1999 Christoph Gießelink
|
|
*
|
|
*/
|
|
#include "pch.h"
|
|
#include "resource.h"
|
|
#include "Emu48.h"
|
|
#include "Opcodes.h"
|
|
#include "ops.h"
|
|
#include "color.h"
|
|
#include "disrpl.h"
|
|
#include "debugger.h"
|
|
|
|
#define MAXCODELINES 15 // number of lines in code window
|
|
#define MAXMEMLINES 6 // number of lines in memory window
|
|
#define MAXMEMITEMS 16 // number of address items in a memory window line
|
|
#define MAXBREAKPOINTS 256 // max. number of breakpoints
|
|
|
|
#define REG_START IDC_REG_A // first register in register update table
|
|
#define REG_STOP IDC_MISC_BS // last register in register update table
|
|
#define REG_SIZE (REG_STOP-REG_START+1) // size of register update table
|
|
|
|
// assert for register update
|
|
#define _ASSERTREG(r) _ASSERT(r >= REG_START && r <= REG_STOP)
|
|
|
|
#define WM_UPDATE (WM_USER+0x1000) // update debugger dialog box
|
|
|
|
#define MEMWNDMAX (sizeof(nCol) / sizeof(nCol[0]))
|
|
|
|
#define RT_TOOLBAR MAKEINTRESOURCE(241) // MFC toolbar resource type
|
|
|
|
#define CODELABEL 0x80000000 // label in code window
|
|
|
|
// trace log file modes
|
|
enum TRACE_MODE { TRACE_FILE_NEW = 0, TRACE_FILE_APPEND };
|
|
|
|
typedef struct CToolBarData
|
|
{
|
|
WORD wVersion;
|
|
WORD wWidth;
|
|
WORD wHeight;
|
|
WORD wItemCount;
|
|
WORD aItems[1];
|
|
} CToolBarData;
|
|
|
|
typedef struct // type of breakpoint table
|
|
{
|
|
BOOL bEnable; // breakpoint enabled
|
|
UINT nType; // breakpoint type
|
|
DWORD dwAddr; // breakpoint address
|
|
} BP_T;
|
|
|
|
static CONST int nCol[] =
|
|
{
|
|
IDC_DEBUG_MEM_COL0, IDC_DEBUG_MEM_COL1, IDC_DEBUG_MEM_COL2, IDC_DEBUG_MEM_COL3,
|
|
IDC_DEBUG_MEM_COL4, IDC_DEBUG_MEM_COL5, IDC_DEBUG_MEM_COL6, IDC_DEBUG_MEM_COL7
|
|
};
|
|
|
|
static CONST TCHAR cHex[] = { _T('0'),_T('1'),_T('2'),_T('3'),
|
|
_T('4'),_T('5'),_T('6'),_T('7'),
|
|
_T('8'),_T('9'),_T('A'),_T('B'),
|
|
_T('C'),_T('D'),_T('E'),_T('F') };
|
|
|
|
static INT nDbgPosX = 0; // position of debugger window
|
|
static INT nDbgPosY = 0;
|
|
|
|
static WORD wBreakpointCount = 0; // number of breakpoints
|
|
static BP_T sBreakpoint[MAXBREAKPOINTS]; // breakpoint table
|
|
|
|
static WORD wBackupBreakpointCount = 0; // number of breakpoints
|
|
static BP_T sBackupBreakpoint[MAXBREAKPOINTS]; // breakpoint table
|
|
|
|
static INT nRplBreak; // RPL breakpoint
|
|
|
|
static DWORD dwAdrLine[MAXCODELINES]; // addresses of disassember lines in code window
|
|
static DWORD dwAdrMem = 0; // start address of memory window
|
|
|
|
static UINT uIDFol = ID_DEBUG_MEM_FNONE; // follow mode
|
|
static DWORD dwAdrMemFol = 0; // follow address memory window
|
|
|
|
static UINT uIDMap = ID_DEBUG_MEM_MAP; // current memory view mode
|
|
|
|
static BOOL bDbgTrace = FALSE; // enable trace output
|
|
static HANDLE hLogFile = NULL; // log file handle
|
|
static TCHAR szTraceFilename[MAX_PATH] = _T("trace.log"); // filename for trace file
|
|
static UINT uTraceMode = TRACE_FILE_NEW; // trace log file mode
|
|
static BOOL bTraceReg = TRUE; // enable register logging
|
|
static BOOL bTraceMmu = FALSE; // disable MMU logging
|
|
static BOOL bTraceOpc = TRUE; // enable opcode logging
|
|
|
|
static LONG lCharWidth; // width of a character (is a fix font)
|
|
|
|
static HMENU hMenuCode,hMenuMem,hMenuStack;// handle of context menues
|
|
static HWND hWndToolbar; // toolbar handle
|
|
|
|
static DWORD dwDbgRefCycles; // cpu cycles counter from last opcode
|
|
|
|
static CHIPSET OldChipset; // old chipset content
|
|
static BOOL bRegUpdate[REG_SIZE]; // register update table
|
|
|
|
static HBITMAP hBmpCheckBox; // checked and unchecked bitmap
|
|
static HFONT hFontBold; // bold font for symbol labels in code window
|
|
|
|
// function prototypes
|
|
static BOOL OnMemFind(HWND hDlg);
|
|
static BOOL OnProfile(HWND hDlg);
|
|
static VOID UpdateRplObjViewWnd(HWND hDlg, DWORD dwAddr);
|
|
static BOOL OnRplObjView(HWND hDlg);
|
|
static BOOL OnSettings(HWND hDlg);
|
|
static INT_PTR OnNewValue(LPTSTR lpszValue);
|
|
static VOID OnEnterAddress(HWND hDlg, DWORD *dwValue);
|
|
static BOOL OnEditBreakpoint(HWND hDlg);
|
|
static BOOL OnInfoIntr(HWND hDlg);
|
|
static BOOL OnInfoWoRegister(HWND hDlg);
|
|
static VOID UpdateProfileWnd(HWND hDlg);
|
|
static BOOL OnMemLoadData(HWND hDlg);
|
|
static BOOL OnMemSaveData(HWND hDlg);
|
|
static VOID StartTrace(VOID);
|
|
static VOID StopTrace(VOID);
|
|
static VOID FlushTrace(VOID);
|
|
static VOID OutTrace(VOID);
|
|
static BOOL OnTraceSettings(HWND hDlg);
|
|
static BOOL OnTraceEnable(HWND hDlg);
|
|
|
|
//################
|
|
//#
|
|
//# Low level subroutines
|
|
//#
|
|
//################
|
|
|
|
//
|
|
// load external rpl symbol table
|
|
//
|
|
static BOOL LoadSymbTable(VOID)
|
|
{
|
|
TCHAR szSymbFilename[MAX_PATH];
|
|
TCHAR szItemname[16];
|
|
|
|
wsprintf(szItemname,_T("Symb%c"),(TCHAR) cCurrentRomType);
|
|
ReadSettingsString(_T("Disassembler"),szItemname,_T(""),szSymbFilename,ARRAYSIZEOF(szSymbFilename));
|
|
|
|
if (*szSymbFilename == 0) // no reference table defined
|
|
return FALSE; // no success
|
|
|
|
return RplLoadTable(szSymbFilename); // load external reference table
|
|
}
|
|
|
|
//
|
|
// disable menu keys
|
|
//
|
|
static VOID DisableMenuKeys(HWND hDlg)
|
|
{
|
|
HMENU hMenu = GetMenu(hDlg);
|
|
|
|
EnableMenuItem(hMenu,ID_DEBUG_RUN,MF_GRAYED);
|
|
EnableMenuItem(hMenu,ID_DEBUG_RUNCURSOR,MF_GRAYED);
|
|
EnableMenuItem(hMenu,ID_DEBUG_STEP,MF_GRAYED);
|
|
EnableMenuItem(hMenu,ID_DEBUG_STEPOVER,MF_GRAYED);
|
|
EnableMenuItem(hMenu,ID_DEBUG_STEPOUT,MF_GRAYED);
|
|
EnableMenuItem(hMenu,ID_INFO_LASTINSTRUCTIONS,MF_GRAYED);
|
|
EnableMenuItem(hMenu,ID_INFO_WRITEONLYREG,MF_GRAYED);
|
|
|
|
SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_RUN,MAKELONG((FALSE),0));
|
|
SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_BREAK,MAKELONG((TRUE),0));
|
|
SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_RUNCURSOR,MAKELONG((FALSE),0));
|
|
SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEP,MAKELONG((FALSE),0));
|
|
SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEPOVER,MAKELONG((FALSE),0));
|
|
SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEPOUT,MAKELONG((FALSE),0));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// read edit control and decode content as hex number or if enabled as symbol name
|
|
//
|
|
static BOOL GetAddr(HWND hDlg,INT nID,DWORD *pdwAddr,DWORD dwMaxAddr,BOOL bSymbEnable)
|
|
{
|
|
TCHAR szBuffer[48];
|
|
INT i;
|
|
BOOL bSucc = TRUE;
|
|
|
|
HWND hWnd = GetDlgItem(hDlg,nID);
|
|
|
|
GetWindowText(hWnd,szBuffer,ARRAYSIZEOF(szBuffer));
|
|
|
|
if (*szBuffer != 0)
|
|
{
|
|
// if address is not a symbol name decode number
|
|
if ( !bSymbEnable || szBuffer[0] != _T('=')
|
|
|| RplGetAddr(&szBuffer[1],pdwAddr))
|
|
{
|
|
// test if valid hex address
|
|
for (i = 0; bSucc && i < (LONG) lstrlen(szBuffer); ++i)
|
|
{
|
|
bSucc = (_istxdigit(szBuffer[i]) != 0);
|
|
}
|
|
|
|
if (bSucc) // valid characters
|
|
{
|
|
// convert string to number
|
|
*pdwAddr = _tcstoul(szBuffer,NULL,16);
|
|
}
|
|
}
|
|
|
|
// inside address range?
|
|
bSucc = bSucc && (*pdwAddr <= dwMaxAddr);
|
|
|
|
if (!bSucc) // invalid address
|
|
{
|
|
SendMessage(hWnd,EM_SETSEL,0,-1);
|
|
SetFocus(hWnd); // focus to edit control
|
|
}
|
|
}
|
|
return bSucc;
|
|
}
|
|
|
|
//
|
|
// set mapping menu
|
|
//
|
|
static VOID SetMappingMenu(HWND hDlg,UINT uID)
|
|
{
|
|
enum MEM_MAPPING eMode;
|
|
LPTSTR szCaption;
|
|
|
|
UINT uEnable = MF_GRAYED; // disable Memory Data menu items
|
|
|
|
CheckMenuItem(hMenuMem,uIDMap,MF_UNCHECKED);
|
|
|
|
switch (uID)
|
|
{
|
|
case ID_DEBUG_MEM_MAP:
|
|
szCaption = _T("Memory");
|
|
eMode = MEM_MMU;
|
|
uEnable = MF_ENABLED; // enable Memory Data menu items
|
|
break;
|
|
case ID_DEBUG_MEM_NCE1:
|
|
szCaption = _T("Memory (NCE1)");
|
|
eMode = MEM_NCE1;
|
|
break;
|
|
case ID_DEBUG_MEM_NCE2:
|
|
szCaption = _T("Memory (NCE2)");
|
|
eMode = MEM_NCE2;
|
|
break;
|
|
case ID_DEBUG_MEM_CE1:
|
|
szCaption = _T("Memory (CE1)");
|
|
eMode = MEM_CE1;
|
|
break;
|
|
case ID_DEBUG_MEM_CE2:
|
|
szCaption = _T("Memory (CE2)");
|
|
eMode = MEM_CE2;
|
|
break;
|
|
case ID_DEBUG_MEM_NCE3:
|
|
szCaption = _T("Memory (NCE3)");
|
|
eMode = MEM_NCE3;
|
|
break;
|
|
default: _ASSERT(0);
|
|
}
|
|
|
|
VERIFY(SetMemMapType(eMode));
|
|
|
|
if (uIDMap != uID) dwAdrMem = 0; // view from address 0
|
|
|
|
uIDMap = uID;
|
|
CheckMenuItem(hMenuMem,uIDMap,MF_CHECKED);
|
|
|
|
EnableMenuItem(hMenuMem,ID_DEBUG_MEM_LOAD,uEnable);
|
|
EnableMenuItem(hMenuMem,ID_DEBUG_MEM_SAVE,uEnable);
|
|
|
|
SetDlgItemText(hDlg,IDC_STATIC_MEMORY,szCaption);
|
|
return;
|
|
};
|
|
|
|
//
|
|
// get address of cursor in memory window
|
|
//
|
|
static DWORD GetMemCurAddr(HWND hDlg)
|
|
{
|
|
INT i,nPos;
|
|
DWORD dwAddr = dwAdrMem;
|
|
DWORD dwMapDataMask = GetMemDataMask();
|
|
|
|
for (i = 0; i < MEMWNDMAX; ++i) // scan all memory cols
|
|
{
|
|
// column has cursor
|
|
if ((nPos = (INT) SendDlgItemMessage(hDlg,nCol[i],LB_GETCURSEL,0,0)) != LB_ERR)
|
|
{
|
|
dwAddr += (DWORD) (nPos * MEMWNDMAX + i) * 2;
|
|
dwAddr &= dwMapDataMask;
|
|
break;
|
|
}
|
|
}
|
|
return dwAddr;
|
|
}
|
|
|
|
//
|
|
// set/reset breakpoint
|
|
//
|
|
static __inline VOID ToggleBreakpoint(DWORD dwAddr)
|
|
{
|
|
INT i;
|
|
|
|
for (i = 0; i < wBreakpointCount; ++i) // scan all breakpoints
|
|
{
|
|
// code breakpoint found
|
|
if (sBreakpoint[i].nType == BP_EXEC && sBreakpoint[i].dwAddr == dwAddr)
|
|
{
|
|
if (!sBreakpoint[i].bEnable) // breakpoint disabled
|
|
{
|
|
sBreakpoint[i].bEnable = TRUE;
|
|
return;
|
|
}
|
|
|
|
while (++i < wBreakpointCount) // purge breakpoint
|
|
sBreakpoint[i-1] = sBreakpoint[i];
|
|
--wBreakpointCount;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// breakpoint not found
|
|
if (wBreakpointCount >= MAXBREAKPOINTS) // breakpoint buffer full
|
|
{
|
|
AbortMessage(_T("Reached maximum number of breakpoints !"));
|
|
return;
|
|
}
|
|
|
|
sBreakpoint[wBreakpointCount].bEnable = TRUE;
|
|
sBreakpoint[wBreakpointCount].nType = BP_EXEC;
|
|
sBreakpoint[wBreakpointCount].dwAddr = dwAddr;
|
|
++wBreakpointCount;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// init memory mapping table and mapping menu entry
|
|
//
|
|
static __inline VOID InitMemMap(HWND hDlg)
|
|
{
|
|
BOOL bActive;
|
|
|
|
SetMemRomType(cCurrentRomType); // set current model
|
|
|
|
_ASSERT(hMenuMem);
|
|
|
|
// enable menu mappings
|
|
EnableMenuItem(hMenuMem,ID_DEBUG_MEM_NCE1,GetMemAvail(MEM_NCE1) ? MF_ENABLED : MF_GRAYED);
|
|
EnableMenuItem(hMenuMem,ID_DEBUG_MEM_NCE2,GetMemAvail(MEM_NCE2) ? MF_ENABLED : MF_GRAYED);
|
|
EnableMenuItem(hMenuMem,ID_DEBUG_MEM_CE1, GetMemAvail(MEM_CE1) ? MF_ENABLED : MF_GRAYED);
|
|
EnableMenuItem(hMenuMem,ID_DEBUG_MEM_CE2, GetMemAvail(MEM_CE2) ? MF_ENABLED : MF_GRAYED);
|
|
EnableMenuItem(hMenuMem,ID_DEBUG_MEM_NCE3,GetMemAvail(MEM_NCE3) ? MF_ENABLED : MF_GRAYED);
|
|
|
|
bActive = (ID_DEBUG_MEM_NCE1 == uIDMap && GetMemAvail(MEM_NCE1))
|
|
|| (ID_DEBUG_MEM_NCE2 == uIDMap && GetMemAvail(MEM_NCE2))
|
|
|| (ID_DEBUG_MEM_CE1 == uIDMap && GetMemAvail(MEM_CE1))
|
|
|| (ID_DEBUG_MEM_CE2 == uIDMap && GetMemAvail(MEM_CE2))
|
|
|| (ID_DEBUG_MEM_NCE3 == uIDMap && GetMemAvail(MEM_NCE3));
|
|
|
|
SetMappingMenu(hDlg,bActive ? uIDMap : ID_DEBUG_MEM_MAP);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// init bank switcher area
|
|
//
|
|
static __inline VOID InitBsArea(HWND hDlg)
|
|
{
|
|
// not 38 / 48S // CdB for HP: add apples type
|
|
if (cCurrentRomType!='A' && cCurrentRomType!='S')
|
|
{
|
|
EnableWindow(GetDlgItem(hDlg,IDC_MISC_BS_TXT),TRUE);
|
|
EnableWindow(GetDlgItem(hDlg,IDC_MISC_BS),TRUE);
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// convert nibble register to string
|
|
//
|
|
static LPTSTR RegToStr(BYTE *pReg, WORD wNib)
|
|
{
|
|
static TCHAR szBuffer[32];
|
|
|
|
WORD i;
|
|
|
|
for (i = 0;i < wNib;++i)
|
|
szBuffer[i] = cHex[pReg[wNib-i-1]];
|
|
szBuffer[i] = 0;
|
|
|
|
return szBuffer;
|
|
}
|
|
|
|
//
|
|
// convert string to nibble register
|
|
//
|
|
static VOID StrToReg(BYTE *pReg, WORD wNib, LPTSTR lpszValue)
|
|
{
|
|
int i,nValuelen;
|
|
|
|
nValuelen = lstrlen(lpszValue);
|
|
for (i = wNib - 1;i >= 0;--i)
|
|
{
|
|
if (i >= nValuelen) // no character in string
|
|
{
|
|
pReg[i] = 0; // fill with zero
|
|
}
|
|
else
|
|
{
|
|
// convert to number
|
|
pReg[i] = _totupper(*lpszValue) - _T('0');
|
|
if (pReg[i] > 9) pReg[i] -= _T('A') - _T('9') - 1;
|
|
++lpszValue;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// write code window
|
|
//
|
|
static INT ViewCodeWnd(HWND hWnd, DWORD dwAddress)
|
|
{
|
|
enum MEM_MAPPING eMapMode;
|
|
LPCTSTR lpszName;
|
|
TCHAR szAddress[64];
|
|
DWORD dwNxtAddr;
|
|
INT i,j,nLinePC;
|
|
|
|
nLinePC = -1; // PC not shown (no selection)
|
|
|
|
eMapMode = GetMemMapType(); // get current map mode
|
|
SetMemMapType(MEM_MMU); // disassemble in mapped mode
|
|
|
|
dwAddress &= 0xFFFFF; // adjust to Saturn address range
|
|
SendMessage(hWnd,WM_SETREDRAW,FALSE,0);
|
|
SendMessage(hWnd,LB_RESETCONTENT,0,0);
|
|
for (i = 0; i < MAXCODELINES; ++i)
|
|
{
|
|
// entry has a name
|
|
if (disassembler_symb && (lpszName = RplGetName(dwAddress)) != NULL)
|
|
{
|
|
// save address as label
|
|
dwAdrLine[i] = dwAddress | CODELABEL;
|
|
|
|
szAddress[0] = _T('=');
|
|
lstrcpyn(&szAddress[1],lpszName,ARRAYSIZEOF(szAddress)-1);
|
|
SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szAddress);
|
|
if (++i == MAXCODELINES) break;
|
|
}
|
|
|
|
// remember line of PC
|
|
if (dwAddress == Chipset.pc) nLinePC = i;
|
|
|
|
dwAdrLine[i] = dwAddress;
|
|
j = wsprintf(szAddress,
|
|
(dwAddress == Chipset.pc) ? _T("%05lX-%c ") : _T("%05lX "),
|
|
dwAddress,nRplBreak ? _T('R') : _T('>'));
|
|
|
|
dwNxtAddr = (dwAddress + 5) & 0xFFFFF;
|
|
|
|
// check if address content is a PCO (Primitive Code Object)
|
|
// make sure when the PC points to such an address that it's
|
|
// interpreted as opcode
|
|
if ((dwAddress != Chipset.pc) && (Read5(dwAddress) == dwNxtAddr))
|
|
{
|
|
if (disassembler_mode == HP_MNEMONICS)
|
|
{
|
|
_tcscat(&szAddress[j],_T("CON(5) (*)+5"));
|
|
}
|
|
else
|
|
{
|
|
wsprintf(&szAddress[j],_T("dcr.5 $%05x"),dwNxtAddr);
|
|
}
|
|
dwAddress = dwNxtAddr;
|
|
}
|
|
else
|
|
{
|
|
dwAddress = disassemble(dwAddress,&szAddress[j]);
|
|
}
|
|
SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szAddress);
|
|
}
|
|
SendMessage(hWnd,WM_SETREDRAW,TRUE,0);
|
|
SetMemMapType(eMapMode); // switch back to old map mode
|
|
return nLinePC;
|
|
}
|
|
|
|
//
|
|
// write memory window
|
|
//
|
|
static VOID ViewMemWnd(HWND hDlg, DWORD dwAddress)
|
|
{
|
|
#define TEXTOFF 32
|
|
|
|
INT i,j;
|
|
TCHAR szBuffer[16],szItem[4];
|
|
DWORD dwMapDataMask;
|
|
BYTE cChar;
|
|
|
|
szItem[2] = 0; // end of string
|
|
dwAdrMem = dwAddress; // save start address of memory window
|
|
dwMapDataMask = GetMemDataMask(); // size mask of data mapping
|
|
|
|
// purge all list boxes
|
|
SendDlgItemMessage(hDlg,IDC_DEBUG_MEM_ADDR,LB_RESETCONTENT,0,0);
|
|
SendDlgItemMessage(hDlg,IDC_DEBUG_MEM_TEXT,LB_RESETCONTENT,0,0);
|
|
for (j = 0; j < MEMWNDMAX; ++j)
|
|
SendDlgItemMessage(hDlg,nCol[j],LB_RESETCONTENT,0,0);
|
|
|
|
for (i = 0; i < MAXMEMLINES; ++i)
|
|
{
|
|
BYTE byLineData[MAXMEMITEMS];
|
|
|
|
if (ID_DEBUG_MEM_MAP == uIDMap) // mapped memory content
|
|
{
|
|
wsprintf(szBuffer,_T("%05lX"),dwAddress);
|
|
}
|
|
else // module memory content
|
|
{
|
|
wsprintf(szBuffer,_T("%06lX"),dwAddress);
|
|
}
|
|
SendDlgItemMessage(hDlg,IDC_DEBUG_MEM_ADDR,LB_ADDSTRING,0,(LPARAM) szBuffer);
|
|
|
|
// fetch data line
|
|
GetMemPeek(byLineData, dwAddress, MAXMEMITEMS);
|
|
|
|
for (j = 0; j < MAXMEMITEMS; ++j)
|
|
{
|
|
// read from fetched data line
|
|
szItem[j&0x1] = cHex[byLineData[j]];
|
|
// characters are saved in LBS, MSB order
|
|
cChar = (cChar >> 4) | (byLineData[j] << 4);
|
|
|
|
if ((j&0x1) != 0)
|
|
{
|
|
// byte field
|
|
_ASSERT(j/2 < MEMWNDMAX);
|
|
SendDlgItemMessage(hDlg,nCol[j/2],LB_ADDSTRING,0,(LPARAM) szItem);
|
|
|
|
// text field
|
|
szBuffer[j/2] = (isprint(cChar) != 0) ? cChar : _T('.');
|
|
}
|
|
}
|
|
szBuffer[j/2] = 0; // end of text string
|
|
SendDlgItemMessage(hDlg,IDC_DEBUG_MEM_TEXT,LB_ADDSTRING,0,(LPARAM) szBuffer);
|
|
|
|
dwAddress = (dwAddress + MAXMEMITEMS) & dwMapDataMask;
|
|
}
|
|
return;
|
|
#undef TEXTOFF
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# High level Window draw routines
|
|
//#
|
|
//################
|
|
|
|
//
|
|
// update code window with scrolling
|
|
//
|
|
static VOID UpdateCodeWnd(HWND hDlg)
|
|
{
|
|
DWORD dwAddress,dwPriorAddr;
|
|
INT i,j;
|
|
|
|
HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE);
|
|
|
|
j = (INT) SendMessage(hWnd,LB_GETCOUNT,0,0); // no. of items in table
|
|
|
|
// seach for actual address in code area
|
|
for (i = 0; i < j; ++i)
|
|
{
|
|
if (dwAdrLine[i] == Chipset.pc) // found new pc address line
|
|
break;
|
|
}
|
|
|
|
// redraw code window
|
|
dwAddress = dwAdrLine[0]; // redraw list box with modified pc
|
|
if (i == j) // address not found
|
|
{
|
|
dwAddress = Chipset.pc; // begin with actual pc
|
|
|
|
// check if current pc is the begin of a PCO, show PCO address
|
|
dwPriorAddr = (dwAddress - 5) & 0xFFFFF;
|
|
if (Read5(dwPriorAddr) == dwAddress)
|
|
dwAddress = dwPriorAddr;
|
|
}
|
|
else
|
|
{
|
|
if (i > 10) // cursor near bottom line
|
|
{
|
|
j = 10; // pc to line 11
|
|
|
|
// new address line is label
|
|
if ((dwAdrLine[i-11] & CODELABEL) != 0)
|
|
--j; // pc to line 10
|
|
|
|
dwAddress = dwAdrLine[i-j]; // move that pc is in line 11
|
|
}
|
|
}
|
|
|
|
i = ViewCodeWnd(hWnd,dwAddress); // init code area
|
|
SendMessage(hWnd,LB_SETCURSEL,i,0); // set cursor on actual pc
|
|
return;
|
|
}
|
|
|
|
//
|
|
// update register window
|
|
//
|
|
static VOID UpdateRegisterWnd(HWND hDlg)
|
|
{
|
|
TCHAR szBuffer[64];
|
|
|
|
_ASSERTREG(IDC_REG_A);
|
|
bRegUpdate[IDC_REG_A-REG_START] = memcmp(Chipset.A, OldChipset.A, sizeof(Chipset.A)) != 0;
|
|
wsprintf(szBuffer,_T("A= %s"),RegToStr(Chipset.A,16));
|
|
SetDlgItemText(hDlg,IDC_REG_A,szBuffer);
|
|
_ASSERTREG(IDC_REG_B);
|
|
bRegUpdate[IDC_REG_B-REG_START] = memcmp(Chipset.B, OldChipset.B, sizeof(Chipset.B)) != 0;
|
|
wsprintf(szBuffer,_T("B= %s"),RegToStr(Chipset.B,16));
|
|
SetDlgItemText(hDlg,IDC_REG_B,szBuffer);
|
|
_ASSERTREG(IDC_REG_C);
|
|
bRegUpdate[IDC_REG_C-REG_START] = memcmp(Chipset.C, OldChipset.C, sizeof(Chipset.C)) != 0;
|
|
wsprintf(szBuffer,_T("C= %s"),RegToStr(Chipset.C,16));
|
|
SetDlgItemText(hDlg,IDC_REG_C,szBuffer);
|
|
_ASSERTREG(IDC_REG_D);
|
|
bRegUpdate[IDC_REG_D-REG_START] = memcmp(Chipset.D, OldChipset.D, sizeof(Chipset.D)) != 0;
|
|
wsprintf(szBuffer,_T("D= %s"),RegToStr(Chipset.D,16));
|
|
SetDlgItemText(hDlg,IDC_REG_D,szBuffer);
|
|
_ASSERTREG(IDC_REG_R0);
|
|
bRegUpdate[IDC_REG_R0-REG_START] = memcmp(Chipset.R0, OldChipset.R0, sizeof(Chipset.R0)) != 0;
|
|
wsprintf(szBuffer,_T("R0=%s"),RegToStr(Chipset.R0,16));
|
|
SetDlgItemText(hDlg,IDC_REG_R0,szBuffer);
|
|
_ASSERTREG(IDC_REG_R1);
|
|
bRegUpdate[IDC_REG_R1-REG_START] = memcmp(Chipset.R1, OldChipset.R1, sizeof(Chipset.R1)) != 0;
|
|
wsprintf(szBuffer,_T("R1=%s"),RegToStr(Chipset.R1,16));
|
|
SetDlgItemText(hDlg,IDC_REG_R1,szBuffer);
|
|
_ASSERTREG(IDC_REG_R2);
|
|
bRegUpdate[IDC_REG_R2-REG_START] = memcmp(Chipset.R2, OldChipset.R2, sizeof(Chipset.R2)) != 0;
|
|
wsprintf(szBuffer,_T("R2=%s"),RegToStr(Chipset.R2,16));
|
|
SetDlgItemText(hDlg,IDC_REG_R2,szBuffer);
|
|
_ASSERTREG(IDC_REG_R3);
|
|
bRegUpdate[IDC_REG_R3-REG_START] = memcmp(Chipset.R3, OldChipset.R3, sizeof(Chipset.R3)) != 0;
|
|
wsprintf(szBuffer,_T("R3=%s"),RegToStr(Chipset.R3,16));
|
|
SetDlgItemText(hDlg,IDC_REG_R3,szBuffer);
|
|
_ASSERTREG(IDC_REG_R4);
|
|
bRegUpdate[IDC_REG_R4-REG_START] = memcmp(Chipset.R4, OldChipset.R4, sizeof(Chipset.R4)) != 0;
|
|
wsprintf(szBuffer,_T("R4=%s"),RegToStr(Chipset.R4,16));
|
|
SetDlgItemText(hDlg,IDC_REG_R4,szBuffer);
|
|
_ASSERTREG(IDC_REG_D0);
|
|
bRegUpdate[IDC_REG_D0-REG_START] = Chipset.d0 != OldChipset.d0;
|
|
wsprintf(szBuffer,_T("D0=%05X"),Chipset.d0);
|
|
SetDlgItemText(hDlg,IDC_REG_D0,szBuffer);
|
|
_ASSERTREG(IDC_REG_D1);
|
|
bRegUpdate[IDC_REG_D1-REG_START] = Chipset.d1 != OldChipset.d1;
|
|
wsprintf(szBuffer,_T("D1=%05X"),Chipset.d1);
|
|
SetDlgItemText(hDlg,IDC_REG_D1,szBuffer);
|
|
_ASSERTREG(IDC_REG_P);
|
|
bRegUpdate[IDC_REG_P-REG_START] = Chipset.P != OldChipset.P;
|
|
wsprintf(szBuffer,_T("P=%X"),Chipset.P);
|
|
SetDlgItemText(hDlg,IDC_REG_P,szBuffer);
|
|
_ASSERTREG(IDC_REG_PC);
|
|
bRegUpdate[IDC_REG_PC-REG_START] = Chipset.pc != OldChipset.pc;
|
|
wsprintf(szBuffer,_T("PC=%05X"),Chipset.pc);
|
|
SetDlgItemText(hDlg,IDC_REG_PC,szBuffer);
|
|
_ASSERTREG(IDC_REG_OUT);
|
|
bRegUpdate[IDC_REG_OUT-REG_START] = Chipset.out != OldChipset.out;
|
|
wsprintf(szBuffer,_T("OUT=%03X"),Chipset.out);
|
|
SetDlgItemText(hDlg,IDC_REG_OUT,szBuffer);
|
|
_ASSERTREG(IDC_REG_IN);
|
|
bRegUpdate[IDC_REG_IN-REG_START] = Chipset.in != OldChipset.in;
|
|
wsprintf(szBuffer,_T("IN=%04X"),Chipset.in);
|
|
SetDlgItemText(hDlg,IDC_REG_IN,szBuffer);
|
|
_ASSERTREG(IDC_REG_ST);
|
|
bRegUpdate[IDC_REG_ST-REG_START] = memcmp(Chipset.ST, OldChipset.ST, sizeof(Chipset.ST)) != 0;
|
|
wsprintf(szBuffer,_T("ST=%s"),RegToStr(Chipset.ST,4));
|
|
SetDlgItemText(hDlg,IDC_REG_ST,szBuffer);
|
|
_ASSERTREG(IDC_REG_CY);
|
|
bRegUpdate[IDC_REG_CY-REG_START] = Chipset.carry != OldChipset.carry;
|
|
wsprintf(szBuffer,_T("CY=%d"),Chipset.carry);
|
|
SetDlgItemText(hDlg,IDC_REG_CY,szBuffer);
|
|
_ASSERTREG(IDC_REG_MODE);
|
|
bRegUpdate[IDC_REG_MODE-REG_START] = Chipset.mode_dec != OldChipset.mode_dec;
|
|
wsprintf(szBuffer,_T("Mode=%c"),Chipset.mode_dec ? _T('D') : _T('H'));
|
|
SetDlgItemText(hDlg,IDC_REG_MODE,szBuffer);
|
|
_ASSERTREG(IDC_REG_MP);
|
|
bRegUpdate[IDC_REG_MP-REG_START] = ((Chipset.HST ^ OldChipset.HST) & MP) != 0;
|
|
wsprintf(szBuffer,_T("MP=%d"),(Chipset.HST & MP) != 0);
|
|
SetDlgItemText(hDlg,IDC_REG_MP,szBuffer);
|
|
_ASSERTREG(IDC_REG_SR);
|
|
bRegUpdate[IDC_REG_SR-REG_START] = ((Chipset.HST ^ OldChipset.HST) & SR) != 0;
|
|
wsprintf(szBuffer,_T("SR=%d"),(Chipset.HST & SR) != 0);
|
|
SetDlgItemText(hDlg,IDC_REG_SR,szBuffer);
|
|
_ASSERTREG(IDC_REG_SB);
|
|
bRegUpdate[IDC_REG_SB-REG_START] = ((Chipset.HST ^ OldChipset.HST) & SB) != 0;
|
|
wsprintf(szBuffer,_T("SB=%d"),(Chipset.HST & SB) != 0);
|
|
SetDlgItemText(hDlg,IDC_REG_SB,szBuffer);
|
|
_ASSERTREG(IDC_REG_XM);
|
|
bRegUpdate[IDC_REG_XM-REG_START] = ((Chipset.HST ^ OldChipset.HST) & XM) != 0;
|
|
wsprintf(szBuffer,_T("XM=%d"),(Chipset.HST & XM) != 0);
|
|
SetDlgItemText(hDlg,IDC_REG_XM,szBuffer);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// update memory window
|
|
//
|
|
static VOID UpdateMemoryWnd(HWND hDlg)
|
|
{
|
|
// check follow mode setting for memory window
|
|
switch(uIDFol)
|
|
{
|
|
case ID_DEBUG_MEM_FNONE: break;
|
|
case ID_DEBUG_MEM_FADDR: dwAdrMem = Read5(dwAdrMemFol); break;
|
|
case ID_DEBUG_MEM_FPC: dwAdrMem = Chipset.pc; break;
|
|
case ID_DEBUG_MEM_FD0: dwAdrMem = Chipset.d0; break;
|
|
case ID_DEBUG_MEM_FD1: dwAdrMem = Chipset.d1; break;
|
|
default: _ASSERT(FALSE);
|
|
}
|
|
|
|
ViewMemWnd(hDlg,dwAdrMem);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// update stack window
|
|
//
|
|
static VOID UpdateStackWnd(HWND hDlg)
|
|
{
|
|
UINT i;
|
|
LONG nPos;
|
|
TCHAR szBuffer[64];
|
|
|
|
HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_STACK);
|
|
|
|
SendMessage(hWnd,WM_SETREDRAW,FALSE,0);
|
|
nPos = (LONG) SendMessage(hWnd,LB_GETTOPINDEX,0,0);
|
|
SendMessage(hWnd,LB_RESETCONTENT,0,0);
|
|
for (i = 1; i <= ARRAYSIZEOF(Chipset.rstk); ++i)
|
|
{
|
|
INT j;
|
|
|
|
wsprintf(szBuffer,_T("%d: %05X"), i, Chipset.rstk[(Chipset.rstkp-i)&7]);
|
|
j = (INT) SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer);
|
|
SendMessage(hWnd,LB_SETITEMDATA,j,Chipset.rstk[(Chipset.rstkp-i)&7]);
|
|
}
|
|
SendMessage(hWnd,LB_SETTOPINDEX,nPos,0);
|
|
SendMessage(hWnd,WM_SETREDRAW,TRUE,0);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// update MMU window
|
|
//
|
|
static VOID UpdateMmuWnd(HWND hDlg)
|
|
{
|
|
TCHAR szBuffer[64];
|
|
|
|
if (Chipset.IOCfig)
|
|
wsprintf(szBuffer,_T("%05X"),Chipset.IOBase);
|
|
else
|
|
lstrcpy(szBuffer,_T("-----"));
|
|
SetDlgItemText(hDlg,IDC_MMU_IO_A,szBuffer);
|
|
if (Chipset.P0Cfig)
|
|
wsprintf(szBuffer,_T("%05X"),Chipset.P0Base<<12);
|
|
else
|
|
lstrcpy(szBuffer,_T("-----"));
|
|
SetDlgItemText(hDlg,IDC_MMU_NCE2_A,szBuffer);
|
|
if (Chipset.P0Cfg2)
|
|
wsprintf(szBuffer,_T("%05X"),(Chipset.P0Size^0xFF)<<12);
|
|
else
|
|
lstrcpy(szBuffer,_T("-----"));
|
|
SetDlgItemText(hDlg,IDC_MMU_NCE2_S,szBuffer);
|
|
if (Chipset.P1Cfig)
|
|
wsprintf(szBuffer,_T("%05X"),Chipset.P1Base<<12);
|
|
else
|
|
lstrcpy(szBuffer,_T("-----"));
|
|
SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_CE1_A : IDC_MMU_CE2_A,szBuffer);
|
|
if (Chipset.P1Cfg2)
|
|
wsprintf(szBuffer,_T("%05X"),(Chipset.P1Size^0xFF)<<12);
|
|
else
|
|
lstrcpy(szBuffer,_T("-----"));
|
|
SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_CE1_S : IDC_MMU_CE2_S,szBuffer);
|
|
if (Chipset.P2Cfig)
|
|
wsprintf(szBuffer,_T("%05X"),Chipset.P2Base<<12);
|
|
else
|
|
lstrcpy(szBuffer,_T("-----"));
|
|
SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_CE2_A : IDC_MMU_NCE3_A,szBuffer);
|
|
if (Chipset.P2Cfg2)
|
|
wsprintf(szBuffer,_T("%05X"),(Chipset.P2Size^0xFF)<<12);
|
|
else
|
|
lstrcpy(szBuffer,_T("-----"));
|
|
SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_CE2_S : IDC_MMU_NCE3_S,szBuffer);
|
|
if (Chipset.BSCfig)
|
|
wsprintf(szBuffer,_T("%05X"),Chipset.BSBase<<12);
|
|
else
|
|
lstrcpy(szBuffer,_T("-----"));
|
|
SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_NCE3_A : IDC_MMU_CE1_A,szBuffer);
|
|
if (Chipset.BSCfg2)
|
|
wsprintf(szBuffer,_T("%05X"),(Chipset.BSSize^0xFF)<<12);
|
|
else
|
|
lstrcpy(szBuffer,_T("-----"));
|
|
SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_NCE3_S : IDC_MMU_CE1_S,szBuffer);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// update miscellaneous window
|
|
//
|
|
static VOID UpdateMiscWnd(HWND hDlg)
|
|
{
|
|
_ASSERTREG(IDC_MISC_INT);
|
|
bRegUpdate[IDC_MISC_INT-REG_START] = Chipset.inte != OldChipset.inte;
|
|
SetDlgItemText(hDlg,IDC_MISC_INT,Chipset.inte ? _T("On ") : _T("Off"));
|
|
|
|
_ASSERTREG(IDC_MISC_KEY);
|
|
bRegUpdate[IDC_MISC_KEY-REG_START] = Chipset.intk != OldChipset.intk;
|
|
SetDlgItemText(hDlg,IDC_MISC_KEY,Chipset.intk ? _T("On ") : _T("Off"));
|
|
|
|
_ASSERTREG(IDC_MISC_BS);
|
|
bRegUpdate[IDC_MISC_BS-REG_START] = FALSE;
|
|
|
|
// not 38/48S // CdB for HP: add Apples type
|
|
if (cCurrentRomType!='A' && cCurrentRomType!='S')
|
|
{
|
|
TCHAR szBuffer[64];
|
|
|
|
bRegUpdate[IDC_MISC_BS-REG_START] = (Chipset.Bank_FF & 0x7F) != (OldChipset.Bank_FF & 0x7F);
|
|
wsprintf(szBuffer,_T("%02X"),Chipset.Bank_FF & 0x7F);
|
|
SetDlgItemText(hDlg,IDC_MISC_BS,szBuffer);
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// update complete debugger dialog
|
|
//
|
|
VOID OnUpdate(HWND hDlg)
|
|
{
|
|
nDbgState = DBG_STEPINTO; // state "step into"
|
|
dwDbgStopPC = -1; // disable "cursor stop address"
|
|
|
|
// enable debug buttons
|
|
EnableMenuItem(GetMenu(hDlg),ID_DEBUG_RUN,MF_ENABLED);
|
|
EnableMenuItem(GetMenu(hDlg),ID_DEBUG_RUNCURSOR,MF_ENABLED);
|
|
EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEP,MF_ENABLED);
|
|
EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEPOVER,MF_ENABLED);
|
|
EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEPOUT,MF_ENABLED);
|
|
EnableMenuItem(GetMenu(hDlg),ID_INFO_LASTINSTRUCTIONS,MF_ENABLED);
|
|
EnableMenuItem(GetMenu(hDlg),ID_INFO_WRITEONLYREG,MF_ENABLED);
|
|
|
|
// enable toolbar buttons
|
|
SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_RUN,MAKELONG((TRUE),0));
|
|
SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_BREAK,MAKELONG((FALSE),0));
|
|
SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_RUNCURSOR,MAKELONG((TRUE),0));
|
|
SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEP,MAKELONG((TRUE),0));
|
|
SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEPOVER,MAKELONG((TRUE),0));
|
|
SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEPOUT,MAKELONG((TRUE),0));
|
|
|
|
// update windows
|
|
UpdateCodeWnd(hDlg); // update code window
|
|
UpdateRegisterWnd(hDlg); // update registers window
|
|
UpdateMemoryWnd(hDlg); // update memory window
|
|
UpdateStackWnd(hDlg); // update stack window
|
|
UpdateMmuWnd(hDlg); // update MMU window
|
|
UpdateMiscWnd(hDlg); // update bank switcher window
|
|
UpdateProfileWnd(hDlgProfile); // update profiler dialog
|
|
ShowWindow(hDlg,SW_RESTORE); // pop up if minimized
|
|
SetFocus(hDlg); // set focus to debugger
|
|
return;
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Virtual key handler
|
|
//#
|
|
//################
|
|
|
|
//
|
|
// toggle breakpoint key handler (F2)
|
|
//
|
|
static BOOL OnKeyF2(HWND hDlg)
|
|
{
|
|
HWND hWnd;
|
|
RECT rc;
|
|
LONG i;
|
|
|
|
hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE);
|
|
i = (LONG) SendMessage(hWnd,LB_GETCURSEL,0,0); // get selected item
|
|
ToggleBreakpoint(dwAdrLine[i]); // toggle breakpoint at address
|
|
// update region of toggled item
|
|
SendMessage(hWnd,LB_GETITEMRECT,i,(LPARAM)&rc);
|
|
InvalidateRect(hWnd,&rc,TRUE);
|
|
return -1; // call windows default handler
|
|
}
|
|
|
|
//
|
|
// run key handler (F5)
|
|
//
|
|
static BOOL OnKeyF5(HWND hDlg)
|
|
{
|
|
HWND hWnd;
|
|
INT i,nPos;
|
|
TCHAR szBuf[64];
|
|
|
|
if (nDbgState != DBG_RUN) // emulation stopped
|
|
{
|
|
DisableMenuKeys(hDlg); // disable menu keys
|
|
|
|
hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE);
|
|
nPos = (INT) SendMessage(hWnd,LB_GETCURSEL,0,0);
|
|
|
|
// clear "->" in code window
|
|
for (i = 0; i < MAXCODELINES; ++i)
|
|
{
|
|
if (dwAdrLine[i] == Chipset.pc) // PC in window
|
|
{
|
|
SendMessage(hWnd,LB_GETTEXT,i,(LPARAM) szBuf);
|
|
szBuf[5] = szBuf[6] = _T(' ');
|
|
SendMessage(hWnd,LB_DELETESTRING,i,0);
|
|
SendMessage(hWnd,LB_INSERTSTRING,i,(LPARAM) szBuf);
|
|
break;
|
|
}
|
|
}
|
|
SendMessage(hWnd,LB_SETCURSEL,nPos,0);
|
|
|
|
nDbgState = DBG_RUN; // state "run"
|
|
OldChipset = Chipset; // save chipset values
|
|
SetEvent(hEventDebug); // run emulation
|
|
}
|
|
return -1; // call windows default handler
|
|
UNREFERENCED_PARAMETER(hDlg);
|
|
}
|
|
|
|
//
|
|
// step cursor key handler (F6)
|
|
//
|
|
static BOOL OnKeyF6(HWND hDlg)
|
|
{
|
|
if (nDbgState != DBG_RUN) // emulation stopped
|
|
{
|
|
// get address of selected item
|
|
INT nPos = (INT) SendDlgItemMessage(hDlg,IDC_DEBUG_CODE,LB_GETCURSEL,0,0);
|
|
dwDbgStopPC = dwAdrLine[nPos];
|
|
|
|
OnKeyF5(hDlg); // run emulation
|
|
}
|
|
return -1; // call windows default handler
|
|
}
|
|
|
|
//
|
|
// step into key handler (F7)
|
|
//
|
|
static BOOL OnKeyF7(HWND hDlg)
|
|
{
|
|
if (nDbgState != DBG_RUN) // emulation stopped
|
|
{
|
|
if (bDbgSkipInt) // skip code in interrupt handler
|
|
DisableMenuKeys(hDlg); // disable menu keys
|
|
|
|
nDbgState = DBG_STEPINTO; // state "step into"
|
|
OldChipset = Chipset; // save chipset values
|
|
SetEvent(hEventDebug); // run emulation
|
|
}
|
|
return -1; // call windows default handler
|
|
UNREFERENCED_PARAMETER(hDlg);
|
|
}
|
|
|
|
//
|
|
// step over key handler (F8)
|
|
//
|
|
static BOOL OnKeyF8(HWND hDlg)
|
|
{
|
|
if (nDbgState != DBG_RUN) // emulation stopped
|
|
{
|
|
LPBYTE I = FASTPTR(Chipset.pc);
|
|
|
|
if (bDbgSkipInt) // skip code in interrupt handler
|
|
DisableMenuKeys(hDlg); // disable menu keys
|
|
|
|
dwDbgRstkp = Chipset.rstkp; // save stack level
|
|
|
|
// GOSUB 7aaa, GOSUBL 8Eaaaa, GOSBVL 8Faaaaa
|
|
if (I[0] == 0x7 || (I[0] == 0x8 && (I[1] == 0xE || I[1] == 0xF)))
|
|
{
|
|
nDbgState = DBG_STEPOVER; // state "step over"
|
|
}
|
|
else
|
|
{
|
|
nDbgState = DBG_STEPINTO; // state "step into"
|
|
}
|
|
OldChipset = Chipset; // save chipset values
|
|
SetEvent(hEventDebug); // run emulation
|
|
}
|
|
return -1; // call windows default handler
|
|
UNREFERENCED_PARAMETER(hDlg);
|
|
}
|
|
|
|
//
|
|
// step out key handler (F9)
|
|
//
|
|
static BOOL OnKeyF9(HWND hDlg)
|
|
{
|
|
if (nDbgState != DBG_RUN) // emulation stopped
|
|
{
|
|
DisableMenuKeys(hDlg); // disable menu keys
|
|
dwDbgRstkp = (Chipset.rstkp-1)&7; // save stack data
|
|
dwDbgRstk = Chipset.rstk[dwDbgRstkp];
|
|
nDbgState = DBG_STEPOUT; // state "step out"
|
|
OldChipset = Chipset; // save chipset values
|
|
SetEvent(hEventDebug); // run emulation
|
|
}
|
|
return -1; // call windows default handler
|
|
UNREFERENCED_PARAMETER(hDlg);
|
|
}
|
|
|
|
//
|
|
// break key handler (F11)
|
|
//
|
|
static BOOL OnKeyF11(HWND hDlg)
|
|
{
|
|
nDbgState = DBG_STEPINTO; // state "step into"
|
|
if (Chipset.Shutdn) // cpu thread stopped
|
|
SetEvent(hEventShutdn); // goto debug session
|
|
return -1; // call windows default handler
|
|
UNREFERENCED_PARAMETER(hDlg);
|
|
}
|
|
|
|
//
|
|
// view of given address in disassembler window
|
|
//
|
|
static BOOL OnCodeGoAdr(HWND hDlg)
|
|
{
|
|
DWORD dwAddress = -1; // no address given
|
|
|
|
OnEnterAddress(hDlg, &dwAddress);
|
|
if (dwAddress != -1)
|
|
{
|
|
HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE);
|
|
ViewCodeWnd(hWnd,dwAddress);
|
|
SendMessage(hWnd,LB_SETCURSEL,0,0);
|
|
}
|
|
return -1; // call windows default handler
|
|
}
|
|
|
|
//
|
|
// view pc in disassembler window
|
|
//
|
|
static BOOL OnCodeGoPC(HWND hDlg)
|
|
{
|
|
UpdateCodeWnd(hDlg);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// set pc to selection
|
|
//
|
|
static BOOL OnCodeSetPcToSelection(HWND hDlg)
|
|
{
|
|
Chipset.pc = dwAdrLine[SendDlgItemMessage(hDlg,IDC_DEBUG_CODE,LB_GETCURSEL,0,0)];
|
|
return OnCodeGoPC(hDlg);
|
|
}
|
|
|
|
//
|
|
// find PCO object in code window
|
|
//
|
|
static BOOL OnCodeFindPCO(HWND hDlg,DWORD dwAddr,INT nSearchDir)
|
|
{
|
|
DWORD dwCnt;
|
|
BOOL bMatch;
|
|
|
|
// searching upwards / downwards
|
|
_ASSERT(nSearchDir == 1 || nSearchDir == -1);
|
|
|
|
dwAddr += nSearchDir; // start address for search
|
|
|
|
// scan mapped address area until PCO found
|
|
for (dwCnt = 0; dwCnt <= 0xFFFFF; ++dwCnt)
|
|
{
|
|
// is this a PCO?
|
|
bMatch = (Read5(dwAddr & 0xFFFFF) == ((dwAddr + 5) & 0xFFFFF));
|
|
|
|
if (bMatch)
|
|
{
|
|
// update code window
|
|
ViewCodeWnd(GetDlgItem(hDlg,IDC_DEBUG_CODE),dwAddr);
|
|
break;
|
|
}
|
|
|
|
dwAddr += nSearchDir;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// view from address in memory window
|
|
//
|
|
static BOOL OnMemGoDx(HWND hDlg, DWORD dwAddress)
|
|
{
|
|
HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_MEM_COL0);
|
|
|
|
ViewMemWnd(hDlg, dwAddress);
|
|
SendMessage(hWnd,LB_SETCURSEL,0,0);
|
|
SetFocus(hWnd);
|
|
return -1; // call windows default handler
|
|
}
|
|
|
|
//
|
|
// view of given address in memory window
|
|
//
|
|
static BOOL OnMemGoAdr(HWND hDlg)
|
|
{
|
|
DWORD dwAddress = -1; // no address given
|
|
|
|
OnEnterAddress(hDlg, &dwAddress);
|
|
if (dwAddress != -1) // not Cancel key
|
|
OnMemGoDx(hDlg,dwAddress & GetMemDataMask());
|
|
return -1; // call windows default handler
|
|
}
|
|
|
|
//
|
|
// view from address in memory window
|
|
//
|
|
static BOOL OnMemFollow(HWND hDlg,UINT uID)
|
|
{
|
|
if (ID_DEBUG_MEM_FADDR == uID) // ask for follow address
|
|
{
|
|
DWORD dwAddress = -1; // no address given
|
|
|
|
OnEnterAddress(hDlg, &dwAddress);
|
|
if (dwAddress == -1) return -1; // return at cancel button
|
|
|
|
dwAdrMemFol = dwAddress;
|
|
}
|
|
|
|
CheckMenuItem(hMenuMem,uIDFol,MF_UNCHECKED);
|
|
uIDFol = uID;
|
|
CheckMenuItem(hMenuMem,uIDFol,MF_CHECKED);
|
|
UpdateMemoryWnd(hDlg); // update memory window
|
|
return -1; // call windows default handler
|
|
}
|
|
|
|
//
|
|
// clear all breakpoints
|
|
//
|
|
static BOOL OnClearAll(HWND hDlg)
|
|
{
|
|
wBreakpointCount = 0;
|
|
// redraw code window
|
|
InvalidateRect(GetDlgItem(hDlg,IDC_DEBUG_CODE),NULL,TRUE);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// toggle menu selection
|
|
//
|
|
static BOOL OnToggleMenuItem(HWND hDlg,UINT uIDCheckItem,BOOL *bCheck)
|
|
{
|
|
*bCheck = !*bCheck; // toggle flag
|
|
CheckMenuItem(GetMenu(hDlg),uIDCheckItem,*bCheck ? MF_CHECKED : MF_UNCHECKED);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// change memory window mapping style
|
|
//
|
|
static BOOL OnMemMapping(HWND hDlg,UINT uID)
|
|
{
|
|
if (uID == uIDMap) return -1; // same view, call windows default handler
|
|
|
|
SetMappingMenu(hDlg,uID); // update menu settings
|
|
UpdateMemoryWnd(hDlg); // update memory window
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// push value on hardware stack
|
|
//
|
|
static BOOL OnStackPush(HWND hDlg)
|
|
{
|
|
TCHAR szBuffer[] = _T("00000");
|
|
DWORD dwAddr;
|
|
HWND hWnd;
|
|
UINT i,j;
|
|
|
|
if (nDbgState != DBG_STEPINTO) // not in single step mode
|
|
return TRUE;
|
|
|
|
hWnd = GetDlgItem(hDlg,IDC_DEBUG_STACK);
|
|
|
|
i = (UINT) SendMessage(hWnd,LB_GETCURSEL,0,0);
|
|
if (LB_ERR == (INT) i) return TRUE; // no selection
|
|
|
|
if (IDOK != OnNewValue(szBuffer)) // canceled function
|
|
return TRUE;
|
|
_stscanf(szBuffer,_T("%5X"),&dwAddr);
|
|
|
|
// push stack element
|
|
for (j = ARRAYSIZEOF(Chipset.rstk); j > i + 1; --j)
|
|
{
|
|
Chipset.rstk[(Chipset.rstkp-j)&7] = Chipset.rstk[(Chipset.rstkp-j+1)&7];
|
|
}
|
|
Chipset.rstk[(Chipset.rstkp-j)&7] = dwAddr;
|
|
|
|
UpdateStackWnd(hDlg); // update stack window
|
|
SendMessage(hWnd,LB_SETCURSEL,i,0); // restore cursor postion
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// pop value from hardware stack
|
|
//
|
|
static BOOL OnStackPop(HWND hDlg)
|
|
{
|
|
HWND hWnd;
|
|
UINT i,j;
|
|
|
|
if (nDbgState != DBG_STEPINTO) // not in single step mode
|
|
return TRUE;
|
|
|
|
hWnd = GetDlgItem(hDlg,IDC_DEBUG_STACK);
|
|
|
|
i = (UINT) SendMessage(hWnd,LB_GETCURSEL,0,0);
|
|
if (LB_ERR == (INT) i) return TRUE; // no selection
|
|
|
|
// pop stack element
|
|
for (j = i + 1; j < ARRAYSIZEOF(Chipset.rstk); ++j)
|
|
{
|
|
Chipset.rstk[(Chipset.rstkp-j)&7] = Chipset.rstk[(Chipset.rstkp-j-1)&7];
|
|
}
|
|
Chipset.rstk[Chipset.rstkp] = 0;
|
|
|
|
UpdateStackWnd(hDlg); // update stack window
|
|
SendMessage(hWnd,LB_SETCURSEL,i,0); // restore cursor postion
|
|
return 0;
|
|
}
|
|
|
|
// modify value on hardware stack
|
|
static BOOL OnStackModify(HWND hDlg)
|
|
{
|
|
TCHAR szBuffer[16];
|
|
HWND hWnd;
|
|
INT i;
|
|
|
|
if (nDbgState != DBG_STEPINTO) // not in single step mode
|
|
return TRUE;
|
|
|
|
hWnd = GetDlgItem(hDlg,IDC_DEBUG_STACK);
|
|
|
|
i = (INT) SendMessage(hWnd,LB_GETCURSEL,0,0);
|
|
if (LB_ERR == i) return TRUE; // no selection
|
|
|
|
SendMessage(hWnd,LB_GETTEXT,i,(LPARAM) szBuffer);
|
|
OnNewValue(&szBuffer[3]);
|
|
_stscanf(&szBuffer[3],_T("%5X"),&Chipset.rstk[(Chipset.rstkp-i-1)&7]);
|
|
|
|
UpdateStackWnd(hDlg); // update stack window
|
|
SendMessage(hWnd,LB_SETCURSEL,i,0); // restore cursor postion
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// new register setting
|
|
//
|
|
static BOOL OnLButtonUp(HWND hDlg, LPARAM lParam)
|
|
{
|
|
TCHAR szBuffer[64];
|
|
POINT pt;
|
|
HWND hWnd;
|
|
INT nId;
|
|
|
|
if (nDbgState != DBG_STEPINTO) // not in single step mode
|
|
return TRUE;
|
|
|
|
POINTSTOPOINT(pt,MAKEPOINTS(lParam));
|
|
|
|
// handle of selected window
|
|
hWnd = ChildWindowFromPointEx(hDlg,pt,CWP_SKIPDISABLED);
|
|
nId = GetDlgCtrlID(hWnd); // control ID of window
|
|
|
|
GetWindowText(hWnd,szBuffer,ARRAYSIZEOF(szBuffer));
|
|
switch (nId)
|
|
{
|
|
case IDC_REG_A: // A
|
|
OnNewValue(&szBuffer[3]);
|
|
StrToReg(Chipset.A,16,&szBuffer[3]);
|
|
break;
|
|
case IDC_REG_B: // B
|
|
OnNewValue(&szBuffer[3]);
|
|
StrToReg(Chipset.B,16,&szBuffer[3]);
|
|
break;
|
|
case IDC_REG_C: // C
|
|
OnNewValue(&szBuffer[3]);
|
|
StrToReg(Chipset.C,16,&szBuffer[3]);
|
|
break;
|
|
case IDC_REG_D: // D
|
|
OnNewValue(&szBuffer[3]);
|
|
StrToReg(Chipset.D,16,&szBuffer[3]);
|
|
break;
|
|
case IDC_REG_R0: // R0
|
|
OnNewValue(&szBuffer[3]);
|
|
StrToReg(Chipset.R0,16,&szBuffer[3]);
|
|
break;
|
|
case IDC_REG_R1: // R1
|
|
OnNewValue(&szBuffer[3]);
|
|
StrToReg(Chipset.R1,16,&szBuffer[3]);
|
|
break;
|
|
case IDC_REG_R2: // R2
|
|
OnNewValue(&szBuffer[3]);
|
|
StrToReg(Chipset.R2,16,&szBuffer[3]);
|
|
break;
|
|
case IDC_REG_R3: // R3
|
|
OnNewValue(&szBuffer[3]);
|
|
StrToReg(Chipset.R3,16,&szBuffer[3]);
|
|
break;
|
|
case IDC_REG_R4: // R4
|
|
OnNewValue(&szBuffer[3]);
|
|
StrToReg(Chipset.R4,16,&szBuffer[3]);
|
|
break;
|
|
case IDC_REG_D0: // D0
|
|
OnNewValue(&szBuffer[3]);
|
|
_stscanf(&szBuffer[3],_T("%5X"),&Chipset.d0);
|
|
break;
|
|
case IDC_REG_D1: // D1
|
|
OnNewValue(&szBuffer[3]);
|
|
_stscanf(&szBuffer[3],_T("%5X"),&Chipset.d1);
|
|
break;
|
|
case IDC_REG_P: // P
|
|
OnNewValue(&szBuffer[2]);
|
|
Chipset.P = _totupper(szBuffer[2]) - _T('0');
|
|
if (Chipset.P > 9) Chipset.P -= 7;
|
|
PCHANGED;
|
|
break;
|
|
case IDC_REG_PC: // PC
|
|
OnNewValue(&szBuffer[3]);
|
|
_stscanf(&szBuffer[3],_T("%5X"),&Chipset.pc);
|
|
break;
|
|
case IDC_REG_OUT: // OUT
|
|
OnNewValue(&szBuffer[4]);
|
|
Chipset.out = (WORD) _tcstoul(&szBuffer[4],NULL,16);
|
|
break;
|
|
case IDC_REG_IN: // IN
|
|
OnNewValue(&szBuffer[3]);
|
|
Chipset.in = (WORD) _tcstoul(&szBuffer[3],NULL,16);
|
|
break;
|
|
case IDC_REG_ST: // ST
|
|
OnNewValue(&szBuffer[3]);
|
|
StrToReg(Chipset.ST,4,&szBuffer[3]);
|
|
break;
|
|
case IDC_REG_CY: // CY
|
|
Chipset.carry = !Chipset.carry;
|
|
break;
|
|
case IDC_REG_MODE: // MODE
|
|
Chipset.mode_dec = !Chipset.mode_dec;
|
|
break;
|
|
case IDC_REG_MP: // MP
|
|
Chipset.HST ^= MP;
|
|
break;
|
|
case IDC_REG_SR: // SR
|
|
Chipset.HST ^= SR;
|
|
break;
|
|
case IDC_REG_SB: // SB
|
|
Chipset.HST ^= SB;
|
|
break;
|
|
case IDC_REG_XM: // XM
|
|
Chipset.HST ^= XM;
|
|
break;
|
|
case IDC_MISC_INT: // interrupt status
|
|
Chipset.inte = !Chipset.inte;
|
|
UpdateMiscWnd(hDlg); // update miscellaneous window
|
|
break;
|
|
case IDC_MISC_KEY: // 1ms keyboard scan
|
|
Chipset.intk = !Chipset.intk;
|
|
UpdateMiscWnd(hDlg); // update miscellaneous window
|
|
break;
|
|
case IDC_MISC_BS: // Bank switcher setting
|
|
OnNewValue(szBuffer);
|
|
Chipset.Bank_FF = _tcstoul(szBuffer,NULL,16);
|
|
Chipset.Bank_FF &= 0x7F;
|
|
RomSwitch(Chipset.Bank_FF); // update memory mapping
|
|
|
|
UpdateCodeWnd(hDlg); // update code window
|
|
UpdateMemoryWnd(hDlg); // update memory window
|
|
UpdateMiscWnd(hDlg); // update miscellaneous window
|
|
break;
|
|
}
|
|
UpdateRegisterWnd(hDlg); // update register
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// double click in list box area
|
|
//
|
|
static BOOL OnDblClick(HWND hWnd, WORD wId)
|
|
{
|
|
HWND hDlg,hWndCode;
|
|
TCHAR szBuffer[4];
|
|
BYTE byData;
|
|
INT i;
|
|
DWORD dwAddress;
|
|
|
|
hDlg = GetParent(hWnd); // dialog window handle
|
|
hWndCode = GetDlgItem(hDlg,IDC_DEBUG_CODE);
|
|
|
|
if (wId == IDC_DEBUG_STACK) // stack list box
|
|
{
|
|
// get cpu address of selected item
|
|
i = (INT) SendMessage(hWnd,LB_GETCURSEL,0,0);
|
|
dwAddress = (DWORD) SendMessage(hWnd,LB_GETITEMDATA,i,0);
|
|
|
|
ViewCodeWnd(hWndCode,dwAddress); // show code of this address
|
|
return TRUE;
|
|
}
|
|
|
|
for (i = 0; i < MEMWNDMAX; ++i) // scan all Id's
|
|
if (nCol[i] == wId) // found ID
|
|
break;
|
|
|
|
// not IDC_DEBUG_MEM window or module mode -> default handler
|
|
if (i == MEMWNDMAX || ID_DEBUG_MEM_MAP != uIDMap)
|
|
return FALSE;
|
|
|
|
// calculate address of byte
|
|
dwAddress = i * 2;
|
|
i = (INT) SendMessage(hWnd,LB_GETCARETINDEX,0,0);
|
|
dwAddress += MAXMEMITEMS * i + dwAdrMem;
|
|
|
|
// enter new value
|
|
SendMessage(hWnd,LB_GETTEXT,i,(LPARAM) szBuffer);
|
|
OnNewValue(szBuffer);
|
|
byData = (BYTE) _tcstoul(szBuffer,NULL,16);
|
|
byData = (byData >> 4) | (byData << 4); // change nibbles for writing
|
|
|
|
Write2(dwAddress,byData); // write data
|
|
ViewCodeWnd(hWndCode,dwAdrLine[0]); // update code window
|
|
ViewMemWnd(hDlg,dwAdrMem); // update memory window
|
|
SendMessage(hWnd,LB_SETCURSEL,i,0);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// request for context menu
|
|
//
|
|
static VOID OnContextMenu(HWND hDlg, LPARAM lParam, WPARAM wParam)
|
|
{
|
|
POINT pt;
|
|
INT nId;
|
|
|
|
POINTSTOPOINT(pt,MAKEPOINTS(lParam)); // mouse position
|
|
|
|
if (pt.x == -1 && pt.y == -1) // VK_APPS
|
|
{
|
|
RECT rc;
|
|
|
|
GetWindowRect((HWND) wParam,&rc); // get position of active window
|
|
pt.x = rc.left + 5;
|
|
pt.y = rc.top + 5;
|
|
}
|
|
|
|
nId = GetDlgCtrlID((HWND) wParam); // control ID of window
|
|
|
|
switch(nId)
|
|
{
|
|
case IDC_DEBUG_CODE: // handle code window
|
|
TrackPopupMenu(hMenuCode,0,pt.x,pt.y,0,hDlg,NULL);
|
|
break;
|
|
|
|
case IDC_DEBUG_MEM_COL0:
|
|
case IDC_DEBUG_MEM_COL1:
|
|
case IDC_DEBUG_MEM_COL2:
|
|
case IDC_DEBUG_MEM_COL3:
|
|
case IDC_DEBUG_MEM_COL4:
|
|
case IDC_DEBUG_MEM_COL5:
|
|
case IDC_DEBUG_MEM_COL6:
|
|
case IDC_DEBUG_MEM_COL7: // handle memory window
|
|
TrackPopupMenu(hMenuMem,0,pt.x,pt.y,0,hDlg,NULL);
|
|
break;
|
|
|
|
case IDC_DEBUG_STACK: // handle stack window
|
|
TrackPopupMenu(hMenuStack,0,pt.x,pt.y,0,hDlg,NULL);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// mouse setting for capturing window
|
|
//
|
|
static BOOL OnSetCursor(HWND hDlg)
|
|
{
|
|
// debugger not active but cursor is over debugger window
|
|
if (bActFollowsMouse && GetActiveWindow() != hDlg)
|
|
{
|
|
// force debugger window to foreground
|
|
ForceForegroundWindow(GetLastActivePopup(hDlg));
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//################
|
|
//#
|
|
//# Dialog handler
|
|
//#
|
|
//################
|
|
|
|
//
|
|
// handle right/left keys in memory window
|
|
//
|
|
static __inline BOOL OnKeyRightLeft(HWND hWnd, WPARAM wParam)
|
|
{
|
|
HWND hWndNew;
|
|
WORD wX;
|
|
INT nId;
|
|
|
|
nId = GetDlgCtrlID(hWnd); // control ID of window
|
|
|
|
for (wX = 0; wX < MEMWNDMAX; ++wX) // scan all Id's
|
|
if (nCol[wX] == nId) // found ID
|
|
break;
|
|
|
|
if (wX == MEMWNDMAX) return -1; // not IDC_DEBUG_MEM window, default handler
|
|
|
|
// new position
|
|
wX = ((LOWORD(wParam) == VK_RIGHT) ? (wX + 1) : (wX + MEMWNDMAX - 1)) % MEMWNDMAX;
|
|
|
|
// set new focus
|
|
hWndNew = GetDlgItem(GetParent(hWnd),nCol[wX]);
|
|
SendMessage(hWndNew,LB_SETCURSEL,HIWORD(wParam),0);
|
|
SetFocus(hWndNew);
|
|
return -2;
|
|
}
|
|
|
|
//
|
|
// handle (page) up/down keys in memory window
|
|
//
|
|
static __inline BOOL OnKeyUpDown(HWND hWnd, WPARAM wParam)
|
|
{
|
|
INT wX, wY;
|
|
INT nId;
|
|
|
|
nId = GetDlgCtrlID(hWnd); // control ID of window
|
|
|
|
for (wX = 0; wX < MEMWNDMAX; ++wX) // scan all Id's
|
|
if (nCol[wX] == nId) // found ID
|
|
break;
|
|
|
|
if (wX == MEMWNDMAX) return -1; // not IDC_DEBUG_MEM window, default handler
|
|
|
|
wY = HIWORD(wParam); // get old focus
|
|
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case VK_NEXT:
|
|
dwAdrMem = (dwAdrMem + MAXMEMITEMS * MAXMEMLINES) & GetMemDataMask();
|
|
ViewMemWnd(GetParent(hWnd),dwAdrMem);
|
|
SendMessage(hWnd,LB_SETCURSEL,wY,0);
|
|
return -2;
|
|
|
|
case VK_PRIOR:
|
|
dwAdrMem = (dwAdrMem - MAXMEMITEMS * MAXMEMLINES) & GetMemDataMask();
|
|
ViewMemWnd(GetParent(hWnd),dwAdrMem);
|
|
SendMessage(hWnd,LB_SETCURSEL,wY,0);
|
|
return -2;
|
|
|
|
case VK_DOWN:
|
|
if (wY+1 >= MAXMEMLINES)
|
|
{
|
|
dwAdrMem = (dwAdrMem + MAXMEMITEMS) & GetMemDataMask();
|
|
ViewMemWnd(GetParent(hWnd),dwAdrMem);
|
|
SendMessage(hWnd,LB_SETCURSEL,wY,0);
|
|
return -2;
|
|
}
|
|
break;
|
|
|
|
case VK_UP:
|
|
if (wY == 0)
|
|
{
|
|
dwAdrMem = (dwAdrMem - MAXMEMITEMS) & GetMemDataMask();
|
|
ViewMemWnd(GetParent(hWnd),dwAdrMem);
|
|
SendMessage(hWnd,LB_SETCURSEL,wY,0);
|
|
return -2;
|
|
}
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// handle (page) +/- keys in memory window
|
|
//
|
|
static __inline BOOL OnKeyPlusMinus(HWND hWnd, WPARAM wParam)
|
|
{
|
|
INT wX, wY;
|
|
INT nId;
|
|
|
|
nId = GetDlgCtrlID(hWnd); // control ID of window
|
|
|
|
for (wX = 0; wX < MEMWNDMAX; ++wX) // scan all Id's
|
|
if (nCol[wX] == nId) // found ID
|
|
break;
|
|
|
|
if (wX == MEMWNDMAX) return -1; // not IDC_DEBUG_MEM window, default handler
|
|
|
|
wY = HIWORD(wParam); // get focus
|
|
|
|
if (LOWORD(wParam) == VK_ADD) // move start address of memory view
|
|
dwAdrMem++;
|
|
else
|
|
dwAdrMem--;
|
|
dwAdrMem &= GetMemDataMask();
|
|
|
|
ViewMemWnd(GetParent(hWnd),dwAdrMem); // redraw memory view
|
|
SendMessage(hWnd,LB_SETCURSEL,wY,0); // set focus at old position
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// handle keys in code window
|
|
//
|
|
static __inline BOOL OnKeyCodeWnd(HWND hDlg, WPARAM wParam)
|
|
{
|
|
HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE);
|
|
WORD wKey = LOWORD(wParam);
|
|
WORD wItem = HIWORD(wParam);
|
|
|
|
// down key on last line
|
|
if ((wKey == VK_DOWN || wKey == VK_NEXT) && wItem == MAXCODELINES - 1)
|
|
{
|
|
WORD i = ((dwAdrLine[0] & CODELABEL) != 0) ? 2 : 1;
|
|
|
|
ViewCodeWnd(hWnd,dwAdrLine[i]);
|
|
SendMessage(hWnd,LB_SETCURSEL,wItem-i,0);
|
|
}
|
|
// up key on first line
|
|
if ((wKey == VK_UP || wKey == VK_PRIOR) && wItem == 0)
|
|
{
|
|
ViewCodeWnd(hWnd,dwAdrLine[0]-1);
|
|
}
|
|
|
|
if (wKey == _T('G')) return OnCodeGoAdr(GetParent(hWnd)); // goto new address
|
|
|
|
return -1; // process key
|
|
}
|
|
|
|
//
|
|
// handle drawing in code window
|
|
//
|
|
static __inline BOOL OnDrawCodeWnd(LPDRAWITEMSTRUCT lpdis)
|
|
{
|
|
TCHAR szBuf[64];
|
|
COLORREF crBkColor;
|
|
COLORREF crTextColor;
|
|
HFONT hFont;
|
|
BOOL bBrk,bPC,bLabel;
|
|
|
|
if (lpdis->itemID == -1) // no item in list box
|
|
return TRUE;
|
|
|
|
// get item text
|
|
SendMessage(lpdis->hwndItem,LB_GETTEXT,lpdis->itemID,(LPARAM) szBuf);
|
|
|
|
// line is a label
|
|
bLabel = ((dwAdrLine[lpdis->itemID] & CODELABEL) != 0);
|
|
|
|
if (!bLabel)
|
|
{
|
|
// check for codebreakpoint
|
|
bBrk = CheckBreakpoint(dwAdrLine[lpdis->itemID],1,BP_EXEC);
|
|
bPC = szBuf[5] != _T(' '); // check if line of program counter
|
|
|
|
crTextColor = COLOR_WHITE; // standard text color
|
|
|
|
if (lpdis->itemState & ODS_SELECTED) // cursor line
|
|
{
|
|
if (bPC) // PC line
|
|
{
|
|
crBkColor = bBrk ? COLOR_DKGRAY : COLOR_TEAL;
|
|
}
|
|
else // normal line
|
|
{
|
|
crBkColor = bBrk ? COLOR_PURPLE : COLOR_NAVY;
|
|
}
|
|
}
|
|
else // not cursor line
|
|
{
|
|
if (bPC) // PC line
|
|
{
|
|
crBkColor = bBrk ? COLOR_OLIVE : COLOR_GREEN;
|
|
}
|
|
else // normal line
|
|
{
|
|
if (bBrk)
|
|
{
|
|
crBkColor = COLOR_MAROON;
|
|
}
|
|
else
|
|
{
|
|
crBkColor = COLOR_WHITE;
|
|
crTextColor = COLOR_BLACK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else // label
|
|
{
|
|
crBkColor = COLOR_WHITE;
|
|
crTextColor = COLOR_NAVY;
|
|
hFont = (HFONT) SelectObject(lpdis->hDC,hFontBold);
|
|
}
|
|
|
|
// write Text
|
|
crBkColor = SetBkColor(lpdis->hDC,crBkColor);
|
|
crTextColor = SetTextColor(lpdis->hDC,crTextColor);
|
|
|
|
ExtTextOut(lpdis->hDC,(int)(lpdis->rcItem.left)+2,(int)(lpdis->rcItem.top),
|
|
ETO_OPAQUE,(LPRECT)&lpdis->rcItem,szBuf,lstrlen(szBuf),NULL);
|
|
|
|
SetBkColor(lpdis->hDC,crBkColor);
|
|
SetTextColor(lpdis->hDC,crTextColor);
|
|
|
|
if (bLabel) SelectObject(lpdis->hDC,hFont);
|
|
|
|
if (lpdis->itemState & ODS_FOCUS) // redraw focus
|
|
DrawFocusRect(lpdis->hDC,&lpdis->rcItem);
|
|
|
|
return TRUE; // focus handled here
|
|
}
|
|
|
|
//
|
|
// detect changed register
|
|
//
|
|
static __inline BOOL OnCtlColorStatic(HWND hWnd)
|
|
{
|
|
BOOL bError = FALSE; // not changed
|
|
|
|
int nId = GetDlgCtrlID(hWnd);
|
|
if (nId >= REG_START && nId <= REG_STOP) // in register area
|
|
bError = bRegUpdate[nId-REG_START]; // register changed?
|
|
return bError;
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Public functions
|
|
//#
|
|
//################
|
|
|
|
//
|
|
// handle upper 32 bit of cpu cycle counter
|
|
//
|
|
VOID UpdateDbgCycleCounter(VOID)
|
|
{
|
|
// update 64 bit cpu cycle counter
|
|
if (Chipset.cycles < dwDbgRefCycles) ++Chipset.cycles_reserved;
|
|
dwDbgRefCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// check for breakpoints
|
|
//
|
|
BOOL CheckBreakpoint(DWORD dwAddr, DWORD dwRange, UINT nType)
|
|
{
|
|
INT i;
|
|
|
|
for (i = 0; i < wBreakpointCount; ++i) // scan all breakpoints
|
|
{
|
|
// check address range and type
|
|
if ( sBreakpoint[i].bEnable
|
|
&& sBreakpoint[i].dwAddr >= dwAddr && sBreakpoint[i].dwAddr < dwAddr + dwRange
|
|
&& (sBreakpoint[i].nType & nType) != 0)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// notify debugger that emulation stopped
|
|
//
|
|
VOID NotifyDebugger(INT nType) // update registers
|
|
{
|
|
nRplBreak = nType; // save breakpoint type
|
|
FlushTrace(); // flush trace buffer
|
|
_ASSERT(hDlgDebug); // debug dialog box open
|
|
PostMessage(hDlgDebug,WM_UPDATE,0,0);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// disable debugger
|
|
//
|
|
VOID DisableDebugger(VOID)
|
|
{
|
|
if (hDlgDebug) // debugger running
|
|
DestroyWindow(hDlgDebug); // then close debugger to renter emulation
|
|
return;
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Debugger Message loop
|
|
//#
|
|
//################
|
|
|
|
//
|
|
// ID_TOOL_DEBUG
|
|
//
|
|
static __inline HWND CreateToolbar(HWND hWnd)
|
|
{
|
|
HRSRC hRes;
|
|
HGLOBAL hGlobal;
|
|
CToolBarData *pData;
|
|
TBBUTTON *ptbb;
|
|
INT i,j;
|
|
|
|
HWND hWndToolbar = NULL; // toolbar window
|
|
|
|
InitCommonControls(); // ensure that common control DLL is loaded
|
|
|
|
if ((hRes = FindResource(hApp,MAKEINTRESOURCE(IDR_DEBUG_TOOLBAR),RT_TOOLBAR)) == NULL)
|
|
goto quit;
|
|
|
|
if ((hGlobal = LoadResource(hApp,hRes)) == NULL)
|
|
goto quit;
|
|
|
|
if ((pData = (CToolBarData*) LockResource(hGlobal)) == NULL)
|
|
goto unlock;
|
|
|
|
_ASSERT(pData->wVersion == 1); // toolbar resource version
|
|
|
|
// alloc memory for TBBUTTON stucture
|
|
if (!(ptbb = (TBBUTTON *) malloc(pData->wItemCount*sizeof(TBBUTTON))))
|
|
goto unlock;
|
|
|
|
// fill TBBUTTON stucture with resource data
|
|
for (i = j = 0; i < pData->wItemCount; ++i)
|
|
{
|
|
if (pData->aItems[i])
|
|
{
|
|
ptbb[i].iBitmap = j++;
|
|
ptbb[i].fsStyle = TBSTYLE_BUTTON;
|
|
}
|
|
else
|
|
{
|
|
ptbb[i].iBitmap = 5; // separator width
|
|
ptbb[i].fsStyle = TBSTYLE_SEP;
|
|
}
|
|
ptbb[i].idCommand = pData->aItems[i];
|
|
ptbb[i].fsState = TBSTATE_ENABLED;
|
|
ptbb[i].dwData = 0;
|
|
ptbb[i].iString = j;
|
|
}
|
|
|
|
hWndToolbar = CreateToolbarEx(hWnd,WS_CHILD | WS_VISIBLE | TBSTYLE_TOOLTIPS,
|
|
IDR_DEBUG_TOOLBAR,j,hApp,IDR_DEBUG_TOOLBAR,ptbb,pData->wItemCount,
|
|
pData->wWidth,pData->wHeight,pData->wWidth,pData->wHeight,
|
|
sizeof(TBBUTTON));
|
|
|
|
free(ptbb);
|
|
|
|
unlock:
|
|
FreeResource(hGlobal);
|
|
quit:
|
|
return hWndToolbar;
|
|
}
|
|
|
|
static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static HMENU hMenuMainCode,hMenuMainMem,hMenuMainStack;
|
|
|
|
WINDOWPLACEMENT wndpl;
|
|
TEXTMETRIC tm;
|
|
HDC hDC;
|
|
HFONT hFont;
|
|
HMENU hSysMenu;
|
|
HMENU hDbgMenu;
|
|
INT i;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
SetWindowLocation(hDlg,nDbgPosX,nDbgPosY);
|
|
if (bAlwaysOnTop) SetWindowPos(hDlg,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
|
|
SendMessage(hDlg,WM_SETICON,ICON_BIG,(LPARAM) LoadIcon(hApp,MAKEINTRESOURCE(IDI_EMU48)));
|
|
|
|
bDbgTrace = FALSE; // disable file trace
|
|
|
|
// load file trace settings
|
|
ReadSettingsString(_T("Debugger"),_T("TraceFile"),szTraceFilename,szTraceFilename,ARRAYSIZEOF(szTraceFilename));
|
|
uTraceMode = ReadSettingsInt(_T("Debugger"),_T("TraceFileMode"),uTraceMode);
|
|
bTraceReg = ReadSettingsInt(_T("Debugger"),_T("TraceRegister"),bTraceReg);
|
|
bTraceMmu = ReadSettingsInt(_T("Debugger"),_T("TraceMMU"),bTraceMmu);
|
|
bTraceOpc = ReadSettingsInt(_T("Debugger"),_T("TraceOpcode"),bTraceOpc);
|
|
|
|
// add Settings item to sysmenu
|
|
_ASSERT((IDM_DEBUG_SETTINGS & 0xFFF0) == IDM_DEBUG_SETTINGS);
|
|
_ASSERT(IDM_DEBUG_SETTINGS < 0xF000);
|
|
if ((hSysMenu = GetSystemMenu(hDlg,FALSE)) != NULL)
|
|
{
|
|
VERIFY(AppendMenu(hSysMenu,MF_SEPARATOR,0,NULL));
|
|
VERIFY(AppendMenu(hSysMenu,MF_STRING,IDM_DEBUG_SETTINGS,_T("Debugger Settings...")));
|
|
}
|
|
|
|
hDbgMenu = GetMenu(hDlg); // menu of debugger dialog
|
|
hWndToolbar = CreateToolbar(hDlg); // add toolbar
|
|
|
|
CheckMenuItem(hDbgMenu,ID_BREAKPOINTS_NOP3, bDbgNOP3 ? MF_CHECKED : MF_UNCHECKED);
|
|
CheckMenuItem(hDbgMenu,ID_BREAKPOINTS_DOCODE,bDbgCode ? MF_CHECKED : MF_UNCHECKED);
|
|
CheckMenuItem(hDbgMenu,ID_BREAKPOINTS_RPL, bDbgRPL ? MF_CHECKED : MF_UNCHECKED);
|
|
CheckMenuItem(hDbgMenu,ID_INTR_STEPOVERINT, bDbgSkipInt ? MF_CHECKED : MF_UNCHECKED);
|
|
CheckMenuItem(hDbgMenu,ID_TRACE_ENABLE, bDbgTrace ? MF_CHECKED : MF_UNCHECKED);
|
|
|
|
EnableMenuItem(hDbgMenu,ID_TRACE_SETTINGS,bDbgTrace ? MF_GRAYED : MF_ENABLED);
|
|
|
|
hDlgDebug = hDlg; // handle for debugger dialog
|
|
hEventDebug = CreateEvent(NULL,FALSE,FALSE,NULL);
|
|
if (hEventDebug == NULL)
|
|
{
|
|
AbortMessage(_T("Event creation failed !"));
|
|
return TRUE;
|
|
}
|
|
hMenuMainCode = LoadMenu(hApp,MAKEINTRESOURCE(IDR_DEBUG_CODE));
|
|
_ASSERT(hMenuMainCode);
|
|
hMenuCode = GetSubMenu(hMenuMainCode, 0);
|
|
_ASSERT(hMenuCode);
|
|
hMenuMainMem = LoadMenu(hApp,MAKEINTRESOURCE(IDR_DEBUG_MEM));
|
|
_ASSERT(hMenuMainMem);
|
|
hMenuMem = GetSubMenu(hMenuMainMem, 0);
|
|
_ASSERT(hMenuMem);
|
|
hMenuMainStack = LoadMenu(hApp,MAKEINTRESOURCE(IDR_DEBUG_STACK));
|
|
_ASSERT(hMenuMainStack);
|
|
hMenuStack = GetSubMenu(hMenuMainStack, 0);
|
|
_ASSERT(hMenuStack);
|
|
|
|
// bold font for symbol labels in code window
|
|
hDC = GetDC(hDlg);
|
|
VERIFY(hFontBold = CreateFont(-MulDiv(8,GetDeviceCaps(hDC,LOGPIXELSY),72),0,0,0,FW_BOLD,0,0,0,ANSI_CHARSET,
|
|
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,_T("Arial")));
|
|
ReleaseDC(hDlg,hDC);
|
|
|
|
// font settings
|
|
SendDlgItemMessage(hDlg,IDC_STATIC_CODE, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
|
|
SendDlgItemMessage(hDlg,IDC_STATIC_REGISTERS,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
|
|
SendDlgItemMessage(hDlg,IDC_STATIC_MEMORY, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
|
|
SendDlgItemMessage(hDlg,IDC_STATIC_STACK, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
|
|
SendDlgItemMessage(hDlg,IDC_STATIC_MMU, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
|
|
SendDlgItemMessage(hDlg,IDC_STATIC_MISC, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
|
|
|
|
// init last instruction circular buffer
|
|
pdwInstrArray = (DWORD *) malloc(wInstrSize*sizeof(*pdwInstrArray));
|
|
wInstrWp = wInstrRp = 0; // write/read pointer
|
|
|
|
// init "Follow" menu entry in debugger "Memory" context menu
|
|
CheckMenuItem(hMenuMem,uIDFol,MF_CHECKED);
|
|
|
|
LoadSymbTable(); // load external rpl symbol table
|
|
|
|
InitMemMap(hDlg); // init memory mapping table
|
|
InitBsArea(hDlg); // init bank switcher list box
|
|
DisableMenuKeys(hDlg); // set debug menu keys into run state
|
|
|
|
fnOutTrace = OutTrace; // function for file trace
|
|
RplReadNibble = GetMemNib; // get nibble function for RPL object viewer
|
|
|
|
dwDbgStopPC = -1; // no stop address for goto cursor
|
|
dwDbgRplPC = -1; // no stop address for RPL breakpoint
|
|
|
|
// init reference cpu cycle counter for 64 bit debug cycle counter
|
|
dwDbgRefCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
|
|
|
|
nDbgState = DBG_STEPINTO; // state "step into"
|
|
if (Chipset.Shutdn) // cpu thread stopped
|
|
SetEvent(hEventShutdn); // goto debug session
|
|
|
|
OldChipset = Chipset; // save chipset values
|
|
return TRUE;
|
|
|
|
case WM_DESTROY:
|
|
// SetHP48Time(); // update time & date
|
|
nDbgState = DBG_OFF; // debugger inactive
|
|
StopTrace(); // finish trace
|
|
bInterrupt = TRUE; // exit opcode loop
|
|
SetEvent(hEventDebug);
|
|
if (pdwInstrArray) // free last instruction circular buffer
|
|
{
|
|
EnterCriticalSection(&csDbgLock);
|
|
{
|
|
free(pdwInstrArray);
|
|
pdwInstrArray = NULL;
|
|
}
|
|
LeaveCriticalSection(&csDbgLock);
|
|
}
|
|
CloseHandle(hEventDebug);
|
|
wndpl.length = sizeof(wndpl); // save debugger window position
|
|
GetWindowPlacement(hDlg, &wndpl);
|
|
nDbgPosX = wndpl.rcNormalPosition.left;
|
|
nDbgPosY = wndpl.rcNormalPosition.top;
|
|
|
|
// save file trace settings
|
|
WriteSettingsString(_T("Debugger"),_T("TraceFile"),szTraceFilename);
|
|
WriteSettingsInt(_T("Debugger"),_T("TraceFileMode"),uTraceMode);
|
|
WriteSettingsInt(_T("Debugger"),_T("TraceRegister"),bTraceReg);
|
|
WriteSettingsInt(_T("Debugger"),_T("TraceMMU"),bTraceMmu);
|
|
WriteSettingsInt(_T("Debugger"),_T("TraceOpcode"),bTraceOpc);
|
|
|
|
RplDeleteTable(); // delete rpl symbol table
|
|
DeleteObject(hFontBold); // delete bold font
|
|
DestroyMenu(hMenuMainCode);
|
|
DestroyMenu(hMenuMainMem);
|
|
DestroyMenu(hMenuMainStack);
|
|
hDlgDebug = NULL; // debugger windows closed
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
DestroyWindow(hDlg);
|
|
break;
|
|
|
|
case WM_UPDATE:
|
|
OnUpdate(hDlg);
|
|
return TRUE;
|
|
|
|
case WM_SYSCOMMAND:
|
|
if ((wParam & 0xFFF0) == IDM_DEBUG_SETTINGS)
|
|
{
|
|
return OnSettings(hDlg);
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (HIWORD(wParam))
|
|
{
|
|
case LBN_DBLCLK:
|
|
return OnDblClick((HWND) lParam, LOWORD(wParam));
|
|
|
|
case LBN_SETFOCUS:
|
|
i = (INT) SendMessage((HWND) lParam,LB_GETCARETINDEX,0,0);
|
|
SendMessage((HWND) lParam,LB_SETCURSEL,i,0);
|
|
return TRUE;
|
|
|
|
case LBN_KILLFOCUS:
|
|
SendMessage((HWND) lParam,LB_SETCURSEL,-1,0);
|
|
return TRUE;
|
|
}
|
|
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case ID_BREAKPOINTS_SETBREAK: return OnKeyF2(hDlg);
|
|
case ID_DEBUG_RUN: return OnKeyF5(hDlg);
|
|
case ID_DEBUG_RUNCURSOR: return OnKeyF6(hDlg);
|
|
case ID_DEBUG_STEP: return OnKeyF7(hDlg);
|
|
case ID_DEBUG_STEPOVER: return OnKeyF8(hDlg);
|
|
case ID_DEBUG_STEPOUT: return OnKeyF9(hDlg);
|
|
case ID_DEBUG_BREAK: return OnKeyF11(hDlg);
|
|
case ID_DEBUG_CODE_GOADR: return OnCodeGoAdr(hDlg);
|
|
case ID_DEBUG_CODE_GOPC: return OnCodeGoPC(hDlg);
|
|
case ID_DEBUG_CODE_SETPCTOSELECT: return OnCodeSetPcToSelection(hDlg);
|
|
case ID_DEBUG_CODE_PREVPCO: return OnCodeFindPCO(hDlg,dwAdrLine[0],-1);
|
|
case ID_DEBUG_CODE_NEXTPCO: return OnCodeFindPCO(hDlg,dwAdrLine[0],1);
|
|
case ID_BREAKPOINTS_CODEEDIT: return OnEditBreakpoint(hDlg);
|
|
case ID_BREAKPOINTS_CLEARALL: return OnClearAll(hDlg);
|
|
case ID_BREAKPOINTS_NOP3: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgNOP3);
|
|
case ID_BREAKPOINTS_DOCODE: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgCode);
|
|
case ID_BREAKPOINTS_RPL: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgRPL);
|
|
case ID_TRACE_SETTINGS: return OnTraceSettings(hDlg);
|
|
case ID_TRACE_ENABLE: return OnTraceEnable(hDlg);
|
|
case ID_INFO_LASTINSTRUCTIONS: return OnInfoIntr(hDlg);
|
|
case ID_INFO_PROFILE: return OnProfile(hDlg);
|
|
case ID_INFO_WRITEONLYREG: return OnInfoWoRegister(hDlg);
|
|
case ID_INTR_STEPOVERINT: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgSkipInt);
|
|
case ID_DEBUG_MEM_GOADR: return OnMemGoAdr(hDlg);
|
|
case ID_DEBUG_MEM_GOPC: return OnMemGoDx(hDlg,Chipset.pc);
|
|
case ID_DEBUG_MEM_GOD0: return OnMemGoDx(hDlg,Chipset.d0);
|
|
case ID_DEBUG_MEM_GOD1: return OnMemGoDx(hDlg,Chipset.d1);
|
|
case ID_DEBUG_MEM_GOSTACK: return OnMemGoDx(hDlg,Chipset.rstk[(Chipset.rstkp-1)&7]);
|
|
case ID_DEBUG_MEM_FNONE:
|
|
case ID_DEBUG_MEM_FADDR:
|
|
case ID_DEBUG_MEM_FPC:
|
|
case ID_DEBUG_MEM_FD0:
|
|
case ID_DEBUG_MEM_FD1: return OnMemFollow(hDlg,LOWORD(wParam));
|
|
case ID_DEBUG_MEM_FIND: return OnMemFind(hDlg);
|
|
case ID_DEBUG_MEM_MAP:
|
|
case ID_DEBUG_MEM_NCE1:
|
|
case ID_DEBUG_MEM_NCE2:
|
|
case ID_DEBUG_MEM_CE1:
|
|
case ID_DEBUG_MEM_CE2:
|
|
case ID_DEBUG_MEM_NCE3: return OnMemMapping(hDlg,LOWORD(wParam));
|
|
case ID_DEBUG_MEM_LOAD: return OnMemLoadData(hDlg);
|
|
case ID_DEBUG_MEM_SAVE: return OnMemSaveData(hDlg);
|
|
case ID_DEBUG_MEM_RPLVIEW: return OnRplObjView(hDlg);
|
|
case ID_DEBUG_STACK_PUSH: return OnStackPush(hDlg);
|
|
case ID_DEBUG_STACK_POP: return OnStackPop(hDlg);
|
|
case ID_DEBUG_STACK_MODIFY: return OnStackModify(hDlg);
|
|
case ID_DEBUG_CANCEL: DestroyWindow(hDlg); return TRUE;
|
|
}
|
|
break;
|
|
|
|
case WM_VKEYTOITEM:
|
|
switch (LOWORD(wParam)) // always valid
|
|
{
|
|
case VK_F2: return OnKeyF2(hDlg); // toggle breakpoint
|
|
case VK_F5: return OnKeyF5(hDlg); // key run
|
|
case VK_F6: return OnKeyF6(hDlg); // key step cursor
|
|
case VK_F7: return OnKeyF7(hDlg); // key step into
|
|
case VK_F8: return OnKeyF8(hDlg); // key step over
|
|
case VK_F9: return OnKeyF9(hDlg); // key step out
|
|
case VK_F11: return OnKeyF11(hDlg); // key break
|
|
}
|
|
|
|
switch(GetDlgCtrlID((HWND) lParam)) // calling window
|
|
{
|
|
// handle code window
|
|
case IDC_DEBUG_CODE:
|
|
return OnKeyCodeWnd(hDlg, wParam);
|
|
|
|
// handle memory window
|
|
case IDC_DEBUG_MEM_COL0:
|
|
case IDC_DEBUG_MEM_COL1:
|
|
case IDC_DEBUG_MEM_COL2:
|
|
case IDC_DEBUG_MEM_COL3:
|
|
case IDC_DEBUG_MEM_COL4:
|
|
case IDC_DEBUG_MEM_COL5:
|
|
case IDC_DEBUG_MEM_COL6:
|
|
case IDC_DEBUG_MEM_COL7:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case _T('G'): return OnMemGoAdr(GetParent((HWND) lParam));
|
|
case _T('F'): return OnMemFind(GetParent((HWND) lParam));
|
|
case VK_RIGHT:
|
|
case VK_LEFT: return OnKeyRightLeft((HWND) lParam, wParam);
|
|
case VK_NEXT:
|
|
case VK_PRIOR:
|
|
case VK_DOWN:
|
|
case VK_UP: return OnKeyUpDown((HWND) lParam, wParam);
|
|
case VK_ADD:
|
|
case VK_SUBTRACT: return OnKeyPlusMinus((HWND) lParam, wParam);
|
|
}
|
|
break;
|
|
}
|
|
return -1; // default action
|
|
|
|
case WM_LBUTTONUP:
|
|
return OnLButtonUp(hDlg, lParam);
|
|
|
|
case WM_CONTEXTMENU:
|
|
OnContextMenu(hDlg, lParam, wParam);
|
|
break;
|
|
|
|
case WM_SETCURSOR:
|
|
return OnSetCursor(hDlg);
|
|
|
|
case WM_CTLCOLORSTATIC: // register color highlighting
|
|
// highlight text?
|
|
if (OnCtlColorStatic((HWND) lParam))
|
|
{
|
|
SetTextColor((HDC) wParam, COLOR_RED);
|
|
SetBkColor((HDC) wParam, GetSysColor(COLOR_BTNFACE));
|
|
return (INT_PTR) GetStockObject(NULL_BRUSH); // transparent brush
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
// tooltip for toolbar
|
|
if (((LPNMHDR) lParam)->code == TTN_GETDISPINFO)
|
|
{
|
|
((LPTOOLTIPTEXT) lParam)->hinst = hApp;
|
|
((LPTOOLTIPTEXT) lParam)->lpszText = MAKEINTRESOURCE(((LPTOOLTIPTEXT) lParam)->hdr.idFrom);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_DRAWITEM:
|
|
if (wParam == IDC_DEBUG_CODE) return OnDrawCodeWnd((LPDRAWITEMSTRUCT) lParam);
|
|
break;
|
|
|
|
case WM_MEASUREITEM:
|
|
hDC = GetDC(hDlg);
|
|
|
|
// GetTextMetrics from "Courier New 8" font
|
|
hFont = CreateFont(-MulDiv(8,GetDeviceCaps(hDC, LOGPIXELSY),72),0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET,
|
|
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,_T("Courier New"));
|
|
|
|
hFont = (HFONT) SelectObject(hDC,hFont);
|
|
GetTextMetrics(hDC,&tm);
|
|
hFont = (HFONT) SelectObject(hDC,hFont);
|
|
DeleteObject(hFont);
|
|
|
|
((LPMEASUREITEMSTRUCT) lParam)->itemHeight = tm.tmHeight;
|
|
lCharWidth = tm.tmAveCharWidth;
|
|
|
|
ReleaseDC(hDlg,hDC);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
LRESULT OnToolDebug(VOID) // debugger dialogbox call
|
|
{
|
|
if ((hDlgDebug = CreateDialog(hApp,MAKEINTRESOURCE(IDD_DEBUG),NULL,
|
|
(DLGPROC)Debugger)) == NULL)
|
|
AbortMessage(_T("Debugger Dialog Box Creation Error !"));
|
|
return 0;
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Find dialog box
|
|
//#
|
|
//################
|
|
|
|
static __inline BOOL OnFindOK(HWND hDlg,BOOL bASCII,DWORD *pdwAddrLast,INT nSearchDir)
|
|
{
|
|
HWND hWnd;
|
|
BYTE *lpbySearch;
|
|
INT i,j;
|
|
DWORD dwCnt,dwAddr,dwMapDataMask;
|
|
BOOL bMatch;
|
|
|
|
// searching upwards / downwards
|
|
_ASSERT(nSearchDir == 1 || nSearchDir == -1);
|
|
|
|
hWnd = GetDlgItem(hDlg,IDC_FIND_DATA);
|
|
|
|
dwMapDataMask = GetMemDataMask(); // size mask of data mapping
|
|
|
|
i = GetWindowTextLength(hWnd) + 1; // text length incl. EOS
|
|
j = bASCII ? 2 : sizeof(*(LPTSTR)0); // buffer width
|
|
|
|
// allocate search buffer
|
|
if ((lpbySearch = (LPBYTE) malloc(i * j)) != NULL)
|
|
{
|
|
// get search text and real length
|
|
i = GetWindowText(hWnd,(LPTSTR) lpbySearch,i);
|
|
|
|
// add string to combo box
|
|
if (SendMessage(hWnd,CB_FINDSTRINGEXACT,0,(LPARAM) lpbySearch) == CB_ERR)
|
|
SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) lpbySearch);
|
|
|
|
#if defined _UNICODE
|
|
{
|
|
// Unicode to byte translation
|
|
LPTSTR szTmp = DuplicateString((LPCTSTR) lpbySearch);
|
|
if (szTmp != NULL)
|
|
{
|
|
WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK,
|
|
szTmp, -1,
|
|
(LPSTR) lpbySearch, i+1, NULL, NULL);
|
|
free(szTmp);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// convert input format to nibble based format
|
|
if (bASCII) // ASCII input
|
|
{
|
|
// convert ASCII to number
|
|
for (j = i - 1; j >= 0; --j)
|
|
{
|
|
// order LSB, MSB
|
|
lpbySearch[j * 2 + 1] = lpbySearch[j] >> 4;
|
|
lpbySearch[j * 2] = lpbySearch[j] & 0xF;
|
|
}
|
|
i *= 2; // no. of nibbles
|
|
}
|
|
else // hex number input
|
|
{
|
|
// convert HEX to number
|
|
for (i = 0, j = 0; lpbySearch[j] != 0; ++j)
|
|
{
|
|
if (lpbySearch[j] == ' ') // skip space
|
|
continue;
|
|
|
|
if (isxdigit(lpbySearch[j]))
|
|
{
|
|
lpbySearch[i] = toupper(lpbySearch[j]) - '0';
|
|
if (lpbySearch[i] > 9) lpbySearch[i] -= 'A' - '9' - 1;
|
|
}
|
|
else
|
|
{
|
|
i = 0; // wrong format, no match
|
|
break;
|
|
}
|
|
++i; // inc, no. of nibbles
|
|
}
|
|
}
|
|
|
|
bMatch = FALSE; // no match
|
|
dwAddr = dwAdrMem; // calculate search start address
|
|
if (*pdwAddrLast == dwAddr)
|
|
dwAddr += nSearchDir;
|
|
|
|
// scan mapping/module until match
|
|
for (dwCnt = 0; i && !bMatch && dwCnt <= dwMapDataMask; ++dwCnt)
|
|
{
|
|
BYTE byC;
|
|
|
|
// i = no. of nibbles that have to match
|
|
for (bMatch = TRUE, j = 0;bMatch && j < i; ++j)
|
|
{
|
|
GetMemPeek(&byC,(dwAddr + j) & dwMapDataMask,1);
|
|
bMatch = (byC == lpbySearch[j]);
|
|
}
|
|
dwAddr += nSearchDir;
|
|
}
|
|
free(lpbySearch);
|
|
|
|
// check match result
|
|
if (bMatch)
|
|
{
|
|
// matching address
|
|
dwAddr = (dwAddr - nSearchDir) & dwMapDataMask;
|
|
|
|
// update memory window
|
|
OnMemGoDx(GetParent(hDlg),dwAddr);
|
|
|
|
// update rpl obj view dialog
|
|
UpdateRplObjViewWnd(hDlgRplObjView,dwAddr);
|
|
|
|
*pdwAddrLast = dwAddr; // last matching address
|
|
}
|
|
else
|
|
{
|
|
MessageBox(hDlg,_T("Search string not found!"),_T("Find"),
|
|
MB_APPLMODAL|MB_OK|MB_ICONEXCLAMATION|MB_SETFOREGROUND);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// enter find dialog
|
|
//
|
|
static INT_PTR CALLBACK Find(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static DWORD dwAddrEntry;
|
|
static BOOL bASCII = FALSE;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
CheckDlgButton(hDlg,IDC_FIND_ASCII,bASCII);
|
|
dwAddrEntry = -1;
|
|
return TRUE;
|
|
|
|
case WM_DESTROY:
|
|
hDlgFind = NULL;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_FIND_ASCII: bASCII = !bASCII; return TRUE;
|
|
case IDC_FIND_PREV: return OnFindOK(hDlg,bASCII,&dwAddrEntry,-1);
|
|
case IDC_FIND_NEXT: return OnFindOK(hDlg,bASCII,&dwAddrEntry,1);
|
|
case IDCANCEL: DestroyWindow(hDlg); return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
return FALSE;
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
}
|
|
|
|
static BOOL OnMemFind(HWND hDlg)
|
|
{
|
|
if (hDlgFind == NULL) // no find dialog, create it
|
|
{
|
|
if ((hDlgFind = CreateDialog(hApp,MAKEINTRESOURCE(IDD_FIND),hDlg,
|
|
(DLGPROC)Find)) == NULL)
|
|
AbortMessage(_T("Find Dialog Box Creation Error !"));
|
|
}
|
|
else
|
|
{
|
|
SetFocus(hDlgFind); // set focus on find dialog
|
|
}
|
|
return -1; // call windows default handler
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Profile dialog box
|
|
//#
|
|
//################
|
|
|
|
//
|
|
// update profiler dialog content
|
|
//
|
|
static VOID UpdateProfileWnd(HWND hDlg)
|
|
{
|
|
#define CPU_FREQ 524288 // base CPU frequency
|
|
#define SX_RATE 0x0E
|
|
#define GX_RATE 0x1B
|
|
#define GP_RATE 0x1B*3 // CdB for HP: add high speed apples
|
|
#define G2_RATE 0x1B*2 // CdB for HP: add low speed apples
|
|
|
|
LPCTSTR pcUnit[] = { _T("s"),_T("ms"),_T("us"),_T("ns") };
|
|
|
|
QWORD lVar;
|
|
TCHAR szBuffer[64];
|
|
UINT i;
|
|
DWORD dwFreq, dwEndFreq;
|
|
|
|
if (hDlg == NULL) return; // dialog not open
|
|
|
|
// 64 bit cpu cycle counter
|
|
lVar = *(QWORD *)&Chipset.cycles - *(QWORD *)&OldChipset.cycles;
|
|
|
|
// cycle counts
|
|
_sntprintf(szBuffer,ARRAYSIZEOF(szBuffer),_T("%I64u"),lVar);
|
|
SetDlgItemText(hDlg,IDC_PROFILE_LASTCYCLES,szBuffer);
|
|
|
|
// CPU frequency
|
|
switch (cCurrentRomType) // CdB for HP: add apples speed selection
|
|
{
|
|
case 'S': dwFreq= ((SX_RATE + 1) * CPU_FREQ / 4); break;
|
|
case 'X': case 'G': case 'E': case 'A': dwFreq= ((GX_RATE + 1) * CPU_FREQ / 4); break;
|
|
case 'P': case 'Q': dwFreq= ((GP_RATE + 1) * CPU_FREQ / 4); break;
|
|
case '2': dwFreq= ((G2_RATE + 1) * CPU_FREQ / 4); break;
|
|
}
|
|
dwEndFreq = ((999 * 2 - 1) * dwFreq) / (2 * 1000);
|
|
|
|
// search for ENG unit
|
|
for (i = 0; i < ARRAYSIZEOF(pcUnit) - 1 && lVar <= dwEndFreq; ++i)
|
|
{
|
|
lVar *= 1000; // next ENG unit
|
|
}
|
|
|
|
// calculate rounded time
|
|
lVar = (2 * lVar + dwFreq) / (2 * dwFreq);
|
|
|
|
_ASSERT(i < ARRAYSIZEOF(pcUnit));
|
|
_sntprintf(szBuffer,ARRAYSIZEOF(szBuffer),_T("%I64u %s"),lVar,pcUnit[i]);
|
|
SetDlgItemText(hDlg,IDC_PROFILE_LASTTIME,szBuffer);
|
|
return;
|
|
#undef SX_CLK
|
|
#undef GX_CLK
|
|
#undef GP_RATE
|
|
#undef G2_RATE
|
|
#undef CPU_FREQ
|
|
}
|
|
|
|
//
|
|
// enter profile dialog
|
|
//
|
|
static INT_PTR CALLBACK Profile(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
UpdateProfileWnd(hDlg);
|
|
return TRUE;
|
|
|
|
case WM_DESTROY:
|
|
hDlgProfile = NULL;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDCANCEL: DestroyWindow(hDlg); return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
return FALSE;
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
}
|
|
|
|
static BOOL OnProfile(HWND hDlg)
|
|
{
|
|
if (hDlgProfile == NULL) // no profile dialog, create it
|
|
{
|
|
if ((hDlgProfile = CreateDialog(hApp,MAKEINTRESOURCE(IDD_PROFILE),hDlg,
|
|
(DLGPROC)Profile)) == NULL)
|
|
AbortMessage(_T("Profile Dialog Box Creation Error !"));
|
|
}
|
|
else
|
|
{
|
|
SetFocus(hDlgProfile); // set focus on profile dialog
|
|
}
|
|
return -1; // call windows default handler
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# RPL object viewer dialog box
|
|
//#
|
|
//################
|
|
|
|
//
|
|
// update rpl obj view dialog content
|
|
//
|
|
static VOID UpdateRplObjViewWnd(HWND hDlg, DWORD dwAddr)
|
|
{
|
|
LPTSTR szObjList;
|
|
|
|
if (hDlg == NULL) return; // dialog not open
|
|
|
|
// show entry point name only in mapped mode
|
|
bRplViewName = (GetMemMapType() == MEM_MMU);
|
|
|
|
// create view string
|
|
szObjList = RplCreateObjView(dwAddr,GetMemDataSize(),TRUE);
|
|
SetDlgItemText(hDlg,IDC_RPLVIEW_DATA,szObjList);
|
|
free(szObjList);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// enter RPL object viewer dialog
|
|
//
|
|
static INT_PTR CALLBACK RplObjView(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
switch (cCurrentRomType)
|
|
{
|
|
case 'S': // HP48SX
|
|
dwRplPlatform = RPL_P3; // Charlemagne platform
|
|
break;
|
|
case '6': // HP38G (64K RAM version)
|
|
case 'A': // HP38G
|
|
case 'G': // HP48GX
|
|
dwRplPlatform = RPL_P4; // Alcuin platform
|
|
break;
|
|
case 'E': // HP39G/40G
|
|
case 'X': // HP49G
|
|
dwRplPlatform = RPL_P5; // V'ger platform
|
|
break;
|
|
default:
|
|
_ASSERT(FALSE);
|
|
}
|
|
|
|
bRplViewAddr = TRUE; // show address
|
|
bRplViewBin = TRUE; // show binary data
|
|
return TRUE;
|
|
|
|
case WM_DESTROY:
|
|
hDlgRplObjView = NULL;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDCANCEL: DestroyWindow(hDlg); return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
return FALSE;
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
}
|
|
|
|
static BOOL OnRplObjView(HWND hDlg)
|
|
{
|
|
// get cursor address of memory view
|
|
DWORD dwAddr = GetMemCurAddr(hDlg);
|
|
|
|
if (hDlgRplObjView == NULL) // no rpl obj view dialog, create it
|
|
{
|
|
if ((hDlgRplObjView = CreateDialog(hApp,MAKEINTRESOURCE(IDD_RPLVIEW),hDlg,
|
|
(DLGPROC)RplObjView)) == NULL)
|
|
AbortMessage(_T("RPL Object View Dialog Box Creation Error !"));
|
|
}
|
|
|
|
UpdateRplObjViewWnd(hDlgRplObjView,dwAddr);
|
|
return -1; // call windows default handler
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Settings dialog box
|
|
//#
|
|
//################
|
|
|
|
//
|
|
// copy edit box content to current combox box selection
|
|
//
|
|
static VOID CopyEditToCombo(HWND hDlg,HWND hWndComboBox)
|
|
{
|
|
TCHAR szSymbFilename[MAX_PATH];
|
|
INT i;
|
|
|
|
// get current selection
|
|
if ((i = (INT) SendMessage(hWndComboBox,CB_GETCURSEL,0,0)) != CB_ERR)
|
|
{
|
|
// delete associated name
|
|
free((LPVOID) SendMessage(hWndComboBox,CB_GETITEMDATA,i,0));
|
|
|
|
// append actual name
|
|
GetDlgItemText(hDlg,IDC_DEBUG_SET_FILE,szSymbFilename,ARRAYSIZEOF(szSymbFilename));
|
|
SendMessage(hWndComboBox,CB_SETITEMDATA,i,(LPARAM) DuplicateString(szSymbFilename));
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// copy edit box content to current combox box selection
|
|
//
|
|
static VOID CopyComboToEdit(HWND hDlg,HWND hWndComboBox)
|
|
{
|
|
HWND hWnd;
|
|
INT i;
|
|
|
|
// get current selection
|
|
if ((i = (INT) SendMessage(hWndComboBox,CB_GETCURSEL,0,0)) != CB_ERR)
|
|
{
|
|
// update file edit box
|
|
hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_FILE);
|
|
SetWindowText(hWnd,(LPTSTR) SendMessage(hWndComboBox,CB_GETITEMDATA,i,0));
|
|
SendMessage(hWnd,EM_SETSEL,0,-1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// settings browse dialog
|
|
//
|
|
static BOOL OnBrowseSettings(HWND hDlg, HWND hWndFilename)
|
|
{
|
|
TCHAR szBuffer[MAX_PATH];
|
|
OPENFILENAME ofn;
|
|
|
|
ZeroMemory(&ofn, sizeof(OPENFILENAME));
|
|
ofn.lStructSize = sizeof(OPENFILENAME);
|
|
ofn.hwndOwner = hDlg;
|
|
ofn.lpstrFilter =
|
|
_T("HP-Tools Linker File (*.O)\0*.O\0")
|
|
_T("All Files (*.*)\0*.*\0");
|
|
ofn.lpstrDefExt = _T("O");
|
|
ofn.nFilterIndex = 1;
|
|
ofn.lpstrFile = szBuffer;
|
|
ofn.lpstrFile[0] = 0;
|
|
ofn.nMaxFile = ARRAYSIZEOF(szBuffer);
|
|
ofn.Flags = OFN_EXPLORER|OFN_HIDEREADONLY|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST;
|
|
if (GetOpenFileName(&ofn))
|
|
{
|
|
SetWindowText(hWndFilename,szBuffer);
|
|
SendMessage(hWndFilename,EM_SETSEL,0,-1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// enter settings dialog
|
|
//
|
|
static INT_PTR CALLBACK Settings(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HWND hWnd;
|
|
TCHAR szSymbFilename[MAX_PATH];
|
|
TCHAR szItemname[16];
|
|
INT i,nMax;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
// set disassembler mode
|
|
CheckDlgButton(hDlg,(disassembler_mode == HP_MNEMONICS) ? IDC_DISASM_HP : IDC_DISASM_CLASS,BST_CHECKED);
|
|
// set symbolic enable check button
|
|
CheckDlgButton(hDlg,IDC_DEBUG_SET_SYMB,disassembler_symb);
|
|
// fill model combo box and corresponding file edit box
|
|
{
|
|
LPCTSTR lpszModels;
|
|
TCHAR cModel[] = _T(" ");
|
|
|
|
// fill model combo box
|
|
hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_MODEL);
|
|
for (lpszModels = _T(MODELS); *lpszModels != 0; ++lpszModels)
|
|
{
|
|
cModel[0] = *lpszModels; // string with model character
|
|
i = (INT) SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) cModel);
|
|
|
|
// get filename
|
|
wsprintf(szItemname,_T("Symb%c"),cModel[0]);
|
|
ReadSettingsString(_T("Disassembler"),szItemname,_T(""),szSymbFilename,ARRAYSIZEOF(szSymbFilename));
|
|
|
|
// append filename to model
|
|
SendMessage(hWnd,CB_SETITEMDATA,i,(LPARAM) DuplicateString(szSymbFilename));
|
|
}
|
|
|
|
// select for actual model
|
|
cModel[0] = (TCHAR) cCurrentRomType;
|
|
if ((i = (INT) SendMessage(hWnd,CB_SELECTSTRING,0,(LPARAM) cModel)) != CB_ERR)
|
|
{
|
|
LPTSTR lpszFilename = (LPTSTR) SendMessage(hWnd,CB_GETITEMDATA,i,0);
|
|
|
|
// fill file edit box
|
|
hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_FILE);
|
|
SetWindowText(hWnd,lpszFilename);
|
|
SendMessage(hWnd,EM_SETSEL,0,-1);
|
|
}
|
|
}
|
|
return TRUE;
|
|
case WM_COMMAND:
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_DEBUG_SET_MODEL:
|
|
// combo box changing item
|
|
if (HIWORD(wParam) == CBN_SETFOCUS)
|
|
{
|
|
// update associated name with file edit box
|
|
CopyEditToCombo(hDlg,(HWND) lParam);
|
|
}
|
|
// new combo box item selected
|
|
if (HIWORD(wParam) == CBN_SELENDOK)
|
|
{
|
|
// update file edit box with associated name
|
|
CopyComboToEdit(hDlg,(HWND) lParam);
|
|
}
|
|
break;
|
|
case IDC_DEBUG_SET_BROWSE:
|
|
return OnBrowseSettings(hDlg,GetDlgItem(hDlg,IDC_DEBUG_SET_FILE));
|
|
case IDOK:
|
|
// set disassembler mode
|
|
disassembler_mode = IsDlgButtonChecked(hDlg,IDC_DISASM_HP) ? HP_MNEMONICS : CLASS_MNEMONICS;
|
|
// set symbolic enable check button
|
|
disassembler_symb = IsDlgButtonChecked(hDlg,IDC_DEBUG_SET_SYMB);
|
|
// update associated name with file edit box
|
|
hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_MODEL);
|
|
CopyEditToCombo(hDlg,hWnd);
|
|
// write all symbol filenames to registry
|
|
nMax = (INT) SendMessage(hWnd,CB_GETCOUNT,0,0);
|
|
for (i = 0; i < nMax; ++i)
|
|
{
|
|
LPTSTR lpszFilename;
|
|
|
|
SendMessage(hWnd,CB_GETLBTEXT,i,(LPARAM) szSymbFilename);
|
|
wsprintf(szItemname,_T("Symb%c"),szSymbFilename[0]);
|
|
lpszFilename = (LPTSTR) SendMessage(hWnd,CB_GETITEMDATA,i,0);
|
|
if (*lpszFilename == 0) // empty
|
|
{
|
|
DelSettingsKey(_T("Disassembler"),szItemname);
|
|
}
|
|
else
|
|
{
|
|
WriteSettingsString(_T("Disassembler"),szItemname,lpszFilename);
|
|
}
|
|
}
|
|
RplDeleteTable(); // delete rpl symbol table
|
|
LoadSymbTable(); // reload external rpl symbol table
|
|
// redraw debugger code view
|
|
ViewCodeWnd(GetDlgItem(GetParent(hDlg),IDC_DEBUG_CODE),dwAdrLine[0]);
|
|
// no break
|
|
case IDCANCEL:
|
|
// free combo box items
|
|
hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_MODEL);
|
|
nMax = (INT) SendMessage(hWnd,CB_GETCOUNT,0,0);
|
|
for (i = 0; i < nMax; ++i)
|
|
{
|
|
LPTSTR lpszFilename = (LPTSTR) SendMessage(hWnd,CB_GETITEMDATA,i,0);
|
|
if (lpszFilename != NULL)
|
|
{
|
|
free(lpszFilename);
|
|
}
|
|
}
|
|
EndDialog(hDlg,LOWORD(wParam));
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
}
|
|
|
|
static BOOL OnSettings(HWND hDlg)
|
|
{
|
|
if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DEBUG_SETTINGS), hDlg, (DLGPROC)Settings) == -1)
|
|
AbortMessage(_T("Settings Dialog Box Creation Error !"));
|
|
return 0;
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# New Value dialog box
|
|
//#
|
|
//################
|
|
|
|
//
|
|
// enter new value dialog
|
|
//
|
|
static INT_PTR CALLBACK NewValue(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static LPTSTR lpszBuffer; // handle of buffer
|
|
static int nBufferlen; // length of buffer
|
|
|
|
HWND hWnd;
|
|
TCHAR szBuffer[64];
|
|
LONG i;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
lpszBuffer = (LPTSTR) lParam;
|
|
// length with zero string terminator
|
|
nBufferlen = lstrlen(lpszBuffer)+1;
|
|
_ASSERT(ARRAYSIZEOF(szBuffer) >= nBufferlen);
|
|
SetDlgItemText(hDlg,IDC_NEWVALUE,lpszBuffer);
|
|
return TRUE;
|
|
case WM_COMMAND:
|
|
wParam = LOWORD(wParam);
|
|
switch(wParam)
|
|
{
|
|
case IDOK:
|
|
hWnd = GetDlgItem(hDlg,IDC_NEWVALUE);
|
|
GetWindowText(hWnd,szBuffer,nBufferlen);
|
|
// test if valid hex address
|
|
for (i = 0; i < (LONG) lstrlen(szBuffer); ++i)
|
|
{
|
|
if (_istxdigit(szBuffer[i]) == 0)
|
|
{
|
|
SendMessage(hWnd,EM_SETSEL,0,-1);
|
|
SetFocus(hWnd); // focus to edit control
|
|
return FALSE;
|
|
}
|
|
}
|
|
lstrcpy(lpszBuffer,szBuffer); // copy valid value
|
|
// no break
|
|
case IDCANCEL:
|
|
EndDialog(hDlg,wParam);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static INT_PTR OnNewValue(LPTSTR lpszValue)
|
|
{
|
|
INT_PTR nResult;
|
|
|
|
if ((nResult = DialogBoxParam(hApp,
|
|
MAKEINTRESOURCE(IDD_NEWVALUE),
|
|
hDlgDebug,
|
|
(DLGPROC)NewValue,
|
|
(LPARAM)lpszValue)
|
|
) == -1)
|
|
AbortMessage(_T("Input Dialog Box Creation Error !"));
|
|
return nResult;
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Goto Address dialog box
|
|
//#
|
|
//################
|
|
|
|
//
|
|
// enter goto address dialog
|
|
//
|
|
static INT_PTR CALLBACK EnterAddr(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
SetWindowLongPtr(hDlg,GWLP_USERDATA,(LONG_PTR) lParam);
|
|
return TRUE;
|
|
case WM_COMMAND:
|
|
wParam = LOWORD(wParam);
|
|
switch(wParam)
|
|
{
|
|
case IDOK:
|
|
if (!GetAddr(hDlg,
|
|
IDC_ENTERADR,
|
|
(DWORD *) GetWindowLongPtr(hDlg,GWLP_USERDATA),
|
|
0xFFFFFFFF,
|
|
disassembler_symb))
|
|
return FALSE;
|
|
// no break
|
|
case IDCANCEL:
|
|
EndDialog(hDlg,wParam);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static VOID OnEnterAddress(HWND hDlg, DWORD *dwValue)
|
|
{
|
|
if (DialogBoxParam(hApp, MAKEINTRESOURCE(IDD_ENTERADR), hDlg, (DLGPROC)EnterAddr, (LPARAM)dwValue) == -1)
|
|
AbortMessage(_T("Address Dialog Box Creation Error !"));
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Breakpoint dialog box
|
|
//#
|
|
//################
|
|
|
|
//
|
|
// enter breakpoint dialog
|
|
//
|
|
static INT_PTR CALLBACK EnterBreakpoint(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static BP_T *sBp;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
sBp = (BP_T *) lParam;
|
|
sBp->bEnable = TRUE;
|
|
sBp->nType = BP_EXEC;
|
|
SendDlgItemMessage(hDlg,IDC_BPCODE,BM_SETCHECK,1,0);
|
|
return TRUE;
|
|
case WM_COMMAND:
|
|
wParam = LOWORD(wParam);
|
|
switch(wParam)
|
|
{
|
|
case IDC_BPCODE: sBp->nType = BP_EXEC; return TRUE;
|
|
case IDC_BPRPL: sBp->nType = BP_RPL; return TRUE;
|
|
case IDC_BPACCESS: sBp->nType = BP_ACCESS; return TRUE;
|
|
case IDC_BPREAD: sBp->nType = BP_READ; return TRUE;
|
|
case IDC_BPWRITE: sBp->nType = BP_WRITE; return TRUE;
|
|
case IDOK:
|
|
if (!GetAddr(hDlg,IDC_ENTERADR,&sBp->dwAddr,0xFFFFF,disassembler_symb))
|
|
return FALSE;
|
|
// no break
|
|
case IDCANCEL:
|
|
EndDialog(hDlg,wParam);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static VOID OnEnterBreakpoint(HWND hDlg, BP_T *sValue)
|
|
{
|
|
if (DialogBoxParam(hApp, MAKEINTRESOURCE(IDD_ENTERBREAK), hDlg, (DLGPROC)EnterBreakpoint, (LPARAM)sValue) == -1)
|
|
AbortMessage(_T("Breakpoint Dialog Box Creation Error !"));
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Edit breakpoint dialog box
|
|
//#
|
|
//################
|
|
|
|
//
|
|
// handle drawing in breakpoint window
|
|
//
|
|
static __inline BOOL OnDrawBreakWnd(LPDRAWITEMSTRUCT lpdis)
|
|
{
|
|
TCHAR szBuf[64];
|
|
COLORREF crBkColor,crTextColor;
|
|
HDC hdcMem;
|
|
HBITMAP hBmpOld;
|
|
|
|
if (lpdis->itemID == -1) // no item in list box
|
|
return TRUE;
|
|
|
|
crBkColor = GetBkColor(lpdis->hDC); // save actual color settings
|
|
crTextColor = GetTextColor(lpdis->hDC);
|
|
|
|
if (lpdis->itemState & ODS_SELECTED) // cursor line
|
|
{
|
|
SetBkColor(lpdis->hDC,GetSysColor(COLOR_HIGHLIGHT));
|
|
SetTextColor(lpdis->hDC,GetSysColor(COLOR_HIGHLIGHTTEXT));
|
|
}
|
|
|
|
// write Text
|
|
SendMessage(lpdis->hwndItem,LB_GETTEXT,lpdis->itemID,(LPARAM) szBuf);
|
|
ExtTextOut(lpdis->hDC,(int)(lpdis->rcItem.left)+17,(int)(lpdis->rcItem.top),
|
|
ETO_OPAQUE,(LPRECT)&lpdis->rcItem,szBuf,lstrlen(szBuf),NULL);
|
|
|
|
SetBkColor(lpdis->hDC,crBkColor); // restore color settings
|
|
SetTextColor(lpdis->hDC,crTextColor);
|
|
|
|
// draw checkbox
|
|
hdcMem = CreateCompatibleDC(lpdis->hDC);
|
|
_ASSERT(hBmpCheckBox);
|
|
hBmpOld = (HBITMAP) SelectObject(hdcMem,hBmpCheckBox);
|
|
|
|
BitBlt(lpdis->hDC,lpdis->rcItem.left+2,lpdis->rcItem.top+2,
|
|
11,lpdis->rcItem.bottom - lpdis->rcItem.top,
|
|
hdcMem,sBreakpoint[lpdis->itemData].bEnable ? 0 : 10,0,SRCCOPY);
|
|
|
|
SelectObject(hdcMem,hBmpOld);
|
|
DeleteDC(hdcMem);
|
|
|
|
if (lpdis->itemState & ODS_FOCUS) // redraw focus
|
|
DrawFocusRect(lpdis->hDC,&lpdis->rcItem);
|
|
|
|
return TRUE; // focus handled here
|
|
}
|
|
|
|
//
|
|
// toggle breakpoint drawing
|
|
//
|
|
static BOOL ToggleBreakpointItem(HWND hWnd, INT nItem)
|
|
{
|
|
RECT rc;
|
|
|
|
// get breakpoint number
|
|
INT i = (INT) SendMessage(hWnd,LB_GETITEMDATA,nItem,0);
|
|
|
|
sBreakpoint[i].bEnable = !sBreakpoint[i].bEnable;
|
|
// update region of toggled item
|
|
SendMessage(hWnd,LB_GETITEMRECT,nItem,(LPARAM)&rc);
|
|
InvalidateRect(hWnd,&rc,TRUE);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// draw breakpoint type
|
|
//
|
|
static VOID DrawBreakpoint(HWND hWnd, INT i)
|
|
{
|
|
TCHAR *szText,szBuffer[32];
|
|
INT nItem;
|
|
|
|
switch(sBreakpoint[i].nType)
|
|
{
|
|
case BP_EXEC: // code breakpoint
|
|
szText = _T("Code");
|
|
break;
|
|
case BP_RPL: // RPL breakpoint
|
|
szText = _T("RPL");
|
|
break;
|
|
case BP_READ: // read memory breakpoint
|
|
szText = _T("Memory Read");
|
|
break;
|
|
case BP_WRITE: // write memory breakpoint
|
|
szText = _T("Memory Write");
|
|
break;
|
|
case BP_ACCESS: // memory breakpoint
|
|
szText = _T("Memory Access");
|
|
break;
|
|
default: // unknown breakpoint type
|
|
szText = _T("unknown");
|
|
_ASSERT(0);
|
|
}
|
|
wsprintf(szBuffer,_T("%05X (%s)"),sBreakpoint[i].dwAddr,szText);
|
|
nItem = (INT) SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer);
|
|
SendMessage(hWnd,LB_SETITEMDATA,nItem,i);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// enter edit breakpoint dialog
|
|
//
|
|
static INT_PTR CALLBACK EditBreakpoint(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
TEXTMETRIC tm;
|
|
|
|
HWND hWnd;
|
|
HDC hDC;
|
|
HFONT hFont;
|
|
BP_T sBp;
|
|
INT i,nItem;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
// font settings
|
|
SendDlgItemMessage(hDlg,IDC_STATIC_BREAKPOINT,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
|
|
SendDlgItemMessage(hDlg,IDC_BREAKEDIT_ADD, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
|
|
SendDlgItemMessage(hDlg,IDC_BREAKEDIT_DELETE, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
|
|
SendDlgItemMessage(hDlg,IDCANCEL, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
|
|
|
|
hBmpCheckBox = LoadBitmap(hApp,MAKEINTRESOURCE(IDB_CHECKBOX));
|
|
_ASSERT(hBmpCheckBox);
|
|
|
|
hWnd = GetDlgItem(hDlg,IDC_BREAKEDIT_WND);
|
|
SendMessage(hWnd,WM_SETREDRAW,FALSE,0);
|
|
SendMessage(hWnd,LB_RESETCONTENT,0,0);
|
|
for (i = 0; i < wBreakpointCount; ++i)
|
|
DrawBreakpoint(hWnd,i);
|
|
SendMessage(hWnd,WM_SETREDRAW,TRUE,0);
|
|
return TRUE;
|
|
|
|
case WM_DESTROY:
|
|
DeleteObject(hBmpCheckBox);
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
hWnd = GetDlgItem(hDlg,IDC_BREAKEDIT_WND);
|
|
switch (HIWORD(wParam))
|
|
{
|
|
case LBN_DBLCLK:
|
|
if (LOWORD(wParam) == IDC_BREAKEDIT_WND)
|
|
{
|
|
if ((nItem = (INT) SendMessage(hWnd,LB_GETCURSEL,0,0)) == LB_ERR)
|
|
return FALSE;
|
|
|
|
return ToggleBreakpointItem(hWnd,nItem);
|
|
}
|
|
}
|
|
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_BREAKEDIT_ADD:
|
|
sBp.dwAddr = -1; // no breakpoint given
|
|
OnEnterBreakpoint(hDlg, &sBp);
|
|
if (sBp.dwAddr != -1)
|
|
{
|
|
for (i = 0; i < wBreakpointCount; ++i)
|
|
{
|
|
if (sBreakpoint[i].dwAddr == sBp.dwAddr)
|
|
{
|
|
// tried to add used code breakpoint
|
|
if (sBreakpoint[i].bEnable && (sBreakpoint[i].nType & sBp.nType & (BP_EXEC | BP_RPL)) != 0)
|
|
return FALSE;
|
|
|
|
// only modify memory breakpoints
|
|
if ( ( sBreakpoint[i].bEnable == FALSE
|
|
&& (sBreakpoint[i].nType & sBp.nType & (BP_EXEC | BP_RPL)) != 0)
|
|
|| ((sBreakpoint[i].nType & BP_ACCESS) && (sBp.nType & BP_ACCESS)))
|
|
{
|
|
// replace breakpoint type
|
|
sBreakpoint[i].bEnable = TRUE;
|
|
sBreakpoint[i].nType = sBp.nType;
|
|
|
|
// redaw breakpoint list
|
|
SendMessage(hWnd,WM_SETREDRAW,FALSE,0);
|
|
SendMessage(hWnd,LB_RESETCONTENT,0,0);
|
|
for (i = 0; i < wBreakpointCount; ++i)
|
|
DrawBreakpoint(hWnd,i);
|
|
SendMessage(hWnd,WM_SETREDRAW,TRUE,0);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// check for breakpoint buffer full
|
|
if (wBreakpointCount >= MAXBREAKPOINTS)
|
|
{
|
|
AbortMessage(_T("Reached maximum number of breakpoints !"));
|
|
return FALSE;
|
|
}
|
|
|
|
sBreakpoint[wBreakpointCount].bEnable = sBp.bEnable;
|
|
sBreakpoint[wBreakpointCount].nType = sBp.nType;
|
|
sBreakpoint[wBreakpointCount].dwAddr = sBp.dwAddr;
|
|
|
|
DrawBreakpoint(hWnd,wBreakpointCount);
|
|
|
|
++wBreakpointCount;
|
|
}
|
|
return TRUE;
|
|
|
|
case IDC_BREAKEDIT_DELETE:
|
|
// scan all breakpoints from top
|
|
for (nItem = wBreakpointCount-1; nItem >= 0; --nItem)
|
|
{
|
|
// item selected
|
|
if (SendMessage(hWnd,LB_GETSEL,nItem,0) > 0)
|
|
{
|
|
INT j;
|
|
|
|
// get breakpoint index
|
|
i = (INT) SendMessage(hWnd,LB_GETITEMDATA,nItem,0);
|
|
SendMessage(hWnd,LB_DELETESTRING,nItem,0);
|
|
--wBreakpointCount;
|
|
|
|
// update remaining list box references
|
|
for (j = 0; j < wBreakpointCount; ++j)
|
|
{
|
|
INT k = (INT) SendMessage(hWnd,LB_GETITEMDATA,j,0);
|
|
if (k > i) SendMessage(hWnd,LB_SETITEMDATA,j,k-1);
|
|
}
|
|
|
|
// remove breakpoint from breakpoint table
|
|
while (++i <= wBreakpointCount)
|
|
sBreakpoint[i-1] = sBreakpoint[i];
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
case IDCANCEL:
|
|
EndDialog(hDlg,IDCANCEL);
|
|
return TRUE;
|
|
}
|
|
|
|
case WM_VKEYTOITEM:
|
|
if (LOWORD(wParam) == VK_SPACE)
|
|
{
|
|
hWnd = GetDlgItem(hDlg,IDC_BREAKEDIT_WND);
|
|
for (nItem = 0; nItem < wBreakpointCount; ++nItem)
|
|
{
|
|
// item selected
|
|
if (SendMessage(hWnd,LB_GETSEL,nItem,0) > 0)
|
|
ToggleBreakpointItem(hWnd,nItem);
|
|
}
|
|
return -2;
|
|
}
|
|
return -1; // default action
|
|
|
|
case WM_DRAWITEM:
|
|
if (wParam == IDC_BREAKEDIT_WND) return OnDrawBreakWnd((LPDRAWITEMSTRUCT) lParam);
|
|
break;
|
|
|
|
case WM_MEASUREITEM:
|
|
hDC = GetDC(hDlg);
|
|
|
|
// GetTextMetrics from "Courier New 8" font
|
|
hFont = CreateFont(-MulDiv(8,GetDeviceCaps(hDC, LOGPIXELSY),72),0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET,
|
|
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,_T("Courier New"));
|
|
|
|
hFont = (HFONT) SelectObject(hDC,hFont);
|
|
GetTextMetrics(hDC,&tm);
|
|
hFont = (HFONT) SelectObject(hDC,hFont);
|
|
DeleteObject(hFont);
|
|
|
|
((LPMEASUREITEMSTRUCT) lParam)->itemHeight = tm.tmHeight;
|
|
|
|
ReleaseDC(hDlg,hDC);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
}
|
|
|
|
static BOOL OnEditBreakpoint(HWND hDlg)
|
|
{
|
|
if (DialogBox(hApp, MAKEINTRESOURCE(IDD_BREAKEDIT), hDlg, (DLGPROC)EditBreakpoint) == -1)
|
|
AbortMessage(_T("Edit Breakpoint Dialog Box Creation Error !"));
|
|
|
|
// update code window
|
|
InvalidateRect(GetDlgItem(hDlg,IDC_DEBUG_CODE),NULL,TRUE);
|
|
return -1;
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Last Instruction dialog box
|
|
//#
|
|
//################
|
|
|
|
//
|
|
// view last instructions
|
|
//
|
|
static INT_PTR CALLBACK InfoIntr(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HWND hWnd;
|
|
TCHAR szBuffer[64];
|
|
LONG lIndex;
|
|
WORD i,j;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
// font settings
|
|
SendDlgItemMessage(hDlg,IDC_INSTR_TEXT, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
|
|
SendDlgItemMessage(hDlg,IDC_INSTR_CLEAR, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
|
|
SendDlgItemMessage(hDlg,IDC_INSTR_COPY, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
|
|
SendDlgItemMessage(hDlg,IDCANCEL, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
|
|
|
|
lIndex = 0; // init lIndex
|
|
hWnd = GetDlgItem(hDlg,IDC_INSTR_CODE);
|
|
SendMessage(hWnd,WM_SETREDRAW,FALSE,0);
|
|
SendMessage(hWnd,LB_RESETCONTENT,0,0);
|
|
for (i = wInstrRp; i != wInstrWp; i = (i + 1) % wInstrSize)
|
|
{
|
|
LPCTSTR lpszName;
|
|
|
|
// entry has a name
|
|
if (disassembler_symb && (lpszName = RplGetName(pdwInstrArray[i])) != NULL)
|
|
{
|
|
szBuffer[0] = _T('=');
|
|
lstrcpyn(&szBuffer[1],lpszName,ARRAYSIZEOF(szBuffer)-1);
|
|
SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer);
|
|
}
|
|
|
|
j = wsprintf(szBuffer,_T("%05lX "),pdwInstrArray[i]);
|
|
disassemble(pdwInstrArray[i],&szBuffer[j]);
|
|
lIndex = (LONG) SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer);
|
|
}
|
|
SendMessage(hWnd,WM_SETREDRAW,TRUE,0);
|
|
SendMessage(hWnd,LB_SETCARETINDEX,lIndex,TRUE);
|
|
return TRUE;
|
|
case WM_COMMAND:
|
|
hWnd = GetDlgItem(hDlg,IDC_INSTR_CODE);
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_INSTR_COPY:
|
|
CopyItemsToClipboard(hWnd); // copy selected items to clipboard
|
|
return TRUE;
|
|
case IDC_INSTR_CLEAR: // clear instruction buffer
|
|
wInstrRp = wInstrWp;
|
|
SendMessage(hWnd,LB_RESETCONTENT,0,0);
|
|
return TRUE;
|
|
case IDCANCEL:
|
|
EndDialog(hDlg,IDCANCEL);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
}
|
|
|
|
static BOOL OnInfoIntr(HWND hDlg)
|
|
{
|
|
if (DialogBox(hApp, MAKEINTRESOURCE(IDD_INSTRUCTIONS), hDlg, (DLGPROC)InfoIntr) == -1)
|
|
AbortMessage(_T("Last Instructions Dialog Box Creation Error !"));
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// view write only I/O registers
|
|
//
|
|
static INT_PTR CALLBACK InfoWoRegister(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
TCHAR szBuffer[8];
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
wsprintf(szBuffer,_T("%05X"),Chipset.start1);
|
|
SetDlgItemText(hDlg,IDC_ADDR20_24,szBuffer);
|
|
wsprintf(szBuffer,_T("%03X"),Chipset.loffset);
|
|
SetDlgItemText(hDlg,IDC_ADDR25_27,szBuffer);
|
|
wsprintf(szBuffer,_T("%02X"),Chipset.lcounter);
|
|
SetDlgItemText(hDlg,IDC_ADDR28_29,szBuffer);
|
|
wsprintf(szBuffer,_T("%05X"),Chipset.start2);
|
|
SetDlgItemText(hDlg,IDC_ADDR30_34,szBuffer);
|
|
return TRUE;
|
|
case WM_COMMAND:
|
|
if ((LOWORD(wParam) == IDCANCEL))
|
|
{
|
|
EndDialog(hDlg,IDCANCEL);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
}
|
|
|
|
static BOOL OnInfoWoRegister(HWND hDlg)
|
|
{
|
|
if (DialogBox(hApp, MAKEINTRESOURCE(IDD_WRITEONLYREG), hDlg, (DLGPROC)InfoWoRegister) == -1)
|
|
AbortMessage(_T("Write-Only Register Dialog Box Creation Error !"));
|
|
return 0;
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Breakpoint list operations
|
|
//#
|
|
//################
|
|
|
|
//
|
|
// load breakpoint list
|
|
//
|
|
VOID LoadBreakpointList(HANDLE hFile) // NULL = clear breakpoint list
|
|
{
|
|
DWORD lBytesRead = 0;
|
|
|
|
// read number of breakpoints
|
|
if (hFile) ReadFile(hFile, &wBreakpointCount, sizeof(wBreakpointCount), &lBytesRead, NULL);
|
|
|
|
// breakpoints found
|
|
if (lBytesRead == sizeof(wBreakpointCount) && wBreakpointCount < ARRAYSIZEOF(sBreakpoint))
|
|
{
|
|
WORD wBreakpointSize;
|
|
|
|
// read size of one breakpoint
|
|
ReadFile(hFile, &wBreakpointSize, sizeof(wBreakpointSize), &lBytesRead, NULL);
|
|
if (lBytesRead == sizeof(wBreakpointSize) && wBreakpointSize == sizeof(sBreakpoint[0]))
|
|
{
|
|
// read breakpoints
|
|
ReadFile(hFile, sBreakpoint, wBreakpointCount * sizeof(sBreakpoint[0]), &lBytesRead, NULL);
|
|
_ASSERT(lBytesRead == wBreakpointCount * sizeof(sBreakpoint[0]));
|
|
}
|
|
else // changed breakpoint structure
|
|
{
|
|
wBreakpointCount = 0; // clear breakpoint list
|
|
}
|
|
}
|
|
else // no breakpoints or breakpoint buffer too small
|
|
{
|
|
wBreakpointCount = 0; // clear breakpoint list
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// save breakpoint list
|
|
//
|
|
VOID SaveBreakpointList(HANDLE hFile)
|
|
{
|
|
if (wBreakpointCount) // defined breakpoints
|
|
{
|
|
DWORD lBytesWritten;
|
|
|
|
WORD wBreakpointSize = sizeof(sBreakpoint[0]);
|
|
|
|
_ASSERT(hFile); // valid file pointer?
|
|
|
|
// write number of breakpoints
|
|
WriteFile(hFile, &wBreakpointCount, sizeof(wBreakpointCount), &lBytesWritten, NULL);
|
|
_ASSERT(lBytesWritten == sizeof(wBreakpointCount));
|
|
|
|
// write size of one breakpoint
|
|
WriteFile(hFile, &wBreakpointSize, sizeof(wBreakpointSize), &lBytesWritten, NULL);
|
|
_ASSERT(lBytesWritten == sizeof(wBreakpointSize));
|
|
|
|
// write breakpoints
|
|
WriteFile(hFile, sBreakpoint, wBreakpointCount * sizeof(sBreakpoint[0]), &lBytesWritten, NULL);
|
|
_ASSERT(lBytesWritten == wBreakpointCount * sizeof(sBreakpoint[0]));
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// create a copy of the breakpoint list
|
|
//
|
|
VOID CreateBackupBreakpointList(VOID)
|
|
{
|
|
_ASSERT(sizeof(sBackupBreakpoint) == sizeof(sBreakpoint));
|
|
|
|
wBackupBreakpointCount = wBreakpointCount;
|
|
|
|
if (wBreakpointCount > 0) // list not empty
|
|
{
|
|
CopyMemory(sBackupBreakpoint,sBreakpoint,sizeof(sBackupBreakpoint));
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// restore the breakpoint list from the copy
|
|
//
|
|
VOID RestoreBackupBreakpointList(VOID)
|
|
{
|
|
_ASSERT(sizeof(sBackupBreakpoint) == sizeof(sBreakpoint));
|
|
|
|
wBreakpointCount = wBackupBreakpointCount;
|
|
|
|
if (wBreakpointCount > 0) // list not empty
|
|
{
|
|
CopyMemory(sBreakpoint,sBackupBreakpoint,sizeof(sBreakpoint));
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Load/Save Memory Data
|
|
//#
|
|
//################
|
|
|
|
static BOOL OnBrowseLoadMem(HWND hDlg)
|
|
{
|
|
TCHAR szBuffer[MAX_PATH];
|
|
OPENFILENAME ofn;
|
|
|
|
ZeroMemory(&ofn, sizeof(OPENFILENAME));
|
|
ofn.lStructSize = sizeof(OPENFILENAME);
|
|
ofn.hwndOwner = hDlg;
|
|
ofn.lpstrFilter =
|
|
_T("Memory Dump Files (*.MEM)\0*.MEM\0")
|
|
_T("All Files (*.*)\0*.*\0");
|
|
ofn.lpstrDefExt = _T("MEM");
|
|
ofn.nFilterIndex = 1;
|
|
ofn.lpstrFile = szBuffer;
|
|
ofn.lpstrFile[0] = 0;
|
|
ofn.nMaxFile = ARRAYSIZEOF(szBuffer);
|
|
ofn.Flags = OFN_EXPLORER|OFN_HIDEREADONLY|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST;
|
|
if (GetOpenFileName(&ofn))
|
|
{
|
|
SetDlgItemText(hDlg,IDC_DEBUG_DATA_FILE,szBuffer);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static BOOL OnBrowseSaveMem(HWND hDlg)
|
|
{
|
|
TCHAR szBuffer[MAX_PATH];
|
|
OPENFILENAME ofn;
|
|
|
|
ZeroMemory(&ofn, sizeof(OPENFILENAME));
|
|
ofn.lStructSize = sizeof(OPENFILENAME);
|
|
ofn.hwndOwner = hDlg;
|
|
ofn.lpstrFilter =
|
|
_T("Memory Dump Files (*.MEM)\0*.MEM\0")
|
|
_T("All Files (*.*)\0*.*\0");
|
|
ofn.lpstrDefExt = _T("MEM");
|
|
ofn.nFilterIndex = 1;
|
|
ofn.lpstrFile = szBuffer;
|
|
ofn.lpstrFile[0] = 0;
|
|
ofn.nMaxFile = ARRAYSIZEOF(szBuffer);
|
|
ofn.Flags = OFN_EXPLORER|OFN_HIDEREADONLY|OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT;
|
|
if (GetSaveFileName(&ofn))
|
|
{
|
|
SetDlgItemText(hDlg,IDC_DEBUG_DATA_FILE,szBuffer);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// write file to memory
|
|
//
|
|
static BOOL LoadMemData(LPCTSTR lpszFilename,DWORD dwStartAddr)
|
|
{
|
|
HANDLE hFile;
|
|
DWORD dwRead;
|
|
BYTE byData;
|
|
|
|
hFile = CreateFile(lpszFilename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE) // error, couldn't create a new file
|
|
return FALSE;
|
|
|
|
while (dwStartAddr <= 0xFFFFF) // read until EOF or end of Saturn address space
|
|
{
|
|
ReadFile(hFile,&byData,sizeof(byData),&dwRead,NULL);
|
|
if (dwRead == 0) break; // EOF
|
|
|
|
if (dwStartAddr < 0xFFFFF)
|
|
{
|
|
Write2(dwStartAddr,byData); // write byte in map mode
|
|
dwStartAddr += 2;
|
|
}
|
|
else // special handling to avoid address wrap around
|
|
{
|
|
byData &= 0xF;
|
|
Nwrite(&byData,dwStartAddr,1); // write nibble in map mode
|
|
++dwStartAddr;
|
|
}
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// write memory data to file
|
|
//
|
|
static BOOL SaveMemData(LPCTSTR lpszFilename,DWORD dwStartAddr,DWORD dwEndAddr)
|
|
{
|
|
HANDLE hFile;
|
|
DWORD dwAddr,dwWritten;
|
|
BYTE byData;
|
|
|
|
hFile = CreateFile(lpszFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE) // error, couldn't create a new file
|
|
return FALSE;
|
|
|
|
for (dwAddr = dwStartAddr; dwAddr <= dwEndAddr; dwAddr += 2)
|
|
{
|
|
_ASSERT(dwAddr <= 0xFFFFF);
|
|
byData = Read2(dwAddr); // read byte in map mode
|
|
WriteFile(hFile,&byData,sizeof(byData),&dwWritten,NULL);
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// memory load data
|
|
//
|
|
static INT_PTR CALLBACK DebugMemLoad(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
TCHAR szFilename[MAX_PATH];
|
|
DWORD dwStartAddr;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_COMMAND:
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_DEBUG_DATA_BUT:
|
|
return OnBrowseLoadMem(hDlg);
|
|
|
|
case IDOK:
|
|
dwStartAddr = -1; // no address given
|
|
|
|
// get filename
|
|
GetDlgItemText(hDlg,IDC_DEBUG_DATA_FILE,szFilename,ARRAYSIZEOF(szFilename));
|
|
|
|
// decode address field
|
|
if ( !GetAddr(hDlg,IDC_DEBUG_DATA_STARTADDR,&dwStartAddr,0xFFFFF,FALSE)
|
|
|| dwStartAddr == -1)
|
|
return FALSE;
|
|
|
|
_ASSERT(dwStartAddr <= 0xFFFFF);
|
|
|
|
// load memory dump file
|
|
if (!LoadMemData(szFilename,dwStartAddr))
|
|
return FALSE;
|
|
|
|
// update memory window
|
|
UpdateMemoryWnd(GetParent(hDlg));
|
|
|
|
// no break
|
|
case IDCANCEL:
|
|
EndDialog(hDlg,LOWORD(wParam));
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
}
|
|
|
|
static BOOL OnMemLoadData(HWND hDlg)
|
|
{
|
|
if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DEBUG_MEMLOAD), hDlg, (DLGPROC)DebugMemLoad) == -1)
|
|
AbortMessage(_T("DebugLoad Dialog Box Creation Error !"));
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// memory save data
|
|
//
|
|
static INT_PTR CALLBACK DebugMemSave(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
TCHAR szFilename[MAX_PATH];
|
|
DWORD dwStartAddr,dwEndAddr;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_COMMAND:
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_DEBUG_DATA_BUT:
|
|
return OnBrowseSaveMem(hDlg);
|
|
|
|
case IDOK:
|
|
dwStartAddr = dwEndAddr = -1; // no address given
|
|
|
|
// get filename
|
|
GetDlgItemText(hDlg,IDC_DEBUG_DATA_FILE,szFilename,ARRAYSIZEOF(szFilename));
|
|
|
|
// decode address fields
|
|
if ( !GetAddr(hDlg,IDC_DEBUG_DATA_STARTADDR,&dwStartAddr,0xFFFFF,FALSE)
|
|
|| dwStartAddr == -1)
|
|
return FALSE;
|
|
if ( !GetAddr(hDlg,IDC_DEBUG_DATA_ENDADDR,&dwEndAddr,0xFFFFF,FALSE)
|
|
|| dwEndAddr == -1)
|
|
return FALSE;
|
|
|
|
_ASSERT(dwStartAddr <= 0xFFFFF);
|
|
_ASSERT(dwEndAddr <= 0xFFFFF);
|
|
|
|
// save memory dump file
|
|
if (!SaveMemData(szFilename,dwStartAddr,dwEndAddr))
|
|
return FALSE;
|
|
|
|
// no break
|
|
case IDCANCEL:
|
|
EndDialog(hDlg,LOWORD(wParam));
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
}
|
|
|
|
static BOOL OnMemSaveData(HWND hDlg)
|
|
{
|
|
if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DEBUG_MEMSAVE), hDlg, (DLGPROC)DebugMemSave) == -1)
|
|
AbortMessage(_T("DebugSave Dialog Box Creation Error !"));
|
|
return -1;
|
|
}
|
|
|
|
|
|
//################
|
|
//#
|
|
//# Trace Log
|
|
//#
|
|
//################
|
|
|
|
static VOID StartTrace(VOID)
|
|
{
|
|
if (hLogFile == NULL)
|
|
{
|
|
SetCurrentDirectory(szEmuDirectory);
|
|
hLogFile = CreateFile(
|
|
szTraceFilename,
|
|
GENERIC_READ|GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
(uTraceMode == TRACE_FILE_NEW) ? CREATE_ALWAYS : OPEN_ALWAYS,
|
|
0,
|
|
NULL);
|
|
SetCurrentDirectory(szCurrentDirectory);
|
|
if (hLogFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
InfoMessage(_T("Unable to create trace log file."));
|
|
hLogFile = NULL;
|
|
return;
|
|
}
|
|
|
|
// goto end of file
|
|
SetFilePointer(hLogFile,0L,NULL,FILE_END);
|
|
}
|
|
return;
|
|
}
|
|
|
|
static VOID StopTrace(VOID)
|
|
{
|
|
if (hLogFile != NULL)
|
|
{
|
|
CloseHandle(hLogFile);
|
|
}
|
|
hLogFile = NULL;
|
|
return;
|
|
}
|
|
|
|
static VOID FlushTrace(VOID)
|
|
{
|
|
if (hLogFile != NULL)
|
|
{
|
|
VERIFY(FlushFileBuffers(hLogFile));
|
|
}
|
|
return;
|
|
}
|
|
|
|
static __inline void __cdecl PrintTrace(LPCTSTR lpFormat, ...)
|
|
{
|
|
TCHAR cOutput[1024];
|
|
DWORD dwWritten, dwRead;
|
|
va_list arglist;
|
|
|
|
va_start(arglist,lpFormat);
|
|
dwWritten = (DWORD) wvsprintf(cOutput,lpFormat,arglist);
|
|
va_end(arglist);
|
|
#if defined _UNICODE
|
|
{
|
|
// Unicode to byte translation
|
|
LPTSTR szTmp = DuplicateString(cOutput);
|
|
if (szTmp != NULL)
|
|
{
|
|
WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK,
|
|
szTmp, -1,
|
|
(LPSTR) cOutput, sizeof(cOutput), NULL, NULL);
|
|
free(szTmp);
|
|
}
|
|
}
|
|
#endif
|
|
WriteFile(hLogFile,cOutput,dwWritten,&dwRead,NULL);
|
|
return;
|
|
}
|
|
|
|
static VOID OutTrace(VOID)
|
|
{
|
|
enum MEM_MAPPING eMapMode;
|
|
LPCTSTR lpszName;
|
|
LPTSTR s,d;
|
|
TCHAR szBuffer[128];
|
|
TCHAR szOpc[8];
|
|
DWORD dwNxtAddr,dwOpcAddr;
|
|
UINT i;
|
|
|
|
if (hLogFile != NULL) // log file opened
|
|
{
|
|
if (bTraceReg) // show regs
|
|
{
|
|
INT nPos;
|
|
|
|
nPos = wsprintf(szBuffer,_T("\r\n A=%s"),RegToStr(Chipset.A,16));
|
|
nPos += wsprintf(&szBuffer[nPos],_T(" B=%s"),RegToStr(Chipset.B,16));
|
|
nPos += wsprintf(&szBuffer[nPos],_T(" C=%s"),RegToStr(Chipset.C,16));
|
|
wsprintf(&szBuffer[nPos],_T(" D=%s\r\n"),RegToStr(Chipset.D,16));
|
|
PrintTrace(szBuffer);
|
|
|
|
nPos = wsprintf(szBuffer,_T(" R0=%s"),RegToStr(Chipset.R0,16));
|
|
nPos += wsprintf(&szBuffer[nPos],_T(" R1=%s"),RegToStr(Chipset.R1,16));
|
|
nPos += wsprintf(&szBuffer[nPos],_T(" R2=%s"),RegToStr(Chipset.R2,16));
|
|
wsprintf(&szBuffer[nPos],_T(" R3=%s\r\n"),RegToStr(Chipset.R3,16));
|
|
PrintTrace(szBuffer);
|
|
|
|
PrintTrace(_T(" R4=%s D0=%05X D1=%05X P=%X CY=%d Mode=%c OUT=%03X IN=%04X\r\n"),
|
|
RegToStr(Chipset.R4,16),Chipset.d0,Chipset.d1,Chipset.P,Chipset.carry,
|
|
Chipset.mode_dec ? _T('D') : _T('H'),Chipset.out,Chipset.in);
|
|
|
|
PrintTrace(_T(" ST=%s MP=%d SR=%d SB=%d XM=%d IntrEn=%d KeyScan=%d BS=%02X\r\n"),
|
|
RegToStr(Chipset.ST,4),
|
|
(Chipset.HST & MP) != 0,(Chipset.HST & SR) != 0,(Chipset.HST & SB) != 0,(Chipset.HST & XM) != 0,
|
|
Chipset.inte,Chipset.intk,Chipset.Bank_FF & 0x7F);
|
|
|
|
// hardware stack content
|
|
PrintTrace(_T(" Stack="));
|
|
for (i = 1; i <= ARRAYSIZEOF(Chipset.rstk); ++i)
|
|
{
|
|
PrintTrace(_T(" %05X"), Chipset.rstk[(Chipset.rstkp-i)&7]);
|
|
}
|
|
PrintTrace(_T("\r\n"));
|
|
}
|
|
|
|
if (bTraceMmu) // show MMU
|
|
{
|
|
TCHAR szSize[8],szAddr[8];
|
|
|
|
if (!bTraceReg) // no regs
|
|
{
|
|
PrintTrace(_T("\r\n")); // add separator line
|
|
}
|
|
|
|
wsprintf(szAddr, Chipset.IOCfig ? _T("%05X") : _T("-----"),Chipset.IOBase);
|
|
PrintTrace(_T(" I/O=%s"),szAddr);
|
|
|
|
wsprintf(szSize, Chipset.P0Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P0Size^0xFF)<<12);
|
|
wsprintf(szAddr, Chipset.P0Cfig ? _T("%05X") : _T("-----"),Chipset.P0Base<<12);
|
|
PrintTrace(_T(" NCE2=%s/%s"),szSize,szAddr);
|
|
|
|
if (cCurrentRomType=='S')
|
|
{
|
|
wsprintf(szSize, Chipset.P1Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P1Size^0xFF)<<12);
|
|
wsprintf(szAddr, Chipset.P1Cfig ? _T("%05X") : _T("-----"),Chipset.P1Base<<12);
|
|
}
|
|
else
|
|
{
|
|
wsprintf(szSize, Chipset.BSCfg2 ? _T("%05X") : _T("-----"),(Chipset.BSSize^0xFF)<<12);
|
|
wsprintf(szAddr, Chipset.BSCfig ? _T("%05X") : _T("-----"),Chipset.BSBase<<12);
|
|
}
|
|
PrintTrace(_T(" CE1=%s/%s"),szSize,szAddr);
|
|
|
|
if (cCurrentRomType=='S')
|
|
{
|
|
wsprintf(szSize, Chipset.P2Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P2Size^0xFF)<<12);
|
|
wsprintf(szAddr, Chipset.P2Cfig ? _T("%05X") : _T("-----"),Chipset.P2Base<<12);
|
|
}
|
|
else
|
|
{
|
|
wsprintf(szSize, Chipset.P1Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P1Size^0xFF)<<12);
|
|
wsprintf(szAddr, Chipset.P1Cfig ? _T("%05X") : _T("-----"),Chipset.P1Base<<12);
|
|
}
|
|
PrintTrace(_T(" CE2=%s/%s"),szSize,szAddr);
|
|
|
|
if (cCurrentRomType=='S')
|
|
{
|
|
wsprintf(szSize, Chipset.BSCfg2 ? _T("%05X") : _T("-----"),(Chipset.BSSize^0xFF)<<12);
|
|
wsprintf(szAddr, Chipset.BSCfig ? _T("%05X") : _T("-----"),Chipset.BSBase<<12);
|
|
}
|
|
else
|
|
{
|
|
wsprintf(szSize, Chipset.P2Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P2Size^0xFF)<<12);
|
|
wsprintf(szAddr, Chipset.P2Cfig ? _T("%05X") : _T("-----"),Chipset.P2Base<<12);
|
|
}
|
|
PrintTrace(_T(" NCE3=%s/%s\r\n"),szSize,szAddr);
|
|
}
|
|
|
|
// disassemble line
|
|
eMapMode = GetMemMapType(); // get current map mode
|
|
SetMemMapType(MEM_MMU); // disassemble in mapped mode
|
|
|
|
// entry has a name
|
|
if (disassembler_symb && (lpszName = RplGetName(Chipset.pc)) != NULL)
|
|
{
|
|
PrintTrace(_T("=%s\r\n"),lpszName); // print address as label
|
|
}
|
|
dwNxtAddr = disassemble(Chipset.pc,szBuffer);
|
|
|
|
// in disassembly replace space characters
|
|
// between Opcode and Modifier with one TAB
|
|
if ((s = _tcschr(szBuffer,_T(' '))) != NULL)
|
|
{
|
|
// skip blanks
|
|
for (d = s; *d == _T(' '); ++d) { }
|
|
|
|
if (d == &szBuffer[8]) // on TAB position
|
|
{
|
|
*s++ = _T('\t'); // replace with TAB
|
|
|
|
// move the opcode modifier
|
|
while ((*s++ = *d++) != 0) { }
|
|
}
|
|
}
|
|
|
|
if (bTraceOpc) // show opcode nibbles
|
|
{
|
|
dwOpcAddr = Chipset.pc; // init address
|
|
|
|
// show opcode nibbles in a block of 5
|
|
for (i = 0; i < 5 && dwOpcAddr < dwNxtAddr; ++i)
|
|
{
|
|
szOpc[i] = cHex[GetMemNib(&dwOpcAddr)];
|
|
}
|
|
|
|
if (i == 1) // only 1 nibble written
|
|
{
|
|
szOpc[i++] = _T('\t'); // one additional TAB necessary
|
|
}
|
|
szOpc[i] = 0; // EOS
|
|
|
|
PrintTrace(_T("%05lX %s\t%s\r\n"),Chipset.pc,szOpc,szBuffer);
|
|
|
|
while (dwOpcAddr < dwNxtAddr) // decode rest of opcode
|
|
{
|
|
// show opcode nibbles in a block of 5
|
|
for (i = 0; i < 5 && dwOpcAddr < dwNxtAddr; ++i)
|
|
{
|
|
szOpc[i] = cHex[GetMemNib(&dwOpcAddr)];
|
|
}
|
|
szOpc[i] = 0; // EOS
|
|
|
|
PrintTrace(_T(" %s\r\n"),szOpc);
|
|
}
|
|
}
|
|
else // without opcode nibbles
|
|
{
|
|
PrintTrace(_T("%05lX\t%s\r\n"),Chipset.pc,szBuffer);
|
|
}
|
|
|
|
SetMemMapType(eMapMode); // switch back to old map mode
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// trace settings dialog
|
|
//
|
|
static BOOL OnBrowseTraceSettings(HWND hDlg)
|
|
{
|
|
TCHAR szBuffer[MAX_PATH];
|
|
OPENFILENAME ofn;
|
|
|
|
// get current content of file edit box
|
|
GetDlgItemText(hDlg,IDC_TRACE_FILE,szBuffer,ARRAYSIZEOF(szBuffer));
|
|
|
|
ZeroMemory(&ofn, sizeof(OPENFILENAME));
|
|
ofn.lStructSize = sizeof(OPENFILENAME);
|
|
ofn.hwndOwner = hDlg;
|
|
ofn.lpstrFilter =
|
|
_T("Trace Log Files (*.log)\0*.log\0")
|
|
_T("All Files (*.*)\0*.*\0");
|
|
ofn.lpstrDefExt = _T("log");
|
|
ofn.nFilterIndex = 1;
|
|
ofn.lpstrFile = szBuffer;
|
|
ofn.nMaxFile = ARRAYSIZEOF(szBuffer);
|
|
ofn.Flags = OFN_EXPLORER|OFN_HIDEREADONLY|OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT;
|
|
if (GetSaveFileName(&ofn))
|
|
{
|
|
SetDlgItemText(hDlg,IDC_TRACE_FILE,szBuffer);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// trace settings
|
|
//
|
|
static INT_PTR CALLBACK TraceSettings(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
SetDlgItemText(hDlg,IDC_TRACE_FILE,szTraceFilename);
|
|
CheckDlgButton(hDlg,(uTraceMode == TRACE_FILE_NEW) ? IDC_TRACE_NEW : IDC_TRACE_APPEND,BST_CHECKED);
|
|
CheckDlgButton(hDlg,IDC_TRACE_REGISTER,bTraceReg);
|
|
CheckDlgButton(hDlg,IDC_TRACE_MMU,bTraceMmu);
|
|
CheckDlgButton(hDlg,IDC_TRACE_OPCODE,bTraceOpc);
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_TRACE_BROWSE:
|
|
return OnBrowseTraceSettings(hDlg);
|
|
|
|
case IDOK:
|
|
// get filename
|
|
GetDlgItemText(hDlg,IDC_TRACE_FILE,szTraceFilename,ARRAYSIZEOF(szTraceFilename));
|
|
|
|
// trace mode
|
|
uTraceMode = IsDlgButtonChecked(hDlg,IDC_TRACE_NEW) ? TRACE_FILE_NEW : TRACE_FILE_APPEND;
|
|
|
|
// trace content
|
|
bTraceReg = IsDlgButtonChecked(hDlg,IDC_TRACE_REGISTER);
|
|
bTraceMmu = IsDlgButtonChecked(hDlg,IDC_TRACE_MMU);
|
|
bTraceOpc = IsDlgButtonChecked(hDlg,IDC_TRACE_OPCODE);
|
|
|
|
// no break
|
|
case IDCANCEL:
|
|
EndDialog(hDlg,LOWORD(wParam));
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
}
|
|
|
|
static BOOL OnTraceSettings(HWND hDlg)
|
|
{
|
|
if (DialogBox(hApp, MAKEINTRESOURCE(IDD_TRACE), hDlg, (DLGPROC)TraceSettings) == -1)
|
|
AbortMessage(_T("TraceSettings Dialog Box Creation Error !"));
|
|
return -1;
|
|
}
|
|
|
|
static BOOL OnTraceEnable(HWND hDlg)
|
|
{
|
|
OnToggleMenuItem(hDlg,ID_TRACE_ENABLE,&bDbgTrace);
|
|
bDbgTrace ? StartTrace() : StopTrace();
|
|
EnableMenuItem(GetMenu(hDlg),ID_TRACE_SETTINGS,bDbgTrace ? MF_GRAYED : MF_ENABLED);
|
|
return 0;
|
|
}
|