#include "std.h"
#include "resource.h"
#include "emul.h"
#include "vars.h"
#include "debug.h"
#include "dbgbpx.h"
#include "dbgcmd.h"
#include "config.h"
#include "util.h"
enum
{
DB_STOP = 0,
DB_CHAR,
DB_SHORT,
DB_PCHAR,
DB_PSHORT,
DB_PINT,
DB_PFUNC
};
typedef bool (__cdecl *func_t)();
static unsigned calcerr;
unsigned calc(const Z80 *cpu, uintptr_t *script)
{
unsigned stack[64];
unsigned *sp = stack-1, x;
while (*script) {
switch (*script++) {
case 'M': *sp = cpu->DirectRm(*sp); break;
case '!': *sp = !*sp; break;
case '~': *sp = ~*sp; break;
case '+': *(sp-1) += *sp; goto arith;
case '-': *(sp-1) -= *sp; goto arith;
case '*': *(sp-1) *= *sp; goto arith;
case '/': if (*sp) *(sp-1) /= *sp; goto arith;
case '%': if (*sp) *(sp-1) %= *sp; goto arith;
case '&': *(sp-1) &= *sp; goto arith;
case '|': *(sp-1) |= *sp; goto arith;
case '^': *(sp-1) ^= *sp; goto arith;
case WORD2('-','>'): *(sp-1) = cpu->DirectRm(*sp + sp[-1]); goto arith;
case WORD2('>','>'): *(sp-1) >>= *sp;goto arith;
case WORD2('<','<'): *(sp-1) <<= *sp;goto arith;
case WORD2('!','='): *(sp-1) = (sp[-1]!=*sp);goto arith;
case '=':
case WORD2('=','='): *(sp-1) = (sp[-1]==*sp);goto arith;
case WORD2('<','='): *(sp-1) = (sp[-1]<=*sp);goto arith;
case WORD2('>','='): *(sp-1) = (sp[-1]>=*sp);goto arith;
case WORD2('|','|'): *(sp-1) = (sp[-1]||*sp);goto arith;
case WORD2('&','&'): *(sp-1) = (sp[-1]&&*sp);goto arith;
case '<': *(sp-1) = (sp[-1]<*sp);goto arith;
case '>': *(sp-1) = (sp[-1]>*sp);goto arith;
arith: sp--; break;
case DB_CHAR:
case DB_SHORT: x = unsigned(*script++); goto push;
case DB_PCHAR: x = *(unsigned char*)*script++; goto push;
case DB_PSHORT: x = 0xFFFF & *(unsigned*)*script++; goto push;
case DB_PINT: x = *(unsigned*)*script++; goto push;
case DB_PFUNC: x = ((func_t)*script++)(); goto push;
push: *++sp = x; break;
} // switch (*script)
} // while
if (sp != stack) calcerr = 1;
return *sp;
}
static bool __cdecl get_dos_flag()
{
return (comp.flags & CF_DOSPORTS) != 0;
}
#define DECL_REGS(var, cpu) \
static struct \
{ \
unsigned reg; \
const void *ptr; \
unsigned char size; \
} var[] = \
{ \
\
{ WORD4('D','O','S',0), (const void *)get_dos_flag, 0 }, \
{ WORD4('O','U','T',0), &brk_port_out, 4 }, \
{ WORD2('I','N'), &brk_port_in, 4 }, \
{ WORD4('V','A','L',0), &brk_port_val, 1 }, \
{ WORD2('F','D'), &comp.p7FFD, 1 }, \
\
{ WORD4('A','F','\'',0), &cpu.alt.af, 2 }, \
{ WORD4('B','C','\'',0), &cpu.alt.bc, 2 }, \
{ WORD4('D','E','\'',0), &cpu.alt.de, 2 }, \
{ WORD4('H','L','\'',0), &cpu.alt.hl, 2 }, \
{ WORD2('A','\''), &cpu.alt.a, 1 }, \
{ WORD2('F','\''), &cpu.alt.f, 1 }, \
{ WORD2('B','\''), &cpu.alt.b, 1 }, \
{ WORD2('C','\''), &cpu.alt.c, 1 }, \
{ WORD2('D','\''), &cpu.alt.d, 1 }, \
{ WORD2('E','\''), &cpu.alt.e, 1 }, \
{ WORD2('H','\''), &cpu.alt.h, 1 }, \
{ WORD2('L','\''), &cpu.alt.l, 1 }, \
\
{ WORD2('A','F'), &cpu.af, 2 }, \
{ WORD2('B','C'), &cpu.bc, 2 }, \
{ WORD2('D','E'), &cpu.de, 2 }, \
{ WORD2('H','L'), &cpu.hl, 2 }, \
{ 'A', &cpu.a, 1 }, \
{ 'F', &cpu.f, 1 }, \
{ 'B', &cpu.b, 1 }, \
{ 'C', &cpu.c, 1 }, \
{ 'D', &cpu.d, 1 }, \
{ 'E', &cpu.e, 1 }, \
{ 'H', &cpu.h, 1 }, \
{ 'L', &cpu.l, 1 }, \
\
{ WORD2('P','C'), &cpu.pc, 2 }, \
{ WORD2('S','P'), &cpu.sp, 2 }, \
{ WORD2('I','X'), &cpu.ix, 2 }, \
{ WORD2('I','Y'), &cpu.iy, 2 }, \
\
{ 'I', &cpu.i, 1 }, \
{ 'R', &cpu.r_low, 1 }, \
}
static unsigned char toscript(char *script, uintptr_t *dst)
{
uintptr_t *d1 = dst;
static struct {
unsigned short op;
unsigned char prior;
} prio[] = {
{ '(', 10 },
{ ')', 0 },
{ '!', 1 },
{ '~', 1 },
{ 'M', 1 },
{ WORD2('-','>'), 1 },
{ '*', 2 },
{ '%', 2 },
{ '/', 2 },
{ '+', 3 },
{ '-', 3 },
{ WORD2('>','>'), 4 },
{ WORD2('<','<'), 4 },
{ '>', 5 },
{ '<', 5 },
{ '=', 5 },
{ WORD2('>','='), 5 },
{ WORD2('<','='), 5 },
{ WORD2('=','='), 5 },
{ WORD2('!','='), 5 },
{ '&', 6 },
{ '^', 7 },
{ '|', 8 },
{ WORD2('&','&'), 9 },
{ WORD2('|','|'), 10 }
};
const Z80 &cpu = CpuMgr.Cpu();
DECL_REGS(regs, cpu);
unsigned sp = 0;
uintptr_t stack[128];
for (char *p = script; *p; p++)
if (p[1] != 0x27)
*p = char(toupper(*p));
while (*script)
{
if (*(unsigned char*)script <= ' ')
{
script++;
continue;
}
if (*script == '\'')
{ // char
*dst++ = DB_CHAR;
*dst++ = uintptr_t(script[1]);
if (script[2] != '\'') return 0;
script += 3; continue;
}
if (isalnum(*script) && *script != 'M')
{
unsigned r = -1U, p = *(unsigned*)script;
unsigned ln = 0;
for (unsigned i = 0; i < _countof(regs); i++)
{
unsigned mask = 0xFF; ln = 1;
if(regs[i].reg & 0xFF00)
{
mask = 0xFFFF;
ln = 2;
}
if(regs[i].reg & 0xFF0000)
{
mask = 0xFFFFFF;
ln = 3;
}
if (regs[i].reg == (p & mask)) { r = i; break; }
}
if (r != -1U)
{
script += ln;
switch (regs[r].size)
{
case 0: *dst++ = DB_PFUNC; break;
case 1: *dst++ = DB_PCHAR; break;
case 2: *dst++ = DB_PSHORT; break;
case 4: *dst++ = DB_PINT; break;
default: errexit("BUG01");
}
*dst++ = (uintptr_t)regs[r].ptr;
}
else
{ // number
if (*script > 'F') return 0;
for (r = 0; isalnum(*script) && *script <= 'F'; script++)
r = r*0x10 + unsigned((*script >= 'A') ? *script-'A'+10 : *script-'0');
*dst++ = DB_SHORT;
*dst++ = r;
}
continue;
}
// find operation
unsigned char pr = 0xFF;
unsigned r = (unsigned)*script++;
if (strchr("<>=&|-!", (char)r) && strchr("<>=&|", *script))
r += unsigned(0x100 * (*script++));
for (unsigned i = 0; i < _countof(prio); i++)
{
if (prio[i].op == r)
{
pr = prio[i].prior;
break;
}
}
if (pr == 0xFF)
return 0;
if (r != '(')
{
while (sp && ((stack[sp] >> 16 <= pr) || (r == ')' && (stack[sp] & 0xFF) != '(')))
{ // get from stack
*dst++ = stack[sp--] & 0xFFFF;
}
}
if (r == ')')
sp--; // del opening bracket
else
stack[++sp] = r+0x10000*pr; // put to stack
if ((int)sp < 0)
return 0; // no opening bracket
}
// empty stack
while (sp)
{
if ((stack[sp] & 0xFF) == '(')
return 0; // no closing bracket
*dst++ = stack[sp--] & 0xFFFF;
}
*dst = DB_STOP;
calcerr = 0;
calc(&cpu, d1);
return u8(1-calcerr);
}
static void script2text(char *dst, const uintptr_t *src)
{
char stack[64][0x200], tmp[0x200];
unsigned sp = 0;
uintptr_t r;
const Z80 &cpu = CpuMgr.Cpu();
DECL_REGS(regs, cpu);
while ((r = *src++))
{
if (r == DB_CHAR)
{
sprintf(stack[sp++], "'%c'", int(*src++));
continue;
}
if (r == DB_SHORT)
{
sprintf(stack[sp], "0%X", unsigned(*src++));
if (isdigit(stack[sp][1])) strcpy(stack[sp], stack[sp]+1);
sp++;
continue;
}
if (r >= DB_PCHAR && r <= DB_PFUNC)
{
unsigned sz = 0;
switch(r)
{
case DB_PCHAR: sz = 1; break;
case DB_PSHORT: sz = 2; break;
case DB_PINT: sz = 4; break;
case DB_PFUNC: sz = 0; break;
}
unsigned i;
for (i = 0; i < _countof(regs); i++)
{
if ((*src == (uintptr_t)regs[i].ptr) && (sz == regs[i].size))
break;
}
*(unsigned*)&(stack[sp++]) = regs[i].reg;
src++;
continue;
}
if (r == 'M' || r == '~' || r == '!')
{ // unary operators
sprintf(tmp, "%c(%s)", int(r), stack[sp-1]);
strcpy(stack[sp-1], tmp);
continue;
}
// else binary operators
sprintf(tmp, "(%s%s%s)", stack[sp-2], (char*)&r, stack[sp-1]);
sp--; strcpy(stack[sp-1], tmp);
}
if (!sp)
*dst = 0;
else
strcpy(dst, stack[sp-1]);
}
static void SetBpxButtons(HWND dlg)
{
int focus = -1, text = 0, box = 0;
HWND focusedWnd = GetFocus();
if(focusedWnd == GetDlgItem(dlg, IDE_CBP) || focusedWnd == GetDlgItem(dlg, IDC_CBP))
{
focus = 0;
text = IDE_CBP;
box = IDC_CBP;
}
if(focusedWnd == GetDlgItem(dlg, IDE_BPX) || focusedWnd == GetDlgItem(dlg, IDC_BPX))
{
focus = 1;
text = IDE_BPX;
box = IDC_BPX;
}
if(focusedWnd == GetDlgItem(dlg, IDE_MEM) || focusedWnd == GetDlgItem(dlg, IDC_MEM) ||
focusedWnd == GetDlgItem(dlg, IDC_MEM_R) || focusedWnd == GetDlgItem(dlg, IDC_MEM_W))
{
focus = 2;
text = IDE_MEM;
box = IDC_MEM;
}
SendDlgItemMessage(dlg, IDE_CBP, EM_SETREADONLY, (BOOL)(focus != 0), 0);
SendDlgItemMessage(dlg, IDE_BPX, EM_SETREADONLY, (BOOL)(focus != 1), 0);
SendDlgItemMessage(dlg, IDE_MEM, EM_SETREADONLY, (BOOL)(focus != 2), 0);
int del0 = 0, add0 = 0, del1 = 0, add1 = 0, del2 = 0, add2 = 0;
unsigned max = unsigned(SendDlgItemMessage(dlg, box, LB_GETCOUNT, 0, 0)),
cur = unsigned(SendDlgItemMessage(dlg, box, LB_GETCURSEL, 0, 0)),
len = unsigned(SendDlgItemMessage(dlg, text, WM_GETTEXTLENGTH, 0, 0));
if (max && cur >= max) SendDlgItemMessage(dlg, box, LB_SETCURSEL, cur = 0, 0);
if (focus == 0) { if (len && max < MAX_CBP) add0 = 1; if (cur < max) del0 = 1; }
if (focus == 1) { if (len) add1 = 1; if (cur < max) del1 = 1; }
if (focus == 2) {
if (IsDlgButtonChecked(dlg, IDC_MEM_R) == BST_UNCHECKED && IsDlgButtonChecked(dlg, IDC_MEM_W) == BST_UNCHECKED) len = 0;
if (len) add2 = 1; if (cur < max) del2 = 1;
}
EnableWindow(GetDlgItem(dlg, IDB_CBP_ADD), add0);
EnableWindow(GetDlgItem(dlg, IDB_CBP_DEL), del0);
EnableWindow(GetDlgItem(dlg, IDB_BPX_ADD), add1);
EnableWindow(GetDlgItem(dlg, IDB_BPX_DEL), del1);
EnableWindow(GetDlgItem(dlg, IDB_MEM_ADD), add2);
EnableWindow(GetDlgItem(dlg, IDB_MEM_DEL), del2);
unsigned defid = 0;
if (add0) defid = IDB_CBP_ADD;
if (add1) defid = IDB_BPX_ADD;
if (add2) defid = IDB_MEM_ADD;
if (defid) SendMessage(dlg, DM_SETDEFID, defid, 0);
}
static void ClearListBox(HWND box)
{
while (SendMessage(box, LB_GETCOUNT, 0, 0))
SendMessage(box, LB_DELETESTRING, 0, 0);
}
static void FillCondBox(HWND dlg, unsigned cursor)
{
HWND box = GetDlgItem(dlg, IDC_CBP);
ClearListBox(box);
Z80 &cpu = CpuMgr.Cpu();
for (unsigned i = 0; i < cpu.cbpn; i++)
{
char tmp[0x200]; script2text(tmp, cpu.cbp[i]);
SendMessage(box, LB_ADDSTRING, 0, (LPARAM)tmp);
}
SendMessage(box, LB_SETCURSEL, cursor, 0);
}
static void FillBpxBox(HWND dlg, unsigned address)
{
HWND box = GetDlgItem(dlg, IDC_BPX);
ClearListBox(box);
unsigned selection = 0;
Z80 &cpu = CpuMgr.Cpu();
unsigned end; //Alone Coder 0.36.7
for (unsigned start = 0; start < 0x10000; )
{
if (!(cpu.membits[start] & MEMBITS_BPX))
{ start++; continue; }
for (/*unsigned*/ end = start; end < 0xFFFF && (cpu.membits[end+1] & MEMBITS_BPX); end++);
char tmp[16];
if (start == end) sprintf(tmp, "%04X", start);
else sprintf(tmp, "%04X-%04X", start, end);
SendMessage(box, LB_ADDSTRING, 0, (LPARAM)tmp);
if (start <= address && address <= end)
selection = unsigned(SendMessage(box, LB_GETCOUNT, 0, 0));
start = end+1;
}
if (selection) SendMessage(box, LB_SETCURSEL, selection-1, 0);
}
static void FillMemBox(HWND dlg, unsigned address)
{
HWND box = GetDlgItem(dlg, IDC_MEM);
ClearListBox(box);
unsigned selection = 0;
Z80 &cpu = CpuMgr.Cpu();
unsigned end; //Alone Coder 0.36.7
for (unsigned start = 0; start < 0x10000; ) {
const unsigned char mask = MEMBITS_BPR | MEMBITS_BPW;
if (!(cpu.membits[start] & mask)) { start++; continue; }
unsigned active = cpu.membits[start];
for (/*unsigned*/ end = start; end < 0xFFFF && !((active ^ cpu.membits[end+1]) & mask); end++);
char tmp[16];
if (start == end) sprintf(tmp, "%04X ", start);
else sprintf(tmp, "%04X-%04X ", start, end);
if (active & MEMBITS_BPR) strcat(tmp, "R");
if (active & MEMBITS_BPW) strcat(tmp, "W");
SendMessage(box, LB_ADDSTRING, 0, (LPARAM)tmp);
if (start <= address && address <= end)
selection = unsigned(SendMessage(box, LB_GETCOUNT, 0, 0));
start = end+1;
}
if (selection) SendMessage(box, LB_SETCURSEL, selection-1, 0);
}
static char MoveBpxFromBoxToEdit(HWND dlg, unsigned box, unsigned edit)
{
HWND hBox = GetDlgItem(dlg, int(box));
unsigned max = unsigned(SendDlgItemMessage(dlg, box, LB_GETCOUNT, 0, 0)),
cur = unsigned(SendDlgItemMessage(dlg, box, LB_GETCURSEL, 0, 0));
if (cur >= max) return 0;
char tmp[0x200];
SendMessage(hBox, LB_GETTEXT, cur, (LPARAM)tmp);
if (box == IDC_MEM && *tmp) {
char *last = tmp + strlen(tmp);
unsigned r = BST_UNCHECKED, w = BST_UNCHECKED;
if(last[-1] == 'W')
{
w = BST_CHECKED;
last--;
}
if(last[-1] == 'R')
{
r = BST_CHECKED;
last--;
}
if (last[-1] == ' ') last--;
*last = 0;
CheckDlgButton(dlg, IDC_MEM_R, r);
CheckDlgButton(dlg, IDC_MEM_W, w);
}
SetDlgItemText(dlg, edit, tmp);
return 1;
}
struct MEM_RANGE { unsigned start, end; };
static int GetMemRamge(char *str, MEM_RANGE &range)
{
while (*str == ' ') str++;
for (range.start = 0; ishex(*str); str++)
range.start = range.start*0x10 + hex(*str);
if (*str == '-') {
for (range.end = 0, str++; ishex(*str); str++)
range.end = range.end*0x10 + hex(*str);
} else range.end = range.start;
while (*str == ' ') str++;
if (*str) return 0;
if (range.start > 0xFFFF || range.end > 0xFFFF || range.start > range.end) return 0;
return 1;
}
static INT_PTR CALLBACK conddlg(HWND dlg, UINT msg, WPARAM wp, LPARAM lp)
{
(void)lp;
if (msg == WM_INITDIALOG)
{
FillCondBox(dlg, 0);
FillBpxBox(dlg, 0);
FillMemBox(dlg, 0);
SetFocus(GetDlgItem(dlg, IDE_CBP));
set_buttons_and_return:
SetBpxButtons(dlg);
return 1;
}
if (msg == WM_SYSCOMMAND && (wp & 0xFFF0) == SC_CLOSE) EndDialog(dlg, 0);
if (msg != WM_COMMAND) return 0;
unsigned id = LOWORD(wp), code = HIWORD(wp); unsigned char mask = 0;
if (id == IDCANCEL || id == IDOK) EndDialog(dlg, 0);
char tmp[0x200];
if (((id == IDE_BPX || id == IDE_CBP || id == IDE_MEM) && (code == EN_SETFOCUS || code == EN_CHANGE)) ||
((id == IDC_BPX || id == IDC_CBP || id == IDC_MEM) && code == LBN_SETFOCUS)) goto set_buttons_and_return;
if (id == IDC_MEM_R || id == IDC_MEM_W) goto set_buttons_and_return;
if (code == LBN_DBLCLK)
{
if (id == IDC_CBP && MoveBpxFromBoxToEdit(dlg, IDC_CBP, IDE_CBP)) goto del_cond;
if (id == IDC_BPX && MoveBpxFromBoxToEdit(dlg, IDC_BPX, IDE_BPX)) goto del_bpx;
if (id == IDC_MEM && MoveBpxFromBoxToEdit(dlg, IDC_MEM, IDE_MEM)) goto del_mem;
}
if (id == IDB_CBP_ADD)
{
SendDlgItemMessage(dlg, IDE_CBP, WM_GETTEXT, sizeof tmp, (LPARAM)tmp);
SetFocus(GetDlgItem(dlg, IDE_CBP));
Z80 &cpu = CpuMgr.Cpu();
if (!toscript(tmp, cpu.cbp[cpu.cbpn])) {
MessageBox(dlg, "Error in expression\nPlease do RTFM", nullptr, MB_ICONERROR);
return 1;
}
SendDlgItemMessage(dlg, IDE_CBP, WM_SETTEXT, 0, 0);
FillCondBox(dlg, cpu.cbpn++);
cpu.dbgchk = isbrk(cpu);
goto set_buttons_and_return;
}
if (id == IDB_BPX_ADD)
{
SendDlgItemMessage(dlg, IDE_BPX, WM_GETTEXT, sizeof tmp, (LPARAM)tmp);
SetFocus(GetDlgItem(dlg, IDE_BPX));
MEM_RANGE range;
if (!GetMemRamge(tmp, range))
{
MessageBox(dlg, "Invalid breakpoint address / range", nullptr, MB_ICONERROR);
return 1;
}
Z80 &cpu = CpuMgr.Cpu();
for (unsigned i = range.start; i <= range.end; i++)
cpu.membits[i] |= MEMBITS_BPX;
SendDlgItemMessage(dlg, IDE_BPX, WM_SETTEXT, 0, 0);
FillBpxBox(dlg, range.start);
cpu.dbgchk = isbrk(cpu);
goto set_buttons_and_return;
}
if (id == IDB_MEM_ADD)
{
SendDlgItemMessage(dlg, IDE_MEM, WM_GETTEXT, sizeof tmp, (LPARAM)tmp);
SetFocus(GetDlgItem(dlg, IDE_MEM));
MEM_RANGE range;
if (!GetMemRamge(tmp, range))
{
MessageBox(dlg, "Invalid watch address / range", nullptr, MB_ICONERROR);
return 1;
}
unsigned char mask = 0;
if (IsDlgButtonChecked(dlg, IDC_MEM_R) == BST_CHECKED) mask |= MEMBITS_BPR;
if (IsDlgButtonChecked(dlg, IDC_MEM_W) == BST_CHECKED) mask |= MEMBITS_BPW;
Z80 &cpu = CpuMgr.Cpu();
for (unsigned i = range.start; i <= range.end; i++)
cpu.membits[i] |= mask;
SendDlgItemMessage(dlg, IDE_MEM, WM_SETTEXT, 0, 0);
CheckDlgButton(dlg, IDC_MEM_R, BST_UNCHECKED);
CheckDlgButton(dlg, IDC_MEM_W, BST_UNCHECKED);
FillMemBox(dlg, range.start);
cpu.dbgchk = isbrk(cpu);
goto set_buttons_and_return;
}
if (id == IDB_CBP_DEL)
{
del_cond:
SetFocus(GetDlgItem(dlg, IDE_CBP));
unsigned cur = unsigned(SendDlgItemMessage(dlg, IDC_CBP, LB_GETCURSEL, 0, 0));
Z80 &cpu = CpuMgr.Cpu();
if (cur >= cpu.cbpn)
return 0;
cpu.cbpn--;
memcpy(cpu.cbp[cur], cpu.cbp[cur+1], sizeof(cpu.cbp[0])*(cpu.cbpn-cur));
if (cur && cur == cpu.cbpn)
cur--;
FillCondBox(dlg, cur);
cpu.dbgchk = isbrk(cpu);
goto set_buttons_and_return;
}
if (id == IDB_BPX_DEL)
{
del_bpx:
SetFocus(GetDlgItem(dlg, IDE_BPX));
id = IDC_BPX; mask = u8(~MEMBITS_BPX);
del_range:
unsigned cur = unsigned(SendDlgItemMessage(dlg, id, LB_GETCURSEL, 0, 0)),
max = unsigned(SendDlgItemMessage(dlg, id, LB_GETCOUNT, 0, 0));
if (cur >= max) return 0;
SendDlgItemMessage(dlg, id, LB_GETTEXT, cur, (LPARAM)tmp);
unsigned start, end;
sscanf(tmp, "%X", &start);
if (tmp[4] == '-') sscanf(tmp+5, "%X", &end); else end = start;
Z80 &cpu = CpuMgr.Cpu();
for (unsigned i = start; i <= end; i++)
cpu.membits[i] &= mask;
if (id == IDC_BPX) FillBpxBox(dlg, 0); else FillMemBox(dlg, 0);
if (cur && cur == max)
cur--;
SendDlgItemMessage(dlg, id, LB_SETCURSEL, cur, 0);
cpu.dbgchk = isbrk(cpu);
goto set_buttons_and_return;
}
if (id == IDB_MEM_DEL)
{
del_mem:
SetFocus(GetDlgItem(dlg, IDE_MEM));
id = IDC_MEM; mask = u8(~(MEMBITS_BPR | MEMBITS_BPW));
goto del_range;
}
return 0;
}
void mon_bpdialog()
{
DialogBox(hIn, MAKEINTRESOURCE(IDD_COND), wnd, conddlg);
}
static INT_PTR CALLBACK watchdlg(HWND dlg, UINT msg, WPARAM wp, LPARAM lp)
{
(void)lp;
char tmp[0x200]; unsigned i;
static const int ids1[] = { IDC_W1_ON, IDC_W2_ON, IDC_W3_ON, IDC_W4_ON };
static const int ids2[] = { IDE_W1, IDE_W2, IDE_W3, IDE_W4 };
if (msg == WM_INITDIALOG) {
for (i = 0; i < 4; i++) {
CheckDlgButton(dlg, ids1[i], watch_enabled[i] ? BST_CHECKED : BST_UNCHECKED);
script2text(tmp, watch_script[i]); SetWindowText(GetDlgItem(dlg, ids2[i]), tmp);
}
CheckDlgButton(dlg, IDC_TR_RAM, trace_ram ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(dlg, IDC_TR_ROM, trace_ram ? BST_CHECKED : BST_UNCHECKED);
reinit:
for (i = 0; i < 4; i++)
EnableWindow(GetDlgItem(dlg, ids2[i]), watch_enabled[i]);
return 1;
}
if (msg == WM_COMMAND && (LOWORD(wp)==ids1[0] || LOWORD(wp)==ids1[1] || LOWORD(wp)==ids1[2] || LOWORD(wp)==ids1[3])) {
for (i = 0; i < 4; i++)
watch_enabled[i] = IsDlgButtonChecked(dlg, ids1[i]) == BST_CHECKED;
goto reinit;
}
if ((msg == WM_SYSCOMMAND && (wp & 0xFFF0) == SC_CLOSE) || (msg == WM_COMMAND && LOWORD(wp) == IDCANCEL)) {
trace_ram = IsDlgButtonChecked(dlg, IDC_TR_RAM) == BST_CHECKED;
trace_rom = IsDlgButtonChecked(dlg, IDC_TR_ROM) == BST_CHECKED;
for (i = 0; i < 4; i++)
if (watch_enabled[i]) {
SendDlgItemMessage(dlg, ids2[i], WM_GETTEXT, sizeof tmp, (LPARAM)tmp);
if (!toscript(tmp, watch_script[i])) {
sprintf(tmp, "Watch %u: error in expression\nPlease do RTFM", i+1);
MessageBox(dlg, tmp, nullptr, MB_ICONERROR); watch_enabled[i] = 0;
SetFocus(GetDlgItem(dlg, ids2[i]));
return 0;
}
}
EndDialog(dlg, 0);
}
return 0;
}
void mon_watchdialog()
{
DialogBox(hIn, MAKEINTRESOURCE(IDD_OSW), wnd, watchdlg);
}
static void LoadBpx()
{
char Line[100];
char BpxFileName[FILENAME_MAX];
addpath(BpxFileName, "bpx.ini");
FILE *BpxFile = fopen(BpxFileName, "rt");
if(!BpxFile)
return;
while(!feof(BpxFile))
{
fgets(Line, sizeof(Line), BpxFile);
Line[sizeof(Line)-1] = 0;
char Type = -1;
int Start = -1, End = -1, CpuIdx = -1;
int n = sscanf(Line, "%c%1d=%i-%i", &Type, &CpuIdx, &Start, &End);
if(n < 3 || CpuIdx < 0 || CpuIdx >= (int)CpuMgr.GetCount() || Start < 0)
continue;
if(End < 0)
End = Start;
unsigned mask = 0;
switch(Type)
{
case 'r': mask |= MEMBITS_BPR; break;
case 'w': mask |= MEMBITS_BPW; break;
case 'x': mask |= MEMBITS_BPX; break;
default: continue;
}
Z80 &cpu = CpuMgr.Cpu(u32(CpuIdx));
for (unsigned i = unsigned(Start); i <= unsigned(End); i++)
cpu.membits[i] |= mask;
cpu.dbgchk = isbrk(cpu);
}
fclose(BpxFile);
}
static void SaveBpx()
{
char BpxFileName[FILENAME_MAX];
addpath(BpxFileName, "bpx.ini");
FILE *BpxFile = fopen(BpxFileName, "wt");
if(!BpxFile)
return;
for(unsigned CpuIdx = 0; CpuIdx < CpuMgr.GetCount(); CpuIdx++)
{
Z80 &cpu = CpuMgr.Cpu(CpuIdx);
for(int i = 0; i < 3; i++)
{
for (unsigned Start = 0; Start < 0x10000; )
{
static const unsigned Mask[] = { MEMBITS_BPR, MEMBITS_BPW, MEMBITS_BPX };
if (!(cpu.membits[Start] & Mask[i]))
{
Start++;
continue;
}
unsigned active = cpu.membits[Start];
unsigned End;
for (End = Start; End < 0xFFFF && !((active ^ cpu.membits[End+1]) & Mask[i]); End++);
static const char Type[] = { 'r', 'w', 'x' };
if(active & Mask[i])
{
if (Start == End)
fprintf(BpxFile, "%c%1u=0x%04X\n", Type[i], CpuIdx, Start);
else
fprintf(BpxFile, "%c%1u=0x%04X-0x%04X\n", Type[i], CpuIdx, Start, End);
}
Start = End + 1;
}
}
}
fclose(BpxFile);
}
void init_bpx()
{
LoadBpx();
}
void done_bpx()
{
SaveBpx();
}