Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1088 | alone | 1 | #include "std.h" |
2 | |||
3 | #include "resource.h" |
||
4 | |||
5 | #include "emul.h" |
||
6 | #include "vars.h" |
||
7 | #include "debug.h" |
||
8 | #include "dbgpaint.h" |
||
9 | #include "dbglabls.h" |
||
10 | #include "memory.h" |
||
11 | #include "config.h" |
||
12 | #include "util.h" |
||
13 | |||
14 | MON_LABELS mon_labels; |
||
15 | |||
16 | void MON_LABELS::start_watching_labels() |
||
17 | { |
||
18 | addpath(userfile, "?"); |
||
19 | hNewUserLabels = FindFirstChangeNotification(userfile, 0, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE); |
||
20 | addpath(userfile, "user.l"); |
||
21 | } |
||
22 | |||
23 | void MON_LABELS::stop_watching_labels() |
||
24 | { |
||
25 | if (!hNewUserLabels || hNewUserLabels == INVALID_HANDLE_VALUE) return; |
||
26 | CloseHandle(hNewUserLabels); |
||
27 | hNewUserLabels = INVALID_HANDLE_VALUE; |
||
28 | } |
||
29 | |||
30 | void MON_LABELS::notify_user_labels() |
||
31 | { |
||
32 | if (hNewUserLabels == INVALID_HANDLE_VALUE) return; |
||
33 | // load labels at first check |
||
34 | if (hNewUserLabels == nullptr) { start_watching_labels(); import_file(); return; } |
||
35 | |||
36 | if (WaitForSingleObject(hNewUserLabels, 0) != WAIT_OBJECT_0) return; |
||
37 | |||
38 | import_file(); |
||
39 | FindNextChangeNotification(hNewUserLabels); |
||
40 | } |
||
41 | |||
42 | unsigned MON_LABELS::add_name(char *name) |
||
43 | { |
||
44 | size_t len = strlen(name)+1, new_size = names_size + len; |
||
45 | if (new_size > align_by(names_size, 4096U)) |
||
46 | names = (char*)realloc(names, align_by(new_size, 4096U)); |
||
47 | unsigned result = names_size; |
||
48 | memcpy(names + result, name, len); |
||
49 | names_size = unsigned(new_size); |
||
50 | return result; |
||
51 | } |
||
52 | |||
53 | void MON_LABELS::clear(unsigned char *start, unsigned size) |
||
54 | { |
||
55 | unsigned dst = 0; |
||
56 | for (unsigned src = 0; src < n_pairs; src++) |
||
57 | if ((unsigned)(pairs[src].address - start) > size) |
||
58 | pairs[dst++] = pairs[src]; |
||
59 | n_pairs = dst; |
||
60 | // pack `names' |
||
61 | char *pnames = names; names = nullptr; names_size = 0; |
||
62 | for (unsigned l = 0; l < n_pairs; l++) |
||
63 | pairs[l].name_offs = add_name(pnames + pairs[l].name_offs); |
||
64 | free(pnames); |
||
65 | } |
||
66 | |||
67 | static int __cdecl labels_sort_func(const void *e1, const void *e2) |
||
68 | { |
||
69 | const MON_LABEL *a = (const MON_LABEL*)e1; |
||
70 | const MON_LABEL *b = (const MON_LABEL*)e2; |
||
71 | return int(ptrdiff_t(a->address - b->address)); |
||
72 | } |
||
73 | |||
74 | void MON_LABELS::sort() |
||
75 | { |
||
76 | qsort(pairs, n_pairs, sizeof(MON_LABEL), labels_sort_func); |
||
77 | } |
||
78 | |||
79 | void MON_LABELS::add(unsigned char *address, char *name) |
||
80 | { |
||
81 | if (n_pairs >= align_by(n_pairs, 1024U)) |
||
82 | pairs = (MON_LABEL*)realloc(pairs, sizeof(MON_LABEL) * align_by(n_pairs+1, 1024U)); |
||
83 | pairs[n_pairs].address = address; |
||
84 | pairs[n_pairs].name_offs = add_name(name); |
||
85 | n_pairs++; |
||
86 | } |
||
87 | |||
88 | char *MON_LABELS::find(unsigned char *address) |
||
89 | { |
||
90 | unsigned l = 0, r = n_pairs; |
||
91 | for (;;) { |
||
92 | if (l >= r) return nullptr; |
||
93 | unsigned m = (l+r)/2; |
||
94 | if (pairs[m].address == address) return names + pairs[m].name_offs; |
||
95 | if (pairs[m].address < address) l = m+1; else r = m; |
||
96 | } |
||
97 | } |
||
98 | |||
99 | unsigned MON_LABELS::load(char *filename, unsigned char *base, unsigned size) |
||
100 | { |
||
101 | |||
102 | int virt_addr; //NEDOREPO |
||
103 | |||
104 | |||
105 | FILE *in = fopen(filename, "rt"); |
||
106 | if (!in) |
||
107 | { |
||
108 | errmsg("can't find label file %s", filename); |
||
109 | return 0; |
||
110 | } |
||
111 | |||
112 | clear(base, size); |
||
113 | unsigned l_counter = 0, loaded = 0; char *txt = nullptr; |
||
114 | size_t l; //Alone Coder 0.36.7 |
||
115 | while (!feof(in)) { |
||
116 | char line[64]; |
||
117 | if (!fgets(line, sizeof(line), in)) break; |
||
118 | l_counter++; |
||
119 | for (/*int*/ l = strlen(line); l && line[l-1] <= ' '; l--); |
||
120 | line[l] = 0; |
||
121 | if (!l) continue; |
||
122 | unsigned val = 0, offset = 0; |
||
123 | |||
124 | virt_addr = 0; //NEDOREPO |
||
125 | // if (l >= 6 && line[4] == ' ') //0.39.0 |
||
126 | if (l >= 6 && line[0]!=':' && line[4] == ' ') //NEDOREPO |
||
127 | { // ����� ��� ������ ����� xxxx label |
||
128 | for (l = 0; l < 4; l++) |
||
129 | { |
||
130 | if (!ishex(line[l])) |
||
131 | goto ll_err; |
||
132 | val = (val * 0x10) + hex(line[l]); |
||
133 | } |
||
134 | txt = line+5; |
||
135 | } |
||
136 | |||
137 | else if (l >= 7 && line[0]==':' && line[5] == ' ') //NEDOREPO |
||
138 | { // :xxxx label -- virtual addresses (in Z80 addr space, not coupled to pages) |
||
139 | for (l = 1; l < 5; l++) |
||
140 | { |
||
141 | if (!ishex(line[l])) |
||
142 | goto ll_err; |
||
143 | val = (val * 0x10) + hex(line[l]); |
||
144 | } |
||
145 | txt = line+6; |
||
146 | virt_addr = 1; |
||
147 | } //NEDOREPO |
||
148 | |||
149 | else if (l >= 9 && line[2] == ':' && line[7] == ' ') |
||
150 | { // ����� �������� ����� bb:xxxx label |
||
151 | for (l = 0; l < 2; l++) |
||
152 | { |
||
153 | if (!ishex(line[l])) |
||
154 | goto ll_err; |
||
155 | val = (val * 0x10) + hex(line[l]); |
||
156 | } |
||
157 | for (l = 3; l < 7; l++) |
||
158 | { |
||
159 | if (!ishex(line[l])) |
||
160 | goto ll_err; |
||
161 | offset = (offset * 0x10) + hex(line[l]); |
||
162 | } |
||
163 | val = val*PAGE + (offset & (PAGE-1)); |
||
164 | txt = line+8; |
||
165 | } |
||
166 | else |
||
167 | { |
||
168 | ll_err: |
||
169 | color(CONSCLR_ERROR); |
||
170 | printf("error in %s, line %u\n", filename, l_counter); |
||
171 | continue; |
||
172 | } |
||
173 | |||
174 | // if (val < size) //0.39.0 |
||
175 | // { |
||
176 | // add(base+val, txt); |
||
177 | // loaded++; |
||
178 | // } |
||
179 | if (!virt_addr && (val < size)) //NEDOREPO |
||
180 | { |
||
181 | add(base+val, txt); |
||
182 | loaded++; |
||
183 | } |
||
184 | else if (virt_addr) |
||
185 | { |
||
186 | add(((unsigned char *)NULL)+val, txt); |
||
187 | loaded++; |
||
188 | } //NEDOREPO |
||
189 | } |
||
190 | fclose(in); |
||
191 | sort(); |
||
192 | return loaded; |
||
193 | } |
||
194 | |||
195 | unsigned MON_LABELS::alasm_chain_len(unsigned char *page, unsigned offset, unsigned &end) |
||
196 | { |
||
197 | unsigned count = 0; |
||
198 | for (;;) { |
||
199 | if (offset >= 0x3FFC) return 0; |
||
200 | unsigned s1 = page[offset], sz = s1 & 0x3F; |
||
201 | if (!s1 || offset == 0x3E00) { end = offset+1; return count; } |
||
202 | if (sz < 6) return 0; |
||
203 | unsigned char sym = page[offset+sz-1]; |
||
204 | if (sym >= '0' && sym <= '9') return 0; |
||
205 | for (unsigned ptr = 5; ptr < sz; ptr++) |
||
206 | if (!alasm_valid_char[page[offset+ptr]]) return 0; |
||
207 | if (!(s1 & 0xC0)) count++; |
||
208 | offset += sz; |
||
209 | } |
||
210 | } |
||
211 | |||
212 | void MON_LABELS::find_alasm() |
||
213 | { |
||
214 | static const char label_chars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$_"; |
||
215 | memset(alasm_valid_char, 0, sizeof alasm_valid_char); |
||
216 | for (const char *lbl = label_chars; *lbl; lbl++) alasm_valid_char[unsigned(*lbl)] = 1; |
||
217 | |||
218 | alasm_found_tables = 0; |
||
219 | for (unsigned page = 0; page < conf.ramsize*1024; page += PAGE) { |
||
220 | for (unsigned offset = 0; offset < PAGE; offset++) { |
||
221 | unsigned end, count = alasm_chain_len(RAM_BASE_M + page, offset, end); |
||
222 | if (count < 2) continue; |
||
223 | alasm_count[alasm_found_tables] = count; |
||
224 | alasm_offset[alasm_found_tables] = page + offset; |
||
225 | offset = end; alasm_found_tables++; |
||
226 | if (alasm_found_tables == MAX_ALASM_LTABLES) return; |
||
227 | } |
||
228 | } |
||
229 | } |
||
230 | |||
231 | |||
232 | void MON_LABELS::import_alasm(unsigned offset, char *caption) |
||
233 | { |
||
234 | (void)caption; |
||
235 | |||
236 | clear_ram(); |
||
237 | unsigned char *base = RAM_BASE_M + offset; |
||
238 | for (;;) { // #FE00/FF00/FFFC - end of labels? |
||
239 | unsigned char sz = *base; if (!sz) break; |
||
240 | if (!(sz & 0xC0)) { |
||
241 | char lbl[64]; unsigned ptr = 0; |
||
242 | for(unsigned k = sz; k > 5;) |
||
243 | { |
||
244 | k--; |
||
245 | lbl[ptr++] = char(base[k]); |
||
246 | } |
||
247 | lbl[ptr] = 0; |
||
248 | unsigned val = *(unsigned short*)(base+1); |
||
249 | unsigned char *bs; |
||
250 | switch (val & 0xC000) { |
||
251 | case 0x4000: bs = RAM_BASE_M+5*PAGE; break; |
||
252 | case 0x8000: bs = RAM_BASE_M+2*PAGE; break; |
||
253 | case 0xC000: bs = RAM_BASE_M+0*PAGE; break; |
||
254 | default: bs = nullptr; |
||
255 | } |
||
256 | if (bs) add(bs+(val & 0x3FFF), lbl); |
||
257 | } |
||
258 | base += (sz & 0x3F); |
||
259 | } |
||
260 | sort(); |
||
261 | } |
||
262 | |||
263 | void MON_LABELS::find_xas() |
||
264 | { |
||
265 | char look_page_6 = 0; |
||
266 | const char *err = "XAS labels not found in bank #06"; |
||
267 | if(conf.mem_model == MM_PENTAGON && conf.ramsize > 128) |
||
268 | { |
||
269 | err = "XAS labels not found in banks #06,#46"; |
||
270 | look_page_6 = 1; |
||
271 | } |
||
272 | xaspage = 0; |
||
273 | if (look_page_6 && RAM_BASE_M[PAGE*14+0x3FFF] == 5 && RAM_BASE_M[PAGE*14+0x1FFF] == 5) xaspage = 0x46; |
||
274 | if (!xaspage && RAM_BASE_M[PAGE*6+0x3FFF] == 5 && RAM_BASE_M[PAGE*6+0x1FFF] == 5) xaspage = 0x06; |
||
275 | if (!xaspage) strcpy(xas_errstr, err); |
||
276 | else sprintf(xas_errstr, "XAS labels from bank #%02X", xaspage); |
||
277 | } |
||
278 | |||
279 | void MON_LABELS::import_xas() |
||
280 | { |
||
281 | if (!xaspage) return; |
||
282 | unsigned base = (xaspage == 0x46)? 0x0E*PAGE : (unsigned)xaspage*PAGE; |
||
283 | |||
284 | clear_ram(); unsigned count = 0; |
||
285 | int i; //Alone Coder 0.36.7 |
||
286 | for (int k = 0; k < 2; k++) { |
||
287 | unsigned char *ptr = RAM_BASE_M + base + (k? 0x3FFD : 0x1FFD); |
||
288 | for (;;) { |
||
289 | if (ptr[2] < 5 || (ptr[2] & 0x80)) break; |
||
290 | char lbl[16]; |
||
291 | for(/*int*/ i = 0; i < 7; i++) |
||
292 | { |
||
293 | lbl[i] = char(ptr[i - 7]); |
||
294 | } |
||
295 | for (i = 7; i && lbl[i-1]==' '; i--); |
||
296 | |||
297 | lbl[i] = 0; |
||
298 | unsigned val = *(unsigned short*)ptr; |
||
299 | unsigned char *bs; |
||
300 | switch (val & 0xC000) { |
||
301 | case 0x4000: bs = RAM_BASE_M+5*PAGE; break; |
||
302 | case 0x8000: bs = RAM_BASE_M+2*PAGE; break; |
||
303 | case 0xC000: bs = RAM_BASE_M+0*PAGE; break; |
||
304 | default: bs = nullptr; |
||
305 | } |
||
306 | if(bs) |
||
307 | { |
||
308 | add(bs + (val & 0x3FFF), lbl); |
||
309 | count++; |
||
310 | } |
||
311 | ptr -= 9; if (ptr < RAM_BASE_M+base+9) break; |
||
312 | } |
||
313 | } |
||
314 | sort(); |
||
315 | char ln[64]; sprintf(ln, "imported %u labels", count); |
||
316 | MessageBox(GetForegroundWindow(), ln, xas_errstr, MB_OK | MB_ICONINFORMATION); |
||
317 | } |
||
318 | |||
319 | void MON_LABELS::import_menu() |
||
320 | { |
||
321 | find_xas(); |
||
322 | find_alasm(); |
||
323 | |||
324 | MENUITEM items[MAX_ALASM_LTABLES+4] = { }; |
||
325 | unsigned menuptr = 0; |
||
326 | |||
327 | items[menuptr].text = xas_errstr; |
||
328 | items[menuptr].flags = xaspage? (MENUITEM::FLAGS)0 : MENUITEM::DISABLED; |
||
329 | menuptr++; |
||
330 | |||
331 | char alasm_text[MAX_ALASM_LTABLES][64]; |
||
332 | if (!alasm_found_tables) { |
||
333 | sprintf(alasm_text[0], "No ALASM labels in whole %uK memory", conf.ramsize); |
||
334 | items[menuptr].text = alasm_text[0]; |
||
335 | items[menuptr].flags = MENUITEM::DISABLED; |
||
336 | menuptr++; |
||
337 | } else { |
||
338 | for (unsigned i = 0; i < alasm_found_tables; i++) { |
||
339 | sprintf(alasm_text[i], "%u ALASM labels in page %u, offset #%04X", alasm_count[i], alasm_offset[i]/PAGE, (alasm_offset[i] & 0x3FFF) | 0xC000); |
||
340 | items[menuptr].text = alasm_text[i]; |
||
341 | items[menuptr].flags = (MENUITEM::FLAGS)0; |
||
342 | menuptr++; |
||
343 | } |
||
344 | } |
||
345 | |||
346 | items[menuptr].text = nil; |
||
347 | items[menuptr].flags = MENUITEM::DISABLED; |
||
348 | menuptr++; |
||
349 | |||
350 | items[menuptr].text = "CANCEL"; |
||
351 | items[menuptr].flags = MENUITEM::CENTER; |
||
352 | menuptr++; |
||
353 | |||
354 | MENUDEF menu = { items, menuptr, "import labels" }; |
||
355 | if (!handle_menu(&menu)) return; |
||
356 | if (menu.pos == 0) import_xas(); |
||
357 | menu.pos--; |
||
358 | if ((unsigned)menu.pos < alasm_found_tables) import_alasm(alasm_offset[menu.pos], alasm_text[menu.pos]); |
||
359 | } |
||
360 | |||
361 | void MON_LABELS::import_file() |
||
362 | { |
||
363 | FILE *ff = fopen(userfile, "rb"); if (!ff) return; fclose(ff); |
||
364 | unsigned count = load(userfile, RAM_BASE_M, conf.ramsize * 1024); |
||
365 | if (!count) return; |
||
366 | char tmp[0x200]; |
||
367 | sprintf(tmp, "loaded %u labels from\r\n%s", count, userfile); |
||
368 | puts(tmp); |
||
369 | //MessageBox(GetForegroundWindow(), tmp, "unreal discovered changes in user labels", MB_OK | MB_ICONINFORMATION);//removed by Alone Coder |
||
370 | } |
||
371 | |||
372 | void load_labels(char *filename, unsigned char *base, unsigned size) |
||
373 | { |
||
374 | mon_labels.load(filename, base, size); |
||
375 | } |
||
376 | |||
377 | static char curlabel[64]; |
||
378 | static unsigned lcount; |
||
379 | |||
380 | static void ShowLabels() |
||
381 | { |
||
382 | SetDlgItemText(dlg, IDC_LABEL_TEXT, curlabel); |
||
383 | HWND list = GetDlgItem(dlg, IDC_LABELS); |
||
384 | |||
385 | while (SendMessage(list, LB_GETCOUNT, 0, 0)) |
||
386 | SendMessage(list, LB_DELETESTRING, 0, 0); |
||
387 | |||
388 | size_t ln = strlen(curlabel); lcount = 0; |
||
389 | char *s; //Alone Coder 0.36.7 |
||
390 | for (unsigned p = 0; p < 4; p++) |
||
391 | { |
||
392 | unsigned char *base = am_r(p*PAGE); |
||
393 | for (unsigned i = 0; i < mon_labels.n_pairs; i++) |
||
394 | { |
||
395 | unsigned char *label = mon_labels.pairs[i].address; |
||
396 | if (label < base || label >= base + PAGE) |
||
397 | continue; |
||
398 | char *name = mon_labels.pairs[i].name_offs + mon_labels.names; |
||
399 | if (ln) |
||
400 | { |
||
401 | // unfortunately, strstr() is case sensitive, use loop |
||
402 | for (/*char * */s = name; *s; s++) |
||
403 | if (!strnicmp(s, curlabel, ln)) break; |
||
404 | if (!*s) continue; |
||
405 | } |
||
406 | char zz[0x400]; |
||
407 | sprintf(zz, "%04X %s", unsigned((label - base) + (p * PAGE)), name); |
||
408 | SendMessage(list, LB_ADDSTRING, 0, (LPARAM)zz); lcount++; |
||
409 | } |
||
410 | } |
||
411 | SendMessage(list, LB_SETCURSEL, 0, 0); |
||
412 | SetFocus(list); |
||
413 | } |
||
414 | |||
415 | static INT_PTR CALLBACK LabelsDlg(HWND dlg, UINT msg, WPARAM wp, LPARAM lp) |
||
416 | { |
||
417 | (void)lp; |
||
418 | |||
419 | ::dlg = dlg; |
||
420 | if (msg == WM_INITDIALOG) |
||
421 | { |
||
422 | *curlabel = 0; |
||
423 | ShowLabels(); |
||
424 | return 1; |
||
425 | } |
||
426 | |||
427 | if (msg == WM_SYSCOMMAND && (wp & 0xFFF0) == SC_CLOSE) EndDialog(dlg, 0); |
||
428 | |||
429 | if (msg == WM_VKEYTOITEM) |
||
430 | { |
||
431 | size_t sz = strlen(curlabel); |
||
432 | wp = LOWORD(wp); |
||
433 | if(wp == VK_BACK) |
||
434 | { |
||
435 | if(sz) |
||
436 | { |
||
437 | curlabel[sz - 1] = 0; |
||
438 | ShowLabels(); |
||
439 | } |
||
440 | else { deadkey: Beep(300, 100); } |
||
441 | } |
||
442 | else if((unsigned)(wp - '0') < 10 || (unsigned)(wp - 'A') < 26 || wp == '_') |
||
443 | { |
||
444 | if(sz == sizeof(curlabel) - 1) |
||
445 | { |
||
446 | goto deadkey; |
||
447 | } |
||
448 | curlabel[sz] = char(wp); |
||
449 | curlabel[sz + 1] = 0; |
||
450 | ShowLabels(); |
||
451 | if(!lcount) |
||
452 | { |
||
453 | curlabel[sz] = 0; |
||
454 | ShowLabels(); |
||
455 | goto deadkey; |
||
456 | } |
||
457 | } |
||
458 | else |
||
459 | { |
||
460 | return -1; |
||
461 | } |
||
462 | return -2; |
||
463 | } |
||
464 | |||
465 | if (msg != WM_COMMAND) return 0; |
||
466 | |||
467 | unsigned id = LOWORD(wp), code = HIWORD(wp); |
||
468 | if (id == IDCANCEL || id == IDOK) EndDialog(dlg, 0); |
||
469 | |||
470 | if (id == IDOK || (id == IDC_LABELS && code == LBN_DBLCLK)) |
||
471 | { |
||
472 | HWND list = GetDlgItem(dlg, IDC_LABELS); |
||
473 | unsigned n = unsigned(SendMessage(list, LB_GETCURSEL, 0, 0)); |
||
474 | if (n >= lcount) return 0; |
||
475 | char zz[0x400]; SendMessage(list, LB_GETTEXT, n, (LPARAM)zz); |
||
476 | unsigned address; sscanf(zz, "%X", &address); |
||
477 | |||
478 | void push_pos(); push_pos(); //????? �_� �� ���? |
||
479 | CpuMgr.Cpu().trace_curs = CpuMgr.Cpu().trace_top = address; |
||
480 | activedbg = WNDTRACE; |
||
481 | |||
482 | EndDialog(dlg, 1); |
||
483 | return 1; |
||
484 | } |
||
485 | |||
486 | return 0; |
||
487 | } |
||
488 | |||
489 | void mon_show_labels() |
||
490 | { |
||
491 | DialogBox(hIn, MAKEINTRESOURCE(IDD_LABELS), wnd, LabelsDlg); |
||
492 | } |