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