Subversion Repositories pentevo

Rev

Rev 716 | Blame | Last modification | View Log | Download | RSS feed

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