Subversion Repositories pentevo

Rev

Rev 796 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

  1. #include "std.h"
  2.  
  3. #include "resource.h"
  4. #include "emul.h"
  5. #include "vars.h"
  6. #include "debug.h"
  7. #include "dbgbpx.h"
  8. #include "dbgcmd.h"
  9. #include "config.h"
  10. #include "util.h"
  11.  
  12. enum
  13. {
  14.    DB_STOP = 0,
  15.    DB_CHAR,
  16.    DB_SHORT,
  17.    DB_PCHAR,
  18.    DB_PSHORT,
  19.    DB_PINT,
  20.    DB_PFUNC
  21. };
  22.  
  23. typedef bool (__cdecl *func_t)();
  24.  
  25. static unsigned calcerr;
  26. unsigned calc(const Z80 *cpu, uintptr_t *script)
  27. {
  28.    unsigned stack[64];
  29.    unsigned *sp = stack-1, x;
  30.    while (*script) {
  31.       switch (*script++) {
  32.          case 'M':             *sp = cpu->DirectRm(*sp);   break;
  33.          case '!':             *sp = !*sp;     break;
  34.          case '~':             *sp = ~*sp;     break;
  35.          case '+':             *(sp-1) += *sp; goto arith;
  36.          case '-':             *(sp-1) -= *sp; goto arith;
  37.          case '*':             *(sp-1) *= *sp; goto arith;
  38.          case '/':             if (*sp) *(sp-1) /= *sp; goto arith;
  39.          case '%':             if (*sp) *(sp-1) %= *sp; goto arith;
  40.          case '&':             *(sp-1) &= *sp; goto arith;
  41.          case '|':             *(sp-1) |= *sp; goto arith;
  42.          case '^':             *(sp-1) ^= *sp; goto arith;
  43.          case WORD2('-','>'):  *(sp-1) = cpu->DirectRm(*sp + sp[-1]); goto arith;
  44.          case WORD2('>','>'):  *(sp-1) >>= *sp;goto arith;
  45.          case WORD2('<','<'):  *(sp-1) <<= *sp;goto arith;
  46.          case WORD2('!','='):  *(sp-1) = (sp[-1]!=*sp);goto arith;
  47.          case '=':
  48.          case WORD2('=','='):  *(sp-1) = (sp[-1]==*sp);goto arith;
  49.          case WORD2('<','='):  *(sp-1) = (sp[-1]<=*sp);goto arith;
  50.          case WORD2('>','='):  *(sp-1) = (sp[-1]>=*sp);goto arith;
  51.          case WORD2('|','|'):  *(sp-1) = (sp[-1]||*sp);goto arith;
  52.          case WORD2('&','&'):  *(sp-1) = (sp[-1]&&*sp);goto arith;
  53.          case '<':             *(sp-1) = (sp[-1]<*sp);goto arith;
  54.          case '>':             *(sp-1) = (sp[-1]>*sp);goto arith;
  55.          arith:                sp--;  break;
  56.          case DB_CHAR:
  57.          case DB_SHORT:        x = unsigned(*script++); goto push;
  58.          case DB_PCHAR:        x = *(unsigned char*)*script++; goto push;
  59.          case DB_PSHORT:       x = 0xFFFF & *(unsigned*)*script++; goto push;
  60.          case DB_PINT:         x = *(unsigned*)*script++; goto push;
  61.          case DB_PFUNC:        x = ((func_t)*script++)(); goto push;
  62.          push:                 *++sp = x; break;
  63.       } // switch (*script)
  64.    } // while
  65.    if (sp != stack) calcerr = 1;
  66.    return *sp;
  67. }
  68.  
  69. static bool __cdecl get_dos_flag()
  70. {
  71.     return (comp.flags & CF_DOSPORTS) != 0;
  72. }
  73.  
  74. #define DECL_REGS(var, cpu)                        \
  75.    static struct                                   \
  76.    {                                               \
  77.       unsigned reg;                                \
  78.       const void *ptr;                             \
  79.       unsigned char size;                          \
  80.    } var[] =                                       \
  81.    {                                               \
  82.                                                    \
  83.       { WORD4('D','O','S',0), (const void *)get_dos_flag, 0 },  \
  84.       { WORD4('O','U','T',0), &brk_port_out, 4 },  \
  85.       { WORD2('I','N'), &brk_port_in, 4 },         \
  86.       { WORD4('V','A','L',0), &brk_port_val, 1 },  \
  87.       { WORD2('F','D'), &comp.p7FFD, 1 },          \
  88.                                                    \
  89.       { WORD4('A','F','\'',0), &cpu.alt.af, 2 },   \
  90.       { WORD4('B','C','\'',0), &cpu.alt.bc, 2 },   \
  91.       { WORD4('D','E','\'',0), &cpu.alt.de, 2 },   \
  92.       { WORD4('H','L','\'',0), &cpu.alt.hl, 2 },   \
  93.       { WORD2('A','\''), &cpu.alt.a, 1 },          \
  94.       { WORD2('F','\''), &cpu.alt.f, 1 },          \
  95.       { WORD2('B','\''), &cpu.alt.b, 1 },          \
  96.       { WORD2('C','\''), &cpu.alt.c, 1 },          \
  97.       { WORD2('D','\''), &cpu.alt.d, 1 },          \
  98.       { WORD2('E','\''), &cpu.alt.e, 1 },          \
  99.       { WORD2('H','\''), &cpu.alt.h, 1 },          \
  100.       { WORD2('L','\''), &cpu.alt.l, 1 },          \
  101.                                                    \
  102.       { WORD2('A','F'), &cpu.af, 2 },              \
  103.       { WORD2('B','C'), &cpu.bc, 2 },              \
  104.       { WORD2('D','E'), &cpu.de, 2 },              \
  105.       { WORD2('H','L'), &cpu.hl, 2 },              \
  106.       { 'A', &cpu.a, 1 },                          \
  107.       { 'F', &cpu.f, 1 },                          \
  108.       { 'B', &cpu.b, 1 },                          \
  109.       { 'C', &cpu.c, 1 },                          \
  110.       { 'D', &cpu.d, 1 },                          \
  111.       { 'E', &cpu.e, 1 },                          \
  112.       { 'H', &cpu.h, 1 },                          \
  113.       { 'L', &cpu.l, 1 },                          \
  114.                                                    \
  115.       { WORD2('P','C'), &cpu.pc, 2 },              \
  116.       { WORD2('S','P'), &cpu.sp, 2 },              \
  117.       { WORD2('I','X'), &cpu.ix, 2 },              \
  118.       { WORD2('I','Y'), &cpu.iy, 2 },              \
  119.                                                    \
  120.       { 'I', &cpu.i, 1 },                          \
  121.       { 'R', &cpu.r_low, 1 },                      \
  122.    }
  123.  
  124.  
  125. static unsigned char toscript(char *script, uintptr_t *dst)
  126. {
  127.    uintptr_t *d1 = dst;
  128.    static struct {
  129.       unsigned short op;
  130.       unsigned char prior;
  131.    } prio[] = {
  132.       { '(', 10 },
  133.       { ')', 0 },
  134.       { '!', 1 },
  135.       { '~', 1 },
  136.       { 'M', 1 },
  137.       { WORD2('-','>'), 1 },
  138.       { '*', 2 },
  139.       { '%', 2 },
  140.       { '/', 2 },
  141.       { '+', 3 },
  142.       { '-', 3 },
  143.       { WORD2('>','>'), 4 },
  144.       { WORD2('<','<'), 4 },
  145.       { '>', 5 },
  146.       { '<', 5 },
  147.       { '=', 5 },
  148.       { WORD2('>','='), 5 },
  149.       { WORD2('<','='), 5 },
  150.       { WORD2('=','='), 5 },
  151.       { WORD2('!','='), 5 },
  152.       { '&', 6 },
  153.       { '^', 7 },
  154.       { '|', 8 },
  155.       { WORD2('&','&'), 9 },
  156.       { WORD2('|','|'), 10 }
  157.    };
  158.  
  159.    const Z80 &cpu = CpuMgr.Cpu();
  160.  
  161.    DECL_REGS(regs, cpu);
  162.  
  163.    unsigned sp = 0;
  164.    uintptr_t stack[128];
  165.    for (char *p = script; *p; p++)
  166.        if (p[1] != 0x27)
  167.            *p = char(toupper(*p));
  168.  
  169.    while (*script)
  170.    {
  171.       if (*(unsigned char*)script <= ' ')
  172.       {
  173.           script++;
  174.           continue;
  175.       }
  176.  
  177.       if (*script == '\'')
  178.       { // char
  179.          *dst++ = DB_CHAR;
  180.          *dst++ = uintptr_t(script[1]);
  181.          if (script[2] != '\'') return 0;
  182.          script += 3; continue;
  183.       }
  184.  
  185.       if (isalnum(*script) && *script != 'M')
  186.       {
  187.          unsigned r = -1U, p = *(unsigned*)script;
  188.          unsigned ln = 0;
  189.          for (unsigned i = 0; i < _countof(regs); i++)
  190.          {
  191.             unsigned mask = 0xFF; ln = 1;
  192.             if(regs[i].reg & 0xFF00)
  193.             {
  194.                 mask = 0xFFFF;
  195.                 ln = 2;
  196.             }
  197.             if(regs[i].reg & 0xFF0000)
  198.             {
  199.                 mask = 0xFFFFFF;
  200.                 ln = 3;
  201.             }
  202.             if (regs[i].reg == (p & mask)) { r = i; break; }
  203.          }
  204.          if (r != -1U)
  205.          {
  206.             script += ln;
  207.             switch (regs[r].size)
  208.             {
  209.                case 0: *dst++ = DB_PFUNC; break;
  210.                case 1: *dst++ = DB_PCHAR; break;
  211.                case 2: *dst++ = DB_PSHORT; break;
  212.                case 4: *dst++ = DB_PINT; break;
  213.                default: errexit("BUG01");
  214.             }
  215.             *dst++ = (uintptr_t)regs[r].ptr;
  216.          }
  217.          else
  218.          { // number
  219.             if (*script > 'F') return 0;
  220.             for (r = 0; isalnum(*script) && *script <= 'F'; script++)
  221.                r = r*0x10 + unsigned((*script >= 'A') ? *script-'A'+10 : *script-'0');
  222.             *dst++ = DB_SHORT;
  223.             *dst++ = r;
  224.          }
  225.          continue;
  226.       }
  227.       // find operation
  228.       unsigned char pr = 0xFF;
  229.       unsigned r = (unsigned)*script++;
  230.       if (strchr("<>=&|-!", (char)r) && strchr("<>=&|", *script))
  231.          r += unsigned(0x100 * (*script++));
  232.       for (unsigned i = 0; i < _countof(prio); i++)
  233.       {
  234.          if (prio[i].op == r)
  235.          {
  236.              pr = prio[i].prior;
  237.              break;
  238.          }
  239.       }
  240.       if (pr == 0xFF)
  241.           return 0;
  242.       if (r != '(')
  243.       {
  244.           while (sp && ((stack[sp] >> 16 <= pr) || (r == ')' && (stack[sp] & 0xFF) != '(')))
  245.           { // get from stack
  246.              *dst++ = stack[sp--] & 0xFFFF;
  247.           }
  248.       }
  249.       if (r == ')')
  250.           sp--; // del opening bracket
  251.       else
  252.           stack[++sp] = r+0x10000*pr; // put to stack
  253.       if ((int)sp < 0)
  254.           return 0; // no opening bracket
  255.    }
  256.    // empty stack
  257.    while (sp)
  258.    {
  259.       if ((stack[sp] & 0xFF) == '(')
  260.           return 0; // no closing bracket
  261.       *dst++ = stack[sp--] & 0xFFFF;
  262.    }
  263.    *dst = DB_STOP;
  264.  
  265.    calcerr = 0;
  266.    calc(&cpu, d1);
  267.    return u8(1-calcerr);
  268. }
  269.  
  270. static void script2text(char *dst, const uintptr_t *src)
  271. {
  272.    char stack[64][0x200], tmp[0x200];
  273.    unsigned sp = 0;
  274.    uintptr_t r;
  275.  
  276.    const Z80 &cpu = CpuMgr.Cpu();
  277.  
  278.    DECL_REGS(regs, cpu);
  279.  
  280.    while ((r = *src++))
  281.    {
  282.       if (r == DB_CHAR)
  283.       {
  284.          sprintf(stack[sp++], "'%c'", int(*src++));
  285.          continue;
  286.       }
  287.       if (r == DB_SHORT)
  288.       {
  289.          sprintf(stack[sp], "0%X", unsigned(*src++));
  290.          if (isdigit(stack[sp][1])) strcpy(stack[sp], stack[sp]+1);
  291.          sp++;
  292.          continue;
  293.       }
  294.       if (r >= DB_PCHAR && r <= DB_PFUNC)
  295.       {
  296.          unsigned sz = 0;
  297.          switch(r)
  298.          {
  299.          case DB_PCHAR: sz = 1; break;
  300.          case DB_PSHORT: sz = 2; break;
  301.          case DB_PINT: sz = 4; break;
  302.          case DB_PFUNC: sz = 0; break;
  303.          }
  304.          unsigned i;
  305.          for (i = 0; i < _countof(regs); i++)
  306.          {
  307.             if ((*src == (uintptr_t)regs[i].ptr) && (sz == regs[i].size))
  308.                 break;
  309.          }
  310.          *(unsigned*)&(stack[sp++]) = regs[i].reg;
  311.          src++;
  312.          continue;
  313.       }
  314.       if (r == 'M' || r == '~' || r == '!')
  315.       { // unary operators
  316.          sprintf(tmp, "%c(%s)", int(r), stack[sp-1]);
  317.          strcpy(stack[sp-1], tmp);
  318.          continue;
  319.       }
  320.       // else binary operators
  321.       sprintf(tmp, "(%s%s%s)", stack[sp-2], (char*)&r, stack[sp-1]);
  322.       sp--; strcpy(stack[sp-1], tmp);
  323.    }
  324.    if (!sp)
  325.        *dst = 0;
  326.    else
  327.        strcpy(dst, stack[sp-1]);
  328. }
  329.  
  330. static void SetBpxButtons(HWND dlg)
  331. {
  332.    int focus = -1, text = 0, box = 0;
  333.    HWND focusedWnd = GetFocus();
  334.    if(focusedWnd == GetDlgItem(dlg, IDE_CBP) || focusedWnd == GetDlgItem(dlg, IDC_CBP))
  335.    {
  336.        focus = 0;
  337.        text = IDE_CBP;
  338.        box = IDC_CBP;
  339.    }
  340.    if(focusedWnd == GetDlgItem(dlg, IDE_BPX) || focusedWnd == GetDlgItem(dlg, IDC_BPX))
  341.    {
  342.        focus = 1;
  343.        text = IDE_BPX;
  344.        box = IDC_BPX;
  345.    }
  346.    if(focusedWnd == GetDlgItem(dlg, IDE_MEM) || focusedWnd == GetDlgItem(dlg, IDC_MEM) ||
  347.        focusedWnd == GetDlgItem(dlg, IDC_MEM_R) || focusedWnd == GetDlgItem(dlg, IDC_MEM_W))
  348.    {
  349.        focus = 2;
  350.        text = IDE_MEM;
  351.        box = IDC_MEM;
  352.    }
  353.  
  354.    SendDlgItemMessage(dlg, IDE_CBP, EM_SETREADONLY, (BOOL)(focus != 0), 0);
  355.    SendDlgItemMessage(dlg, IDE_BPX, EM_SETREADONLY, (BOOL)(focus != 1), 0);
  356.    SendDlgItemMessage(dlg, IDE_MEM, EM_SETREADONLY, (BOOL)(focus != 2), 0);
  357.  
  358.    int del0 = 0, add0 = 0, del1 = 0, add1 = 0, del2 = 0, add2 = 0;
  359.    unsigned max = unsigned(SendDlgItemMessage(dlg, box, LB_GETCOUNT, 0, 0)),
  360.             cur = unsigned(SendDlgItemMessage(dlg, box, LB_GETCURSEL, 0, 0)),
  361.             len = unsigned(SendDlgItemMessage(dlg, text, WM_GETTEXTLENGTH, 0, 0));
  362.  
  363.    if (max && cur >= max) SendDlgItemMessage(dlg, box, LB_SETCURSEL, cur = 0, 0);
  364.  
  365.    if (focus == 0) { if (len && max < MAX_CBP) add0 = 1; if (cur < max) del0 = 1; }
  366.    if (focus == 1) { if (len) add1 = 1; if (cur < max) del1 = 1; }
  367.    if (focus == 2) {
  368.       if (IsDlgButtonChecked(dlg, IDC_MEM_R) == BST_UNCHECKED && IsDlgButtonChecked(dlg, IDC_MEM_W) == BST_UNCHECKED) len = 0;
  369.       if (len) add2 = 1; if (cur < max) del2 = 1;
  370.    }
  371.  
  372.    EnableWindow(GetDlgItem(dlg, IDB_CBP_ADD), add0);
  373.    EnableWindow(GetDlgItem(dlg, IDB_CBP_DEL), del0);
  374.    EnableWindow(GetDlgItem(dlg, IDB_BPX_ADD), add1);
  375.    EnableWindow(GetDlgItem(dlg, IDB_BPX_DEL), del1);
  376.    EnableWindow(GetDlgItem(dlg, IDB_MEM_ADD), add2);
  377.    EnableWindow(GetDlgItem(dlg, IDB_MEM_DEL), del2);
  378.  
  379.    unsigned defid = 0;
  380.    if (add0) defid = IDB_CBP_ADD;
  381.    if (add1) defid = IDB_BPX_ADD;
  382.    if (add2) defid = IDB_MEM_ADD;
  383.    if (defid) SendMessage(dlg, DM_SETDEFID, defid, 0);
  384. }
  385.  
  386. static void ClearListBox(HWND box)
  387. {
  388.    while (SendMessage(box, LB_GETCOUNT, 0, 0))
  389.       SendMessage(box, LB_DELETESTRING, 0, 0);
  390. }
  391.  
  392. static void FillCondBox(HWND dlg, unsigned cursor)
  393. {
  394.    HWND box = GetDlgItem(dlg, IDC_CBP);
  395.    ClearListBox(box);
  396.  
  397.    Z80 &cpu = CpuMgr.Cpu();
  398.    for (unsigned i = 0; i < cpu.cbpn; i++)
  399.    {
  400.       char tmp[0x200]; script2text(tmp, cpu.cbp[i]);
  401.       SendMessage(box, LB_ADDSTRING, 0, (LPARAM)tmp);
  402.    }
  403.    SendMessage(box, LB_SETCURSEL, cursor, 0);
  404. }
  405.  
  406. static void FillBpxBox(HWND dlg, unsigned address)
  407. {
  408.    HWND box = GetDlgItem(dlg, IDC_BPX);
  409.    ClearListBox(box);
  410.    unsigned selection = 0;
  411.  
  412.    Z80 &cpu = CpuMgr.Cpu();
  413.    unsigned end; //Alone Coder 0.36.7
  414.    for (unsigned start = 0; start < 0x10000; )
  415.    {
  416.       if (!(cpu.membits[start] & MEMBITS_BPX))
  417.       { start++; continue; }
  418.       for (/*unsigned*/ end = start; end < 0xFFFF && (cpu.membits[end+1] & MEMBITS_BPX); end++);
  419.       char tmp[16];
  420.       if (start == end) sprintf(tmp, "%04X", start);
  421.       else sprintf(tmp, "%04X-%04X", start, end);
  422.       SendMessage(box, LB_ADDSTRING, 0, (LPARAM)tmp);
  423.       if (start <= address && address <= end)
  424.          selection = unsigned(SendMessage(box, LB_GETCOUNT, 0, 0));
  425.       start = end+1;
  426.    }
  427.    if (selection) SendMessage(box, LB_SETCURSEL, selection-1, 0);
  428. }
  429.  
  430. static void FillMemBox(HWND dlg, unsigned address)
  431. {
  432.    HWND box = GetDlgItem(dlg, IDC_MEM);
  433.    ClearListBox(box);
  434.    unsigned selection = 0;
  435.  
  436.    Z80 &cpu = CpuMgr.Cpu();
  437.    unsigned end; //Alone Coder 0.36.7
  438.    for (unsigned start = 0; start < 0x10000; ) {
  439.       const unsigned char mask = MEMBITS_BPR | MEMBITS_BPW;
  440.       if (!(cpu.membits[start] & mask)) { start++; continue; }
  441.       unsigned active = cpu.membits[start];
  442.       for (/*unsigned*/ end = start; end < 0xFFFF && !((active ^ cpu.membits[end+1]) & mask); end++);
  443.       char tmp[16];
  444.       if (start == end) sprintf(tmp, "%04X ", start);
  445.       else sprintf(tmp, "%04X-%04X ", start, end);
  446.       if (active & MEMBITS_BPR) strcat(tmp, "R");
  447.       if (active & MEMBITS_BPW) strcat(tmp, "W");
  448.       SendMessage(box, LB_ADDSTRING, 0, (LPARAM)tmp);
  449.       if (start <= address && address <= end)
  450.          selection = unsigned(SendMessage(box, LB_GETCOUNT, 0, 0));
  451.       start = end+1;
  452.    }
  453.    if (selection) SendMessage(box, LB_SETCURSEL, selection-1, 0);
  454. }
  455.  
  456. static char MoveBpxFromBoxToEdit(HWND dlg, unsigned box, unsigned edit)
  457. {
  458.    HWND hBox = GetDlgItem(dlg, int(box));
  459.    unsigned max = unsigned(SendDlgItemMessage(dlg, box, LB_GETCOUNT, 0, 0)),
  460.             cur = unsigned(SendDlgItemMessage(dlg, box, LB_GETCURSEL, 0, 0));
  461.    if (cur >= max) return 0;
  462.    char tmp[0x200];
  463.    SendMessage(hBox, LB_GETTEXT, cur, (LPARAM)tmp);
  464.    if (box == IDC_MEM && *tmp) {
  465.       char *last = tmp + strlen(tmp);
  466.       unsigned r = BST_UNCHECKED, w = BST_UNCHECKED;
  467.       if(last[-1] == 'W')
  468.       {
  469.           w = BST_CHECKED;
  470.           last--;
  471.       }
  472.       if(last[-1] == 'R')
  473.       {
  474.           r = BST_CHECKED;
  475.           last--;
  476.       }
  477.       if (last[-1] == ' ') last--;
  478.       *last = 0;
  479.       CheckDlgButton(dlg, IDC_MEM_R, r);
  480.       CheckDlgButton(dlg, IDC_MEM_W, w);
  481.    }
  482.    SetDlgItemText(dlg, edit, tmp);
  483.    return 1;
  484. }
  485.  
  486. struct MEM_RANGE { unsigned start, end; };
  487.  
  488. static int GetMemRamge(char *str, MEM_RANGE &range)
  489. {
  490.    while (*str == ' ') str++;
  491.    for (range.start = 0; ishex(*str); str++)
  492.       range.start = range.start*0x10 + hex(*str);
  493.    if (*str == '-') {
  494.       for (range.end = 0, str++; ishex(*str); str++)
  495.          range.end = range.end*0x10 + hex(*str);
  496.    } else range.end = range.start;
  497.    while (*str == ' ') str++;
  498.    if (*str) return 0;
  499.  
  500.    if (range.start > 0xFFFF || range.end > 0xFFFF || range.start > range.end) return 0;
  501.    return 1;
  502. }
  503.  
  504.  
  505. static INT_PTR CALLBACK conddlg(HWND dlg, UINT msg, WPARAM wp, LPARAM lp)
  506. {
  507.     (void)lp;
  508.  
  509.    if (msg == WM_INITDIALOG)
  510.    {
  511.       FillCondBox(dlg, 0);
  512.       FillBpxBox(dlg, 0);
  513.       FillMemBox(dlg, 0);
  514.       SetFocus(GetDlgItem(dlg, IDE_CBP));
  515.  
  516. set_buttons_and_return:
  517.       SetBpxButtons(dlg);
  518.       return 1;
  519.    }
  520.    if (msg == WM_SYSCOMMAND && (wp & 0xFFF0) == SC_CLOSE) EndDialog(dlg, 0);
  521.    if (msg != WM_COMMAND) return 0;
  522.  
  523.    unsigned id = LOWORD(wp), code = HIWORD(wp); unsigned char mask = 0;
  524.    if (id == IDCANCEL || id == IDOK) EndDialog(dlg, 0);
  525.    char tmp[0x200];
  526.  
  527.    if (((id == IDE_BPX || id == IDE_CBP || id == IDE_MEM) && (code == EN_SETFOCUS || code == EN_CHANGE)) ||
  528.        ((id == IDC_BPX || id == IDC_CBP || id == IDC_MEM) && code == LBN_SETFOCUS)) goto set_buttons_and_return;
  529.  
  530.    if (id == IDC_MEM_R || id == IDC_MEM_W) goto set_buttons_and_return;
  531.  
  532.    if (code == LBN_DBLCLK)
  533.    {
  534.       if (id == IDC_CBP && MoveBpxFromBoxToEdit(dlg, IDC_CBP, IDE_CBP)) goto del_cond;
  535.       if (id == IDC_BPX && MoveBpxFromBoxToEdit(dlg, IDC_BPX, IDE_BPX)) goto del_bpx;
  536.       if (id == IDC_MEM && MoveBpxFromBoxToEdit(dlg, IDC_MEM, IDE_MEM)) goto del_mem;
  537.    }
  538.  
  539.    if (id == IDB_CBP_ADD)
  540.    {
  541.       SendDlgItemMessage(dlg, IDE_CBP, WM_GETTEXT, sizeof tmp, (LPARAM)tmp);
  542.       SetFocus(GetDlgItem(dlg, IDE_CBP));
  543.       Z80 &cpu = CpuMgr.Cpu();
  544.       if (!toscript(tmp, cpu.cbp[cpu.cbpn])) {
  545.          MessageBox(dlg, "Error in expression\nPlease do RTFM", nullptr, MB_ICONERROR);
  546.          return 1;
  547.       }
  548.       SendDlgItemMessage(dlg, IDE_CBP, WM_SETTEXT, 0, 0);
  549.       FillCondBox(dlg, cpu.cbpn++);
  550.       cpu.dbgchk = isbrk(cpu);
  551.       goto set_buttons_and_return;
  552.    }
  553.  
  554.    if (id == IDB_BPX_ADD)
  555.    {
  556.       SendDlgItemMessage(dlg, IDE_BPX, WM_GETTEXT, sizeof tmp, (LPARAM)tmp);
  557.       SetFocus(GetDlgItem(dlg, IDE_BPX));
  558.       MEM_RANGE range;
  559.       if (!GetMemRamge(tmp, range))
  560.       {
  561.          MessageBox(dlg, "Invalid breakpoint address / range", nullptr, MB_ICONERROR);
  562.          return 1;
  563.       }
  564.  
  565.       Z80 &cpu = CpuMgr.Cpu();
  566.       for (unsigned i = range.start; i <= range.end; i++)
  567.          cpu.membits[i] |= MEMBITS_BPX;
  568.       SendDlgItemMessage(dlg, IDE_BPX, WM_SETTEXT, 0, 0);
  569.       FillBpxBox(dlg, range.start);
  570.       cpu.dbgchk = isbrk(cpu);
  571.       goto set_buttons_and_return;
  572.    }
  573.  
  574.    if (id == IDB_MEM_ADD)
  575.    {
  576.       SendDlgItemMessage(dlg, IDE_MEM, WM_GETTEXT, sizeof tmp, (LPARAM)tmp);
  577.       SetFocus(GetDlgItem(dlg, IDE_MEM));
  578.       MEM_RANGE range;
  579.       if (!GetMemRamge(tmp, range))
  580.       {
  581.          MessageBox(dlg, "Invalid watch address / range", nullptr, MB_ICONERROR);
  582.          return 1;
  583.       }
  584.       unsigned char mask = 0;
  585.       if (IsDlgButtonChecked(dlg, IDC_MEM_R) == BST_CHECKED) mask |= MEMBITS_BPR;
  586.       if (IsDlgButtonChecked(dlg, IDC_MEM_W) == BST_CHECKED) mask |= MEMBITS_BPW;
  587.  
  588.       Z80 &cpu = CpuMgr.Cpu();
  589.       for (unsigned i = range.start; i <= range.end; i++)
  590.           cpu.membits[i] |= mask;
  591.       SendDlgItemMessage(dlg, IDE_MEM, WM_SETTEXT, 0, 0);
  592.       CheckDlgButton(dlg, IDC_MEM_R, BST_UNCHECKED);
  593.       CheckDlgButton(dlg, IDC_MEM_W, BST_UNCHECKED);
  594.       FillMemBox(dlg, range.start);
  595.       cpu.dbgchk = isbrk(cpu);
  596.       goto set_buttons_and_return;
  597.    }
  598.  
  599.    if (id == IDB_CBP_DEL)
  600.    {
  601. del_cond:
  602.       SetFocus(GetDlgItem(dlg, IDE_CBP));
  603.       unsigned cur = unsigned(SendDlgItemMessage(dlg, IDC_CBP, LB_GETCURSEL, 0, 0));
  604.       Z80 &cpu = CpuMgr.Cpu();
  605.       if (cur >= cpu.cbpn)
  606.           return 0;
  607.       cpu.cbpn--;
  608.       memcpy(cpu.cbp[cur], cpu.cbp[cur+1], sizeof(cpu.cbp[0])*(cpu.cbpn-cur));
  609.  
  610.       if (cur && cur == cpu.cbpn)
  611.           cur--;
  612.       FillCondBox(dlg, cur);
  613.       cpu.dbgchk = isbrk(cpu);
  614.       goto set_buttons_and_return;
  615.    }
  616.  
  617.    if (id == IDB_BPX_DEL)
  618.    {
  619. del_bpx:
  620.       SetFocus(GetDlgItem(dlg, IDE_BPX));
  621.       id = IDC_BPX; mask = u8(~MEMBITS_BPX);
  622. del_range:
  623.       unsigned cur = unsigned(SendDlgItemMessage(dlg, id, LB_GETCURSEL, 0, 0)),
  624.                max = unsigned(SendDlgItemMessage(dlg, id, LB_GETCOUNT, 0, 0));
  625.       if (cur >= max) return 0;
  626.       SendDlgItemMessage(dlg, id, LB_GETTEXT, cur, (LPARAM)tmp);
  627.       unsigned start, end;
  628.       sscanf(tmp, "%X", &start);
  629.       if (tmp[4] == '-') sscanf(tmp+5, "%X", &end); else end = start;
  630.  
  631.       Z80 &cpu = CpuMgr.Cpu();
  632.       for (unsigned i = start; i <= end; i++)
  633.           cpu.membits[i] &= mask;
  634.       if (id == IDC_BPX) FillBpxBox(dlg, 0); else FillMemBox(dlg, 0);
  635.       if (cur && cur == max)
  636.           cur--;
  637.       SendDlgItemMessage(dlg, id, LB_SETCURSEL, cur, 0);
  638.       cpu.dbgchk = isbrk(cpu);
  639.       goto set_buttons_and_return;
  640.    }
  641.  
  642.    if (id == IDB_MEM_DEL)
  643.    {
  644. del_mem:
  645.       SetFocus(GetDlgItem(dlg, IDE_MEM));
  646.       id = IDC_MEM; mask = u8(~(MEMBITS_BPR | MEMBITS_BPW));
  647.       goto del_range;
  648.    }
  649.  
  650.    return 0;
  651. }
  652.  
  653. void mon_bpdialog()
  654. {
  655.    DialogBox(hIn, MAKEINTRESOURCE(IDD_COND), wnd, conddlg);
  656. }
  657.  
  658. static INT_PTR CALLBACK watchdlg(HWND dlg, UINT msg, WPARAM wp, LPARAM lp)
  659. {
  660.     (void)lp;
  661.  
  662.    char tmp[0x200]; unsigned i;
  663.    static const int ids1[] = { IDC_W1_ON, IDC_W2_ON, IDC_W3_ON, IDC_W4_ON };
  664.    static const int ids2[] = { IDE_W1, IDE_W2, IDE_W3, IDE_W4 };
  665.    if (msg == WM_INITDIALOG) {
  666.       for (i = 0; i < 4; i++) {
  667.          CheckDlgButton(dlg, ids1[i], watch_enabled[i] ? BST_CHECKED : BST_UNCHECKED);
  668.          script2text(tmp, watch_script[i]); SetWindowText(GetDlgItem(dlg, ids2[i]), tmp);
  669.       }
  670.       CheckDlgButton(dlg, IDC_TR_RAM, trace_ram ? BST_CHECKED : BST_UNCHECKED);
  671.       CheckDlgButton(dlg, IDC_TR_ROM, trace_ram ? BST_CHECKED : BST_UNCHECKED);
  672. reinit:
  673.       for (i = 0; i < 4; i++)
  674.          EnableWindow(GetDlgItem(dlg, ids2[i]), watch_enabled[i]);
  675.       return 1;
  676.    }
  677.    if (msg == WM_COMMAND && (LOWORD(wp)==ids1[0] || LOWORD(wp)==ids1[1] || LOWORD(wp)==ids1[2] || LOWORD(wp)==ids1[3])) {
  678.       for (i = 0; i < 4; i++)
  679.          watch_enabled[i] = IsDlgButtonChecked(dlg, ids1[i]) == BST_CHECKED;
  680.       goto reinit;
  681.    }
  682.    if ((msg == WM_SYSCOMMAND && (wp & 0xFFF0) == SC_CLOSE) || (msg == WM_COMMAND && LOWORD(wp) == IDCANCEL)) {
  683.       trace_ram = IsDlgButtonChecked(dlg, IDC_TR_RAM) == BST_CHECKED;
  684.       trace_rom = IsDlgButtonChecked(dlg, IDC_TR_ROM) == BST_CHECKED;
  685.       for (i = 0; i < 4; i++)
  686.          if (watch_enabled[i]) {
  687.             SendDlgItemMessage(dlg, ids2[i], WM_GETTEXT, sizeof tmp, (LPARAM)tmp);
  688.             if (!toscript(tmp, watch_script[i])) {
  689.                sprintf(tmp, "Watch %u: error in expression\nPlease do RTFM", i+1);
  690.                MessageBox(dlg, tmp, nullptr, MB_ICONERROR); watch_enabled[i] = 0;
  691.                SetFocus(GetDlgItem(dlg, ids2[i]));
  692.                return 0;
  693.             }
  694.          }
  695.       EndDialog(dlg, 0);
  696.    }
  697.    return 0;
  698. }
  699.  
  700. void mon_watchdialog()
  701. {
  702.    DialogBox(hIn, MAKEINTRESOURCE(IDD_OSW), wnd, watchdlg);
  703. }
  704.  
  705. static void LoadBpx()
  706. {
  707.     char Line[100];
  708.     char BpxFileName[FILENAME_MAX];
  709.  
  710.     addpath(BpxFileName, "bpx.ini");
  711.  
  712.     FILE *BpxFile = fopen(BpxFileName, "rt");
  713.     if(!BpxFile)
  714.         return;
  715.  
  716.     while(!feof(BpxFile))
  717.     {
  718.         fgets(Line, sizeof(Line), BpxFile);
  719.         Line[sizeof(Line)-1] = 0;
  720.         char Type = -1;
  721.         int Start = -1, End = -1, CpuIdx = -1;
  722.         int n = sscanf(Line, "%c%1d=%i-%i", &Type, &CpuIdx, &Start, &End);
  723.         if(n < 3 || CpuIdx < 0 || CpuIdx >= (int)CpuMgr.GetCount() || Start < 0)
  724.             continue;
  725.  
  726.         if(End < 0)
  727.             End = Start;
  728.  
  729.         unsigned mask = 0;
  730.         switch(Type)
  731.         {
  732.         case 'r': mask |= MEMBITS_BPR; break;
  733.         case 'w': mask |= MEMBITS_BPW; break;
  734.         case 'x': mask |= MEMBITS_BPX; break;
  735.         default: continue;
  736.         }
  737.  
  738.         Z80 &cpu = CpuMgr.Cpu(u32(CpuIdx));
  739.         for (unsigned i = unsigned(Start); i <= unsigned(End); i++)
  740.             cpu.membits[i] |= mask;
  741.         cpu.dbgchk = isbrk(cpu);
  742.     }
  743.     fclose(BpxFile);
  744. }
  745.  
  746. static void SaveBpx()
  747. {
  748.     char BpxFileName[FILENAME_MAX];
  749.  
  750.     addpath(BpxFileName, "bpx.ini");
  751.  
  752.     FILE *BpxFile = fopen(BpxFileName, "wt");
  753.     if(!BpxFile)
  754.         return;
  755.  
  756.     for(unsigned CpuIdx = 0; CpuIdx < CpuMgr.GetCount(); CpuIdx++)
  757.     {
  758.         Z80 &cpu = CpuMgr.Cpu(CpuIdx);
  759.  
  760.         for(int i = 0; i < 3; i++)
  761.         {
  762.             for (unsigned Start = 0; Start < 0x10000; )
  763.             {
  764.                static const unsigned Mask[] = { MEMBITS_BPR, MEMBITS_BPW, MEMBITS_BPX };
  765.                if (!(cpu.membits[Start] & Mask[i]))
  766.                {
  767.                    Start++;
  768.                    continue;
  769.                }
  770.                unsigned active = cpu.membits[Start];
  771.                unsigned End;
  772.                for (End = Start; End < 0xFFFF && !((active ^ cpu.membits[End+1]) & Mask[i]); End++);
  773.  
  774.                static const char Type[] = { 'r', 'w', 'x' };
  775.                if(active & Mask[i])
  776.                {
  777.                    if (Start == End)
  778.                        fprintf(BpxFile, "%c%1u=0x%04X\n", Type[i], CpuIdx, Start);
  779.                    else
  780.                        fprintf(BpxFile, "%c%1u=0x%04X-0x%04X\n", Type[i], CpuIdx, Start, End);
  781.                }
  782.  
  783.                Start = End + 1;
  784.             }
  785.         }
  786.     }
  787.  
  788.     fclose(BpxFile);
  789. }
  790.  
  791. void init_bpx()
  792. {
  793.     LoadBpx();
  794. }
  795.  
  796. void done_bpx()
  797. {
  798.     SaveBpx();
  799. }
  800.