emu48plus-mirror/source/debugger.c
Gwenhael Le Moine bdab3ead6a
fd -e c -e h -e C -e H -x sed -i 's|^M||g'
Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
2024-04-01 17:27:54 +02:00

3997 lines
105 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;
}